diff options
6 files changed, 143 insertions, 48 deletions
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java index 600c3d3de35..bfd83db3491 100644 --- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java +++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/index/DbDuplicationsIndex.java @@ -73,7 +73,12 @@ public class DbDuplicationsIndex { int endLine = unit.getEndLine(); // TODO Godin: in fact we could work directly with id instead of key - this will allow to decrease memory consumption - Block block = new Block(resourceKey, new ByteArray(hash), indexInFile, startLine, endLine); + Block block = Block.builder() + .setResourceId(resourceKey) + .setBlockHash(new ByteArray(hash)) + .setIndexInFile(indexInFile) + .setLines(startLine, endLine) + .build(); // Group blocks by hash Collection<Block> sameHash = cache.get(block.getBlockHash()); diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/block/Block.java b/sonar-duplications/src/main/java/org/sonar/duplications/block/Block.java index 1ccc79194ef..822454db205 100644 --- a/sonar-duplications/src/main/java/org/sonar/duplications/block/Block.java +++ b/sonar-duplications/src/main/java/org/sonar/duplications/block/Block.java @@ -31,14 +31,92 @@ public final class Block implements CodeFragment { private final String resourceId; private final ByteArray blockHash; private final int indexInFile; + private final int startLine; private final int endLine; + private int startUnit; + private int endUnit; + /** * Cache for hash code. */ private int hash; + /** + * @since 2.14 + */ + public static Builder builder() { + return new Builder(); + } + + /** + * <p>Instances can be reused - it is safe to call {@link #build} + * multiple times to build multiple blocks in series.</p> + * + * @since 2.14 + */ + public static final class Builder { + + private String resourceId; + private ByteArray blockHash; + private int indexInFile; + + private int startLine; + private int endLine; + + private int startUnit; + private int endUnit; + + public Builder setResourceId(String resourceId) { + this.resourceId = resourceId; + return this; + } + + public Builder setBlockHash(ByteArray blockHash) { + this.blockHash = blockHash; + return this; + } + + public Builder setIndexInFile(int index) { + this.indexInFile = index; + return this; + } + + public Builder setLines(int start, int end) { + this.startLine = start; + this.endLine = end; + return this; + } + + @Beta + public Builder setUnit(int start, int end) { + this.startUnit = start; + this.endUnit = end; + return this; + } + + public Block build() { + return new Block(this); + } + } + + private Block(Builder builder) { + this.resourceId = builder.resourceId; + this.blockHash = builder.blockHash; + this.indexInFile = builder.indexInFile; + + this.startLine = builder.startLine; + this.endLine = builder.endLine; + + this.startUnit = builder.startUnit; + this.endUnit = builder.endUnit; + } + + /** + * @deprecated since 2.14 use {@link #builder()} + */ + @Deprecated public Block(String resourceId, ByteArray blockHash, int indexInFile, int startLine, int endLine) { this.resourceId = resourceId; this.blockHash = blockHash; @@ -47,10 +125,6 @@ public final class Block implements CodeFragment { this.endLine = endLine; } - public Block(int indexInFile, int firstLineNumber, int lastLineNumber, String resourceId, String hash) { - this(resourceId, new ByteArray(hash), indexInFile, firstLineNumber, lastLineNumber); - } - public String getHashHex() { return getBlockHash().toString(); } @@ -67,8 +141,13 @@ public final class Block implements CodeFragment { return indexInFile; } - private int startUnit; - private int endUnit; + public int getStartLine() { + return startLine; + } + + public int getEndLine() { + return endLine; + } /** * @since 2.14 @@ -86,36 +165,6 @@ public final class Block implements CodeFragment { return endUnit; } - /** - * TODO get rid of this method, otherwise class is not immutable - * - * @see #getStartUnit() - * @since 2.14 - */ - @Beta - public void setStartUnit(int startUnit) { - this.startUnit = startUnit; - } - - /** - * TODO get rid of this method, otherwise class is not immutable - * - * @see #getEndUnit() - * @since 2.14 - */ - @Beta - public void setEndUnit(int endUnit) { - this.endUnit = endUnit; - } - - public int getStartLine() { - return startLine; - } - - public int getEndLine() { - return endLine; - } - @Override public boolean equals(Object obj) { if (!(obj instanceof Block)) { diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/block/BlockChunker.java b/sonar-duplications/src/main/java/org/sonar/duplications/block/BlockChunker.java index 3abc0742493..0851eb21f04 100644 --- a/sonar-duplications/src/main/java/org/sonar/duplications/block/BlockChunker.java +++ b/sonar-duplications/src/main/java/org/sonar/duplications/block/BlockChunker.java @@ -66,13 +66,18 @@ public class BlockChunker { for (; last < blockSize - 1; last++) { hash = hash * PRIME_BASE + statementsArr[last].getValue().hashCode(); } + Block.Builder blockBuilder = Block.builder().setResourceId(resourceId); for (; last < statementsArr.length; last++, first++) { Statement firstStatement = statementsArr[first]; Statement lastStatement = statementsArr[last]; // add last statement to hash hash = hash * PRIME_BASE + lastStatement.getValue().hashCode(); // create block - blocks.add(new Block(resourceId, new ByteArray(hash), first, firstStatement.getStartLine(), lastStatement.getEndLine())); + Block block = blockBuilder.setBlockHash(new ByteArray(hash)) + .setIndexInFile(first) + .setLines(firstStatement.getStartLine(), lastStatement.getEndLine()) + .build(); + blocks.add(block); // remove first statement from hash hash -= power * firstStatement.getValue().hashCode(); } diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/index/PackedMemoryCloneIndex.java b/sonar-duplications/src/main/java/org/sonar/duplications/index/PackedMemoryCloneIndex.java index a2d66e2f0b3..bced97e3433 100644 --- a/sonar-duplications/src/main/java/org/sonar/duplications/index/PackedMemoryCloneIndex.java +++ b/sonar-duplications/src/main/java/org/sonar/duplications/index/PackedMemoryCloneIndex.java @@ -66,6 +66,8 @@ public class PackedMemoryCloneIndex extends AbstractCloneIndex { private int[] resourceIdsIndex; + private final Block.Builder blockBuilder = Block.builder(); + public PackedMemoryCloneIndex() { this(8, DEFAULT_INITIAL_CAPACITY); } @@ -114,9 +116,13 @@ public class PackedMemoryCloneIndex extends AbstractCloneIndex { int startUnit = blockData[offset++]; int endUnit = blockData[offset]; - Block block = new Block(resourceId, new ByteArray(hash), indexInFile, firstLineNumber, lastLineNumber); - block.setStartUnit(startUnit); - block.setEndUnit(endUnit); + Block block = blockBuilder + .setResourceId(resourceId) + .setBlockHash(new ByteArray(hash)) + .setIndexInFile(indexInFile) + .setLines(firstLineNumber, lastLineNumber) + .setUnit(startUnit, endUnit) + .build(); result.add(block); index++; @@ -154,9 +160,13 @@ public class PackedMemoryCloneIndex extends AbstractCloneIndex { int startUnit = blockData[offset++]; int endUnit = blockData[offset]; - Block block = new Block(resourceId, sequenceHash, indexInFile, firstLineNumber, lastLineNumber); - block.setStartUnit(startUnit); - block.setEndUnit(endUnit); + Block block = blockBuilder + .setResourceId(resourceId) + .setBlockHash(sequenceHash) + .setIndexInFile(indexInFile) + .setLines(firstLineNumber, lastLineNumber) + .setUnit(startUnit, endUnit) + .build(); result.add(block); index++; } diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java b/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java index 81ef62d7b52..7fb3652adc0 100644 --- a/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java +++ b/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java @@ -29,7 +29,7 @@ import java.util.List; /** * Differences with {@link org.sonar.duplications.block.BlockChunker}: * works with {@link TokensLine}, - * sets {@link Block#setStartUnit(int)} and {@link Block#setEndUnit(int)} - indexes of first and last token for this block. + * sets {@link Block#getStartUnit() startUnit} and {@link Block#getEndUnit() endUnit} - indexes of first and last token for this block. */ public class PmdBlockChunker { @@ -60,15 +60,19 @@ public class PmdBlockChunker { for (; last < blockSize - 1; last++) { hash = hash * PRIME_BASE + fragmentsArr[last].getHashCode(); } + Block.Builder blockBuilder = Block.builder().setResourceId(resourceId); for (; last < fragmentsArr.length; last++, first++) { TokensLine firstFragment = fragmentsArr[first]; TokensLine lastFragment = fragmentsArr[last]; // add last statement to hash hash = hash * PRIME_BASE + lastFragment.getHashCode(); // create block - Block block = new Block(resourceId, new ByteArray(hash), first, firstFragment.getStartLine(), lastFragment.getEndLine()); - block.setStartUnit(firstFragment.getStartUnit()); - block.setEndUnit(lastFragment.getEndUnit()); + Block block = blockBuilder + .setBlockHash(new ByteArray(hash)) + .setIndexInFile(first) + .setLines(firstFragment.getStartLine(), lastFragment.getEndLine()) + .setUnit(firstFragment.getStartUnit(), lastFragment.getEndUnit()) + .build(); blocks.add(block); // remove first statement from hash hash -= power * firstFragment.getHashCode(); diff --git a/sonar-duplications/src/test/java/org/sonar/duplications/block/BlockTest.java b/sonar-duplications/src/test/java/org/sonar/duplications/block/BlockTest.java index bcb8bcfe389..fd86e55c699 100644 --- a/sonar-duplications/src/test/java/org/sonar/duplications/block/BlockTest.java +++ b/sonar-duplications/src/test/java/org/sonar/duplications/block/BlockTest.java @@ -27,6 +27,28 @@ import static org.junit.Assert.*; public class BlockTest { @Test + public void testBuilder() { + ByteArray hash = new ByteArray(1); + Block block = Block.builder() + .setResourceId("resource") + .setBlockHash(hash) + .setIndexInFile(1) + .setLines(2, 3) + .setUnit(4, 5) + .build(); + + assertThat(block.getResourceId(), is("resource")); + assertThat(block.getBlockHash(), sameInstance(hash)); + assertThat(block.getIndexInFile(), is(1)); + + assertThat(block.getStartLine(), is(2)); + assertThat(block.getEndLine(), is(3)); + + assertThat(block.getStartUnit(), is(4)); + assertThat(block.getEndUnit(), is(5)); + } + + @Test public void fieldsTest() { String fileName = "someFile"; int statementIndex = 4; |