summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/JavaCpdEngine.java4
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/JavaCpdEngineTest.java22
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java2
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/XooTokenizerSensor.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java1
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java11
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroup.java76
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java3
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java21
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java21
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java4
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java6
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationBuilder.java25
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationGroup.java148
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationTokenBuilder.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/TokenBuilder.java)15
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/internal/DefaultDuplicationBuilder.java (renamed from sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationBuilder.java)23
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/internal/package-info.java21
22 files changed, 307 insertions, 133 deletions
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/JavaCpdEngine.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/JavaCpdEngine.java
index c74f41bccc9..43585d4db4f 100644
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/JavaCpdEngine.java
+++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/JavaCpdEngine.java
@@ -32,13 +32,13 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
+import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder;
import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.FileLinesContext;
import org.sonar.api.measures.FileLinesContextFactory;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.SonarException;
-import org.sonar.batch.duplication.DefaultDuplicationBuilder;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.BlockChunker;
import org.sonar.duplications.detector.suffixtree.SuffixTreeCloneDetectionAlgorithm;
@@ -243,7 +243,7 @@ public class JavaCpdEngine extends CpdEngine {
}
}
}
- builder.done();
+ context.saveDuplications(inputFile, builder.build());
}
}
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/JavaCpdEngineTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/JavaCpdEngineTest.java
index 5a0e6f65815..dcada895aab 100644
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/JavaCpdEngineTest.java
+++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/JavaCpdEngineTest.java
@@ -28,12 +28,12 @@ import org.mockito.Mockito;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
+import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.FileLinesContext;
import org.sonar.api.measures.FileLinesContextFactory;
-import org.sonar.batch.duplication.DefaultDuplicationBuilder;
-import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.duplications.index.CloneGroup;
import org.sonar.duplications.index.ClonePart;
@@ -64,10 +64,10 @@ public class JavaCpdEngineTest {
public void before() throws IOException {
when(context.measureBuilder()).thenReturn(new DefaultMeasureBuilder());
inputFile = new DeprecatedDefaultInputFile("src/main/java/Foo.java");
- DuplicationCache duplicationCache = mock(DuplicationCache.class);
- duplicationBuilder = spy(new DefaultDuplicationBuilder(inputFile, duplicationCache));
+ duplicationBuilder = spy(new DefaultDuplicationBuilder(inputFile));
when(context.duplicationBuilder(any(InputFile.class))).thenReturn(duplicationBuilder);
inputFile.setFile(temp.newFile("Foo.java"));
+ inputFile.setKey("key1");
contextFactory = mock(FileLinesContextFactory.class);
linesContext = mock(FileLinesContext.class);
when(contextFactory.createFor(inputFile)).thenReturn(linesContext);
@@ -95,7 +95,7 @@ public class JavaCpdEngineTest {
InOrder inOrder = Mockito.inOrder(duplicationBuilder);
inOrder.verify(duplicationBuilder).originBlock(5, 204);
inOrder.verify(duplicationBuilder).isDuplicatedBy("key2", 15, 214);
- inOrder.verify(duplicationBuilder).done();
+ inOrder.verify(duplicationBuilder).build();
verify(linesContext).setIntValue(CoreMetrics.DUPLICATION_LINES_DATA_KEY, 1, 0);
verify(linesContext).setIntValue(CoreMetrics.DUPLICATION_LINES_DATA_KEY, 4, 0);
@@ -116,7 +116,7 @@ public class JavaCpdEngineTest {
InOrder inOrder = Mockito.inOrder(duplicationBuilder);
inOrder.verify(duplicationBuilder).originBlock(5, 204);
inOrder.verify(duplicationBuilder).isDuplicatedBy("key1", 215, 414);
- inOrder.verify(duplicationBuilder).done();
+ inOrder.verify(duplicationBuilder).build();
}
@Test
@@ -132,7 +132,13 @@ public class JavaCpdEngineTest {
inOrder.verify(duplicationBuilder).originBlock(5, 204);
inOrder.verify(duplicationBuilder).isDuplicatedBy("key2", 15, 214);
inOrder.verify(duplicationBuilder).isDuplicatedBy("key3", 25, 224);
- inOrder.verify(duplicationBuilder).done();
+ inOrder.verify(duplicationBuilder).build();
+
+ verify(context).saveDuplications(inputFile, Arrays.asList(
+ new DuplicationGroup(new DuplicationGroup.Block("key1", 5, 200))
+ .addDuplicate(new DuplicationGroup.Block("key2", 15, 200))
+ .addDuplicate(new DuplicationGroup.Block("key3", 25, 200))
+ ));
}
@Test
@@ -151,7 +157,7 @@ public class JavaCpdEngineTest {
inOrder.verify(duplicationBuilder).isDuplicatedBy("key2", 15, 214);
inOrder.verify(duplicationBuilder).originBlock(15, 214);
inOrder.verify(duplicationBuilder).isDuplicatedBy("key3", 15, 214);
- inOrder.verify(duplicationBuilder).done();
+ inOrder.verify(duplicationBuilder).build();
}
private CloneGroup newCloneGroup(ClonePart... parts) {
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java
index 71b5288c6b3..1344179bfb2 100644
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java
+++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java
@@ -28,7 +28,7 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.batch.duplication.DuplicationGroup;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.batch.mediumtest.BatchMediumTester;
import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult;
import org.sonar.plugins.cpd.CpdPlugin;
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/XooTokenizerSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/XooTokenizerSensor.java
index 1ee33e560ef..1098625783f 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/XooTokenizerSensor.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/XooTokenizerSensor.java
@@ -28,7 +28,7 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.batch.sensor.duplication.TokenBuilder;
+import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
import org.sonar.xoo.Xoo;
import java.io.File;
@@ -41,7 +41,7 @@ import java.util.List;
public class XooTokenizerSensor implements Sensor {
private void computeTokens(InputFile inputFile, SensorContext context) {
- TokenBuilder tokenBuilder = context.tokenBuilder(inputFile);
+ DuplicationTokenBuilder tokenBuilder = context.duplicationTokenBuilder(inputFile);
File ioFile = inputFile.file();
int lineId = 0;
try {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java
index 6c7836d9e39..b4af6917440 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java
@@ -25,7 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.sensor.duplication.TokenBuilder;
+import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.FileBlocks;
import org.sonar.duplications.internal.pmd.PmdBlockChunker;
@@ -35,7 +35,7 @@ import org.sonar.duplications.internal.pmd.TokensLine;
import java.util.ArrayList;
import java.util.List;
-public class DefaultTokenBuilder implements TokenBuilder {
+public class DefaultTokenBuilder implements DuplicationTokenBuilder {
private static final Logger LOG = LoggerFactory.getLogger(DefaultTokenBuilder.class);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java
index ab1dad47009..26c857a5d23 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java
@@ -22,6 +22,7 @@ package org.sonar.batch.duplication;
import com.persistit.Value;
import com.persistit.encoding.CoderContext;
import com.persistit.encoding.ValueCoder;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
class DuplicationBlockValueCoder implements ValueCoder {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java
index e0265215efc..573ac7a7a13 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java
@@ -20,20 +20,21 @@
package org.sonar.batch.duplication;
import org.sonar.api.BatchComponent;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.batch.index.Cache;
import org.sonar.batch.index.Cache.Entry;
import org.sonar.batch.index.Caches;
import javax.annotation.CheckForNull;
-import java.util.ArrayList;
+import java.util.List;
/**
* Cache of duplication blocks. This cache is shared amongst all project modules.
*/
public class DuplicationCache implements BatchComponent {
- private final Cache<ArrayList<DuplicationGroup>> cache;
+ private final Cache<List<DuplicationGroup>> cache;
public DuplicationCache(Caches caches) {
caches.registerValueCoder(DuplicationGroup.class, new DuplicationGroupValueCoder());
@@ -41,16 +42,16 @@ public class DuplicationCache implements BatchComponent {
cache = caches.createCache("duplications");
}
- public Iterable<Entry<ArrayList<DuplicationGroup>>> entries() {
+ public Iterable<Entry<List<DuplicationGroup>>> entries() {
return cache.entries();
}
@CheckForNull
- public ArrayList<DuplicationGroup> byComponent(String effectiveKey) {
+ public List<DuplicationGroup> byComponent(String effectiveKey) {
return cache.get(effectiveKey);
}
- public DuplicationCache put(String effectiveKey, ArrayList<DuplicationGroup> blocks) {
+ public DuplicationCache put(String effectiveKey, List<DuplicationGroup> blocks) {
cache.put(effectiveKey, blocks);
return this;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroup.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroup.java
deleted file mode 100644
index dc9a7aa2602..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroup.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.batch.duplication;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class DuplicationGroup {
-
- public static class Block {
- private final String resourceKey;
- private final int startLine;
- private final int length;
-
- public Block(String resourceKey, int startLine, int length) {
- this.resourceKey = resourceKey;
- this.startLine = startLine;
- this.length = length;
- }
-
- public String resourceKey() {
- return resourceKey;
- }
-
- public int startLine() {
- return startLine;
- }
-
- public int length() {
- return length;
- }
- }
-
- private final Block originBlock;
-
- private List<Block> duplicates = new ArrayList<DuplicationGroup.Block>();
-
- public DuplicationGroup(Block originBlock) {
- this.originBlock = originBlock;
- }
-
- public void setDuplicates(List<Block> duplicates) {
- this.duplicates = duplicates;
- }
-
- public DuplicationGroup addDuplicate(Block anotherBlock) {
- this.duplicates.add(anotherBlock);
- return this;
- }
-
- public Block originBlock() {
- return originBlock;
- }
-
- public List<Block> duplicates() {
- return duplicates;
- }
-
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java
index b813d728354..5b6ed6d8401 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java
@@ -22,7 +22,8 @@ package org.sonar.batch.duplication;
import com.persistit.Value;
import com.persistit.encoding.CoderContext;
import com.persistit.encoding.ValueCoder;
-import org.sonar.batch.duplication.DuplicationGroup.Block;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup.Block;
import java.util.ArrayList;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
index 9ac3085880c..9461d46dfd7 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/index/DuplicationPersister.java
@@ -20,6 +20,7 @@
package org.sonar.batch.index;
import org.apache.commons.lang.StringEscapeUtils;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.api.database.model.MeasureMapper;
import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.database.model.Snapshot;
@@ -29,12 +30,11 @@ import org.sonar.api.measures.PersistenceMode;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.RuleFinder;
import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.duplication.DuplicationGroup;
import org.sonar.batch.index.Cache.Entry;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
-import java.util.ArrayList;
+import java.util.List;
public final class DuplicationPersister implements ScanPersister {
private final MyBatis mybatis;
@@ -62,7 +62,7 @@ public final class DuplicationPersister implements ScanPersister {
try {
MeasureMapper mapper = session.getMapper(MeasureMapper.class);
org.sonar.api.measures.Metric duplicationMetricWithId = metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY);
- for (Entry<ArrayList<DuplicationGroup>> entry : duplicationCache.entries()) {
+ for (Entry<List<DuplicationGroup>> entry : duplicationCache.entries()) {
String effectiveKey = entry.key()[0].toString();
Measure measure = new Measure(duplicationMetricWithId, toXml(entry.value())).setPersistenceMode(PersistenceMode.DATABASE);
Resource resource = resourceCache.get(effectiveKey);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
index 58cc4f461af..a42ca1ae1b0 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
@@ -29,6 +29,7 @@ import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.measure.Measure;
@@ -42,7 +43,6 @@ import org.sonar.batch.bootstrap.PluginsReferential;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.duplication.DuplicationGroup;
import org.sonar.batch.highlighting.SyntaxHighlightingData;
import org.sonar.batch.highlighting.SyntaxHighlightingRule;
import org.sonar.batch.index.Cache.Entry;
@@ -264,7 +264,7 @@ public class BatchMediumTester {
}
DuplicationCache duplicationCache = container.getComponentByType(DuplicationCache.class);
- for (Entry<ArrayList<DuplicationGroup>> entry : duplicationCache.entries()) {
+ for (Entry<List<DuplicationGroup>> entry : duplicationCache.entries()) {
String effectiveKey = entry.key()[0].toString();
duplications.put(effectiveKey, entry.value());
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java
index d285a6c8646..1cf87b1d6d3 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java
@@ -19,6 +19,7 @@
*/
package org.sonar.batch.scan;
+import com.google.common.base.Preconditions;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
@@ -28,7 +29,9 @@ import org.sonar.api.batch.measure.Metric;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
-import org.sonar.api.batch.sensor.duplication.TokenBuilder;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
+import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
+import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder;
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.issue.IssueBuilder;
@@ -52,7 +55,6 @@ import org.sonar.api.resources.Resource;
import org.sonar.api.resources.Scopes;
import org.sonar.api.rule.RuleKey;
import org.sonar.batch.duplication.BlockCache;
-import org.sonar.batch.duplication.DefaultDuplicationBuilder;
import org.sonar.batch.duplication.DefaultTokenBuilder;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.highlighting.DefaultHighlightingBuilder;
@@ -61,6 +63,7 @@ import org.sonar.batch.symbol.DefaultSymbolTableBuilder;
import org.sonar.duplications.internal.pmd.PmdBlockChunker;
import java.io.Serializable;
+import java.util.List;
/**
* Implements {@link SensorContext} but forward everything to {@link org.sonar.api.batch.SensorContext} for backward compatibility.
@@ -267,14 +270,24 @@ public class SensorContextAdaptor implements SensorContext {
}
@Override
- public TokenBuilder tokenBuilder(InputFile inputFile) {
+ public DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile) {
PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language()));
return new DefaultTokenBuilder(inputFile, blockCache, blockChunker);
}
@Override
public DuplicationBuilder duplicationBuilder(InputFile inputFile) {
- return new DefaultDuplicationBuilder(inputFile, duplicationCache);
+ return new DefaultDuplicationBuilder(inputFile);
+ }
+
+ @Override
+ public void saveDuplications(InputFile inputFile, List<DuplicationGroup> duplications) {
+ Preconditions.checkState(duplications.size() > 0, "Empty duplications");
+ String effectiveKey = ((DefaultInputFile) inputFile).key();
+ for (DuplicationGroup duplicationGroup : duplications) {
+ Preconditions.checkState(effectiveKey.equals(duplicationGroup.originBlock().resourceKey()), "Invalid duplication group");
+ }
+ duplicationCache.put(effectiveKey, duplications);
}
private int getBlockSize(String languageKey) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
index 73d6429bfcd..afd21a8d358 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
@@ -19,6 +19,7 @@
*/
package org.sonar.batch.scan2;
+import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.FileSystem;
@@ -29,7 +30,9 @@ import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.DefaultActiveRule;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
-import org.sonar.api.batch.sensor.duplication.TokenBuilder;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
+import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
+import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplicationBuilder;
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.issue.IssueBuilder;
@@ -44,7 +47,6 @@ import org.sonar.api.config.Settings;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.duplication.BlockCache;
-import org.sonar.batch.duplication.DefaultDuplicationBuilder;
import org.sonar.batch.duplication.DefaultTokenBuilder;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.highlighting.DefaultHighlightingBuilder;
@@ -56,6 +58,7 @@ import org.sonar.core.component.ComponentKeys;
import org.sonar.duplications.internal.pmd.PmdBlockChunker;
import java.io.Serializable;
+import java.util.List;
public class DefaultSensorContext implements SensorContext {
@@ -188,7 +191,7 @@ public class DefaultSensorContext implements SensorContext {
}
@Override
- public TokenBuilder tokenBuilder(InputFile inputFile) {
+ public DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile) {
PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language()));
return new DefaultTokenBuilder(inputFile, blockCache, blockChunker);
@@ -196,7 +199,17 @@ public class DefaultSensorContext implements SensorContext {
@Override
public DuplicationBuilder duplicationBuilder(InputFile inputFile) {
- return new DefaultDuplicationBuilder(inputFile, duplicationCache);
+ return new DefaultDuplicationBuilder(inputFile);
+ }
+
+ @Override
+ public void saveDuplications(InputFile inputFile, List<DuplicationGroup> duplications) {
+ Preconditions.checkState(duplications.size() > 0, "Empty duplications");
+ String effectiveKey = ((DefaultInputFile) inputFile).key();
+ for (DuplicationGroup duplicationGroup : duplications) {
+ Preconditions.checkState(effectiveKey.equals(duplicationGroup.originBlock().resourceKey()), "Invalid duplication group");
+ }
+ duplicationCache.put(effectiveKey, duplications);
}
private int getBlockSize(String languageKey) {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java
index ade701fce45..6317093f00a 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java
@@ -25,11 +25,13 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.batch.index.Caches;
import org.sonar.batch.index.CachesTest;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
@@ -74,7 +76,7 @@ public class DuplicationCacheTest {
assertThat(cache.entries()).hasSize(1);
- ArrayList<DuplicationGroup> entry = cache.byComponent("foo");
+ List<DuplicationGroup> entry = cache.byComponent("foo");
assertThat(entry.get(0).originBlock().resourceKey()).isEqualTo("foo");
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java
index 1860732e80d..644d7400999 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/index/DuplicationPersisterTest.java
@@ -22,17 +22,17 @@ package org.sonar.batch.index;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.File;
import org.sonar.api.rules.RuleFinder;
import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.duplication.DuplicationGroup;
import org.sonar.core.persistence.AbstractDaoTestCase;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -77,7 +77,7 @@ public class DuplicationPersisterTest extends AbstractDaoTestCase {
.addDuplicate(new DuplicationGroup.Block("foo:org/foo/Foo.java", 5, 9));
when(duplicationCache.entries()).thenReturn(
- Arrays.<Cache.Entry<ArrayList<DuplicationGroup>>>asList(new Cache.Entry(new String[] {"foo:org/foo/Bar.java"}, Arrays.asList(group))));
+ Arrays.<Cache.Entry<List<DuplicationGroup>>>asList(new Cache.Entry(new String[] {"foo:org/foo/Bar.java"}, Arrays.asList(group))));
duplicationPersister.persist();
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
index 2e472cabf17..39888e030c3 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
@@ -108,10 +108,8 @@ public class DefaultInputFile implements InputFile, Serializable {
}
/**
- * Component key. It's marked as nullable just for the unit tests that
- * do not previously call {@link #setKey(String)}.
+ * Component key.
*/
- @CheckForNull
public String key() {
return key;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
index 647cab3f3f9..d572d974af4 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
@@ -25,7 +25,8 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measure.Metric;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
-import org.sonar.api.batch.sensor.duplication.TokenBuilder;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
+import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.issue.IssueBuilder;
@@ -37,6 +38,7 @@ import org.sonar.api.config.Settings;
import javax.annotation.CheckForNull;
import java.io.Serializable;
+import java.util.List;
/**
* @since 4.4
@@ -92,6 +94,7 @@ public interface SensorContext {
/**
* Add a measure. Use {@link #measureBuilder()} to create the new measure.
+ * A measure for a given metric can only be saved once for the same resource.
*/
void addMeasure(Measure<?> measure);
@@ -134,13 +137,19 @@ public interface SensorContext {
* Builder to define tokens in a file. Tokens are used to compute duplication by the core.
* @since 4.5
*/
- TokenBuilder tokenBuilder(InputFile inputFile);
+ DuplicationTokenBuilder duplicationTokenBuilder(InputFile inputFile);
/**
* Builder to manually define duplications in a file. When duplication are manually computed then
- * no need to use {@link #tokenBuilder(InputFile)}.
+ * no need to use {@link #duplicationTokenBuilder(InputFile)}.
* @since 4.5
*/
DuplicationBuilder duplicationBuilder(InputFile inputFile);
+ /**
+ * Register all duplications of an {@link InputFile}. Use {@link #duplicationBuilder(InputFile)} to create
+ * list of duplications.
+ */
+ void saveDuplications(InputFile inputFile, List<DuplicationGroup> duplications);
+
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationBuilder.java
index 2f37220b1a3..aa27ff41b28 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationBuilder.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationBuilder.java
@@ -21,18 +21,39 @@ package org.sonar.api.batch.sensor.duplication;
import org.sonar.api.batch.fs.InputFile;
+import java.util.List;
+
/**
* This builder is used to declare duplications on files of the project.
+ * Usage:
+ * <code><pre>
+ * DuplicationBuilder builder = context.duplicationBuilder(inputFile);
+ * .originBlock(2, 10)
+ * .isDuplicatedBy(inputFile, 14, 22)
+ * .isDuplicatedBy(anotherInputFile, 3, 11)
+ * // Start another duplication
+ * .originBlock(45, 50)
+ * .isDuplicatedBy(yetAnotherInputFile, 10, 15);
+ * context.saveDuplications(inputFile, builder.build());
+ * </pre></code>
* @since 4.5
*/
public interface DuplicationBuilder {
+ /**
+ * Declare duplication origin block. Then call {@link #isDuplicatedBy(InputFile, int, int)} to reference all duplicates of this block.
+ * Then call again {@link #originBlock(int, int)} to declare another duplication.
+ */
DuplicationBuilder originBlock(int startLine, int endLine);
+ /**
+ * Declare duplicate block of the previously declared {@link #originBlock(int, int)}.
+ * @param sameOrOtherFile duplicate can be in the same file or in another file.
+ */
DuplicationBuilder isDuplicatedBy(InputFile sameOrOtherFile, int startLine, int endLine);
/**
- * Call this method only once when your are done with defining all duplicates of origin block.
+ * Call this method when you have declared all duplications of the file.
*/
- void done();
+ List<DuplicationGroup> build();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationGroup.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationGroup.java
new file mode 100644
index 00000000000..9061e9165e3
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationGroup.java
@@ -0,0 +1,148 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.sensor.duplication;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.sensor.SensorContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link DuplicationGroup} is a list of duplicated {@link Block}s. One block
+ * is considered as the original code and all others are duplicates.
+ * Use {@link SensorContext#duplicationBuilder(org.sonar.api.batch.fs.InputFile)} and
+ * {@link SensorContext#saveDuplications(org.sonar.api.batch.fs.InputFile, List)}.
+ * @since 4.5
+ */
+public class DuplicationGroup {
+
+ public static class Block {
+ private final String resourceKey;
+ private final int startLine;
+ private final int length;
+
+ public Block(String resourceKey, int startLine, int length) {
+ this.resourceKey = resourceKey;
+ this.startLine = startLine;
+ this.length = length;
+ }
+
+ public String resourceKey() {
+ return resourceKey;
+ }
+
+ public int startLine() {
+ return startLine;
+ }
+
+ public int length() {
+ return length;
+ }
+
+ // Just for unit tests
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ Block rhs = (Block) obj;
+ return new EqualsBuilder()
+ .append(resourceKey, rhs.resourceKey)
+ .append(startLine, rhs.startLine)
+ .append(length, rhs.length).isEquals();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).
+ append("resourceKey", resourceKey).
+ append("startLine", startLine).
+ append("length", length).
+ toString();
+ }
+ }
+
+ private final Block originBlock;
+ private List<Block> duplicates = new ArrayList<DuplicationGroup.Block>();
+
+ /**
+ * For unit test and internal use only.
+ */
+ public DuplicationGroup(Block originBlock) {
+ this.originBlock = originBlock;
+ }
+
+ public void setDuplicates(List<Block> duplicates) {
+ this.duplicates = duplicates;
+ }
+
+ public DuplicationGroup addDuplicate(Block anotherBlock) {
+ this.duplicates.add(anotherBlock);
+ return this;
+ }
+
+ public Block originBlock() {
+ return originBlock;
+ }
+
+ public List<Block> duplicates() {
+ return duplicates;
+ }
+
+ // Just for unit tests
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ DuplicationGroup rhs = (DuplicationGroup) obj;
+ EqualsBuilder equalsBuilder = new EqualsBuilder()
+ .append(originBlock, rhs.originBlock)
+ .append(duplicates.size(), rhs.duplicates.size());
+ for (int i = 0; i < duplicates.size(); i++) {
+ equalsBuilder.append(duplicates.get(i), rhs.duplicates.get(i));
+ }
+ return equalsBuilder.isEquals();
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).
+ append("origin", originBlock).
+ append("duplicates", duplicates, true).
+ toString();
+ }
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/TokenBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationTokenBuilder.java
index f4de9fffc8c..6dfd437c552 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/TokenBuilder.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/DuplicationTokenBuilder.java
@@ -19,19 +19,30 @@
*/
package org.sonar.api.batch.sensor.duplication;
+
/**
* This builder is used to define token on files. Tokens are later used to compute duplication.
* Tokens should be declared in sequential order.
+ * Example:
+ * <code><pre>
+ * DuplicationTokenBuilder tokenBuilder = context.duplicationTokenBuilder(inputFile)
+ * .addToken(1, "public")
+ * .addToken(1, "class")
+ * .addToken(1, "Foo")
+ * .addToken(1, "{")
+ * .addToken(2, "}")
+ * .done();
+ * </pre></code>
* @since 4.5
*/
-public interface TokenBuilder {
+public interface DuplicationTokenBuilder {
/**
* Call this method to register a new token.
* @param line Line number of the token. Line starts at 1.
* @param image Text of the token.
*/
- TokenBuilder addToken(int line, String image);
+ DuplicationTokenBuilder addToken(int line, String image);
/**
* Call this method only once when your are done with defining tokens of the file.
diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationBuilder.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/internal/DefaultDuplicationBuilder.java
index d6dd18026a2..77392b735b6 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationBuilder.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/internal/DefaultDuplicationBuilder.java
@@ -17,26 +17,25 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-package org.sonar.batch.duplication;
+package org.sonar.api.batch.sensor.duplication.internal;
import com.google.common.base.Preconditions;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
+import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import java.util.ArrayList;
+import java.util.List;
public class DefaultDuplicationBuilder implements DuplicationBuilder {
private final InputFile inputFile;
- private final DuplicationCache duplicationCache;
- private boolean done = false;
private DuplicationGroup current = null;
- private ArrayList<DuplicationGroup> duplications;
+ private List<DuplicationGroup> duplications;
- public DefaultDuplicationBuilder(InputFile inputFile, DuplicationCache duplicationCache) {
+ public DefaultDuplicationBuilder(InputFile inputFile) {
this.inputFile = inputFile;
- this.duplicationCache = duplicationCache;
duplications = new ArrayList<DuplicationGroup>();
}
@@ -65,10 +64,16 @@ public class DefaultDuplicationBuilder implements DuplicationBuilder {
}
@Override
- public void done() {
- Preconditions.checkState(!done, "done() already called");
+ public List<DuplicationGroup> build() {
Preconditions.checkNotNull(current, "Call originBlock() first");
duplications.add(current);
- duplicationCache.put(((DefaultInputFile) inputFile).key(), duplications);
+ List<DuplicationGroup> result = duplications;
+ reset();
+ return result;
+ }
+
+ private void reset() {
+ duplications = new ArrayList<DuplicationGroup>();
+ current = null;
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/internal/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/internal/package-info.java
new file mode 100644
index 00000000000..229366c3e9d
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/duplication/internal/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.api.batch.sensor.duplication.internal;