001/* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020package org.sonar.duplications.internal.pmd; 021 022import com.google.common.collect.Lists; 023import org.sonar.duplications.block.Block; 024import org.sonar.duplications.block.ByteArray; 025 026import java.util.Collections; 027import java.util.List; 028 029/** 030 * Differences with {@link org.sonar.duplications.block.BlockChunker}: 031 * works with {@link TokensLine}, 032 * sets {@link Block#getStartUnit() startUnit} and {@link Block#getEndUnit() endUnit} - indexes of first and last token for this block. 033 */ 034public class PmdBlockChunker { 035 036 private static final long PRIME_BASE = 31; 037 038 private final int blockSize; 039 private final long power; 040 041 public PmdBlockChunker(int blockSize) { 042 this.blockSize = blockSize; 043 044 long pow = 1; 045 for (int i = 0; i < blockSize - 1; i++) { 046 pow = pow * PRIME_BASE; 047 } 048 this.power = pow; 049 } 050 051 public List<Block> chunk(String resourceId, List<TokensLine> fragments) { 052 if (fragments.size() < blockSize) { 053 return Collections.emptyList(); 054 } 055 TokensLine[] fragmentsArr = fragments.toArray(new TokensLine[fragments.size()]); 056 List<Block> blocks = Lists.newArrayListWithCapacity(fragmentsArr.length - blockSize + 1); 057 long hash = 0; 058 int first = 0; 059 int last = 0; 060 for (; last < blockSize - 1; last++) { 061 hash = hash * PRIME_BASE + fragmentsArr[last].getHashCode(); 062 } 063 Block.Builder blockBuilder = Block.builder().setResourceId(resourceId); 064 for (; last < fragmentsArr.length; last++, first++) { 065 TokensLine firstFragment = fragmentsArr[first]; 066 TokensLine lastFragment = fragmentsArr[last]; 067 // add last statement to hash 068 hash = hash * PRIME_BASE + lastFragment.getHashCode(); 069 // create block 070 Block block = blockBuilder 071 .setBlockHash(new ByteArray(hash)) 072 .setIndexInFile(first) 073 .setLines(firstFragment.getStartLine(), lastFragment.getEndLine()) 074 .setUnit(firstFragment.getStartUnit(), lastFragment.getEndUnit()) 075 .build(); 076 blocks.add(block); 077 // remove first statement from hash 078 hash -= power * firstFragment.getHashCode(); 079 } 080 return blocks; 081 } 082 083}