aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-duplications/src
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2015-12-21 13:54:14 +0100
committerDuarte Meneses <duarte.meneses@sonarsource.com>2015-12-21 14:37:03 +0100
commitd1e303f8412f61f426a6c746cc2ac10b584940bd (patch)
treeb68693cc8caced2aeee5b06a3590b3e1392e8011 /sonar-duplications/src
parent6fe8b0cd64c4b4e2386d994016b465b0386ed09c (diff)
downloadsonarqube-d1e303f8412f61f426a6c746cc2ac10b584940bd.tar.gz
sonarqube-d1e303f8412f61f426a6c746cc2ac10b584940bd.zip
SONAR-2867 Standard copy-paste detection should happen within a project, not only within a module
Diffstat (limited to 'sonar-duplications/src')
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/index/CloneIndex.java7
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/index/MemoryCloneIndex.java7
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/index/PackedMemoryCloneIndex.java133
-rw-r--r--sonar-duplications/src/test/java/org/sonar/duplications/index/PackedMemoryCloneIndexTest.java32
4 files changed, 145 insertions, 34 deletions
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/index/CloneIndex.java b/sonar-duplications/src/main/java/org/sonar/duplications/index/CloneIndex.java
index 357fca44aa8..7bcf94b914a 100644
--- a/sonar-duplications/src/main/java/org/sonar/duplications/index/CloneIndex.java
+++ b/sonar-duplications/src/main/java/org/sonar/duplications/index/CloneIndex.java
@@ -20,9 +20,11 @@
package org.sonar.duplications.index;
import java.util.Collection;
+import java.util.Iterator;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.ByteArray;
+import org.sonar.duplications.index.PackedMemoryCloneIndex.ResourceBlocks;
public interface CloneIndex {
@@ -45,4 +47,9 @@ public interface CloneIndex {
*/
void insert(Block block);
+ /**
+ * Iterators through the resources, providing the list of blocks for each resource.
+ */
+ Iterator<ResourceBlocks> iterator();
+
}
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/index/MemoryCloneIndex.java b/sonar-duplications/src/main/java/org/sonar/duplications/index/MemoryCloneIndex.java
index 393a8e7d1dd..1b454bf6eff 100644
--- a/sonar-duplications/src/main/java/org/sonar/duplications/index/MemoryCloneIndex.java
+++ b/sonar-duplications/src/main/java/org/sonar/duplications/index/MemoryCloneIndex.java
@@ -23,8 +23,10 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.ByteArray;
+import org.sonar.duplications.index.PackedMemoryCloneIndex.ResourceBlocks;
import java.util.Collection;
+import java.util.Iterator;
public class MemoryCloneIndex implements CloneIndex {
@@ -47,4 +49,9 @@ public class MemoryCloneIndex implements CloneIndex {
byHash.put(block.getBlockHash(), block);
}
+ @Override
+ public Iterator<ResourceBlocks> iterator() {
+ throw new UnsupportedOperationException();
+ }
+
}
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 f0257cef0e2..5681acf1f55 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
@@ -21,11 +21,16 @@ package org.sonar.duplications.index;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
+import java.util.NoSuchElementException;
+
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.ByteArray;
import org.sonar.duplications.utils.FastStringComparator;
+import javax.annotation.Nullable;
+
/**
* Provides an index optimized by memory.
* <p>
@@ -104,31 +109,105 @@ public class PackedMemoryCloneIndex extends AbstractCloneIndex {
List<Block> result = new ArrayList<>();
int realIndex = resourceIdsIndex[index];
while (index < size && FastStringComparator.INSTANCE.compare(resourceIds[realIndex], resourceId) == 0) {
- // extract block (note that there is no need to extract resourceId)
- int offset = realIndex * blockInts;
+ result.add(getBlock(realIndex, resourceId));
+
+ index++;
+ realIndex = resourceIdsIndex[index];
+ }
+ return result;
+ }
+
+ private Block createBlock(int index, String resourceId, @Nullable ByteArray byteHash) {
+ int offset = index * blockInts;
+ ByteArray blockHash;
+
+ if (byteHash == null) {
int[] hash = new int[hashInts];
for (int j = 0; j < hashInts; j++) {
hash[j] = blockData[offset++];
}
- int indexInFile = blockData[offset++];
- int firstLineNumber = blockData[offset++];
- int lastLineNumber = blockData[offset++];
- int startUnit = blockData[offset++];
- int endUnit = blockData[offset];
-
- Block block = blockBuilder
- .setResourceId(resourceId)
- .setBlockHash(new ByteArray(hash))
- .setIndexInFile(indexInFile)
- .setLines(firstLineNumber, lastLineNumber)
- .setUnit(startUnit, endUnit)
- .build();
- result.add(block);
+ blockHash = new ByteArray(hash);
+ } else {
+ blockHash = byteHash;
+ offset += hashInts;
+ }
- index++;
- realIndex = resourceIdsIndex[index];
+ int indexInFile = blockData[offset++];
+ int firstLineNumber = blockData[offset++];
+ int lastLineNumber = blockData[offset++];
+ int startUnit = blockData[offset++];
+ int endUnit = blockData[offset];
+
+ return blockBuilder
+ .setResourceId(resourceId)
+ .setBlockHash(blockHash)
+ .setIndexInFile(indexInFile)
+ .setLines(firstLineNumber, lastLineNumber)
+ .setUnit(startUnit, endUnit)
+ .build();
+ }
+
+ private Block getBlock(int index, String resourceId) {
+ return createBlock(index, resourceId, null);
+ }
+
+ private class ResourceIterator implements Iterator<ResourceBlocks> {
+ private int index = 0;
+
+ @Override
+ public boolean hasNext() {
+ return index < size;
}
- return result;
+
+ @Override
+ public ResourceBlocks next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ String resourceId = resourceIds[resourceIdsIndex[index]];
+ List<Block> blocks = new ArrayList<>();
+
+ // while we are at the same resource, keep going
+ do {
+ blocks.add(getBlock(resourceIdsIndex[index], resourceId));
+ index++;
+ } while (hasNext() && FastStringComparator.INSTANCE.compare(resourceIds[resourceIdsIndex[index]], resourceId) == 0);
+
+ return new ResourceBlocks(resourceId, blocks);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class ResourceBlocks {
+ private Collection<Block> blocks;
+ private String resourceId;
+
+ public ResourceBlocks(String resourceId, Collection<Block> blocks) {
+ this.resourceId = resourceId;
+ this.blocks = blocks;
+ }
+
+ public Collection<Block> blocks() {
+ return blocks;
+ }
+
+ public String resourceId() {
+ return resourceId;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<ResourceBlocks> iterator() {
+ ensureSorted();
+ return new ResourceIterator();
}
/**
@@ -154,21 +233,7 @@ public class PackedMemoryCloneIndex extends AbstractCloneIndex {
while (index < size && !isLessByHash(size, index)) {
// extract block (note that there is no need to extract hash)
String resourceId = resourceIds[index];
- offset = index * blockInts + hashInts;
- int indexInFile = blockData[offset++];
- int firstLineNumber = blockData[offset++];
- int lastLineNumber = blockData[offset++];
- int startUnit = blockData[offset++];
- int endUnit = blockData[offset];
-
- Block block = blockBuilder
- .setResourceId(resourceId)
- .setBlockHash(sequenceHash)
- .setIndexInFile(indexInFile)
- .setLines(firstLineNumber, lastLineNumber)
- .setUnit(startUnit, endUnit)
- .build();
- result.add(block);
+ result.add(createBlock(index, resourceId, sequenceHash));
index++;
}
return result;
diff --git a/sonar-duplications/src/test/java/org/sonar/duplications/index/PackedMemoryCloneIndexTest.java b/sonar-duplications/src/test/java/org/sonar/duplications/index/PackedMemoryCloneIndexTest.java
index cb91fe37b6f..0812e1eb767 100644
--- a/sonar-duplications/src/test/java/org/sonar/duplications/index/PackedMemoryCloneIndexTest.java
+++ b/sonar-duplications/src/test/java/org/sonar/duplications/index/PackedMemoryCloneIndexTest.java
@@ -23,9 +23,13 @@ import org.junit.Before;
import org.junit.Test;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.ByteArray;
+import org.sonar.duplications.index.PackedMemoryCloneIndex.ResourceBlocks;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
@@ -76,6 +80,34 @@ public class PackedMemoryCloneIndexTest {
assertThat(block.getBlockHash(), sameInstance(requestedHash));
}
}
+
+ @Test
+ public void iterate() {
+ index.insert(newBlock("a", 1));
+ index.insert(newBlock("c", 1));
+ index.insert(newBlock("b", 1));
+ index.insert(newBlock("c", 2));
+ index.insert(newBlock("a", 2));
+
+ Iterator<ResourceBlocks> it = index.iterator();
+
+ ArrayList<ResourceBlocks> resourcesBlocks = new ArrayList<>();
+
+ while(it.hasNext()) {
+ resourcesBlocks.add(it.next());
+ }
+
+ assertThat(resourcesBlocks).hasSize(3);
+
+ assertThat(resourcesBlocks.get(0).resourceId()).isEqualTo("a");
+ assertThat(resourcesBlocks.get(1).resourceId()).isEqualTo("b");
+ assertThat(resourcesBlocks.get(2).resourceId()).isEqualTo("c");
+
+ assertThat(resourcesBlocks.get(0).blocks()).hasSize(2);
+ assertThat(resourcesBlocks.get(1).blocks()).hasSize(1);
+ assertThat(resourcesBlocks.get(2).blocks()).hasSize(2);
+
+ }
/**
* Given: index with initial capacity 1.