aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Mandrikov <mandrikov@gmail.com>2012-04-30 12:33:15 +0600
committerEvgeny Mandrikov <mandrikov@gmail.com>2012-04-30 16:42:20 +0600
commit298ece1b781be58ca70d4406a5df84b26869dbe7 (patch)
tree76c804ba0e699062031bd80bbfd7c0db248f91ea
parentbd01ac1036d4a85c1cc434d720f0897a3f7b5fd3 (diff)
downloadsonarqube-298ece1b781be58ca70d4406a5df84b26869dbe7.tar.gz
sonarqube-298ece1b781be58ca70d4406a5df84b26869dbe7.zip
SONAR-3182 Do not use PMD CPD
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdAnalyser.java101
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdException.java26
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java8
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java47
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/DuplicationsData.java111
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/PmdEngine.java110
-rw-r--r--plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java11
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdAnalyserTest.java344
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java35
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/PmdEngineTest.java92
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java32
-rw-r--r--sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDListener.java39
-rw-r--r--sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDNullListener.java34
-rw-r--r--sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/Tokens.java14
-rw-r--r--sonar-duplications/src/main/java/net/sourceforge/pmd/util/FileFinder.java62
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/cpd/CPD.java120
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/cpd/Match.java199
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchAlgorithm.java150
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchCollector.java180
-rw-r--r--sonar-duplications/src/test/java/org/sonar/duplications/cpd/CPDTest.java93
20 files changed, 82 insertions, 1726 deletions
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdAnalyser.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdAnalyser.java
deleted file mode 100644
index 25bf47f6247..00000000000
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdAnalyser.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-package org.sonar.plugins.cpd;
-
-import net.sourceforge.pmd.cpd.TokenEntry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.CpdMapping;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.duplications.cpd.Match;
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-public class CpdAnalyser {
-
- private static final Logger LOG = LoggerFactory.getLogger(CpdAnalyser.class);
-
- private CpdMapping mapping;
- private SensorContext context;
- private Project project;
-
- public CpdAnalyser(Project project, SensorContext context, CpdMapping mapping) {
- this.mapping = mapping;
- this.context = context;
- this.project = project;
- }
-
- public void analyse(Iterator<Match> matches) {
- Map<Resource, DuplicationsData> duplicationsData = new HashMap<Resource, DuplicationsData>();
- while (matches.hasNext()) {
- Match match = matches.next();
-
- for (TokenEntry firstMark : match.getMarkSet()) {
- String firstAbsolutePath = firstMark.getTokenSrcID();
- int firstLine = firstMark.getBeginLine();
-
- Resource firstFile = mapping.createResource(new File(firstAbsolutePath), project.getFileSystem().getSourceDirs());
- if (firstFile == null) {
- LOG.warn("CPD - File not found : {}", firstAbsolutePath);
- continue;
- }
-
- DuplicationsData firstFileData = getDuplicationsData(duplicationsData, firstFile);
- firstFileData.incrementDuplicatedBlock();
-
- for (TokenEntry tokenEntry : match.getMarkSet()) {
- String secondAbsolutePath = tokenEntry.getTokenSrcID();
- int secondLine = tokenEntry.getBeginLine();
- if (secondAbsolutePath.equals(firstAbsolutePath) && firstLine == secondLine) {
- continue;
- }
- Resource secondFile = mapping.createResource(new File(secondAbsolutePath), project.getFileSystem().getSourceDirs());
- if (secondFile == null) {
- LOG.warn("CPD - File not found : {}", secondAbsolutePath);
- continue;
- }
-
- String resourceKey = SonarEngine.getFullKey(project, secondFile);
- firstFileData.cumulate(resourceKey, secondLine, firstLine, match.getLineCount());
- }
- }
- }
-
- for (Map.Entry<Resource, DuplicationsData> entry : duplicationsData.entrySet()) {
- entry.getValue().save(context, entry.getKey());
- }
- }
-
- private DuplicationsData getDuplicationsData(Map<Resource, DuplicationsData> fileContainer, Resource file) {
- DuplicationsData data = fileContainer.get(file);
- if (data == null) {
- String resourceKey = SonarEngine.getFullKey(project, file);
- data = new DuplicationsData(resourceKey);
- fileContainer.put(file, data);
- }
- return data;
- }
-
-}
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdException.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdException.java
deleted file mode 100644
index f4cd45b4d55..00000000000
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-package org.sonar.plugins.cpd;
-
-public class CpdException extends RuntimeException {
- public CpdException(Throwable throwable) {
- super(throwable);
- }
-}
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java
index 9b734290990..ccbe4936d82 100644
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java
+++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdPlugin.java
@@ -20,12 +20,7 @@
package org.sonar.plugins.cpd;
import com.google.common.collect.ImmutableList;
-import org.sonar.api.BatchExtension;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.Properties;
-import org.sonar.api.Property;
-import org.sonar.api.PropertyType;
-import org.sonar.api.SonarPlugin;
+import org.sonar.api.*;
import org.sonar.plugins.cpd.decorators.DuplicationDensityDecorator;
import org.sonar.plugins.cpd.decorators.SumDuplicationsDecorator;
import org.sonar.plugins.cpd.index.IndexFactory;
@@ -103,7 +98,6 @@ public final class CpdPlugin extends SonarPlugin {
DuplicationDensityDecorator.class,
IndexFactory.class,
SonarEngine.class,
- PmdEngine.class,
SonarBridgeEngine.class);
}
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java
index b07ff10dbff..754ef176ee0 100644
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java
+++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/CpdSensor.java
@@ -19,67 +19,51 @@
*/
package org.sonar.plugins.cpd;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.configuration.Configuration;
-import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;
-import org.sonar.api.utils.Logs;
public class CpdSensor implements Sensor {
+ private static final Logger LOG = LoggerFactory.getLogger(CpdSensor.class);
+
private CpdEngine sonarEngine;
- private CpdEngine pmdEngine;
private CpdEngine sonarBridgeEngine;
- public CpdSensor(SonarEngine sonarEngine, PmdEngine pmdEngine) {
+ public CpdSensor(SonarEngine sonarEngine, SonarBridgeEngine sonarBridgeEngine) {
this.sonarEngine = sonarEngine;
- this.pmdEngine = pmdEngine;
- }
-
- public CpdSensor(SonarEngine sonarEngine, PmdEngine pmdEngine, SonarBridgeEngine sonarBridgeEngine) {
- this.sonarEngine = sonarEngine;
- this.pmdEngine = pmdEngine;
this.sonarBridgeEngine = sonarBridgeEngine;
}
public boolean shouldExecuteOnProject(Project project) {
if (isSkipped(project)) {
- LoggerFactory.getLogger(getClass()).info("Detection of duplicated code is skipped");
+ LOG.info("Detection of duplicated code is skipped");
return false;
}
if (!getEngine(project).isLanguageSupported(project.getLanguage())) {
- LoggerFactory.getLogger(getClass()).info("Detection of duplication code is not supported for {}.", project.getLanguage());
+ LOG.info("Detection of duplicated code is not supported for {}.", project.getLanguage());
return false;
}
return true;
}
- private CpdEngine getEngine(Project project) {
- if (isEngineEnabled(project, "sonar")) {
- if (sonarEngine.isLanguageSupported(project.getLanguage())) {
- return sonarEngine;
- }
- // falback to bridge
- } else if (isEngineEnabled(project, "pmd")) {
- return pmdEngine;
+ @VisibleForTesting
+ CpdEngine getEngine(Project project) {
+ if (sonarEngine.isLanguageSupported(project.getLanguage())) {
+ return sonarEngine;
+ } else {
+ return sonarBridgeEngine;
}
- return sonarBridgeEngine;
- }
-
- boolean isEngineEnabled(Project project, String engineName) {
- Configuration conf = project.getConfiguration();
- return StringUtils.equalsIgnoreCase(conf.getString(CoreProperties.CPD_ENGINE, CoreProperties.CPD_ENGINE_DEFAULT_VALUE), engineName);
- }
-
- boolean isSonarEngineEnabled(Project project) {
- return isEngineEnabled(project, "sonar");
}
+ @VisibleForTesting
boolean isSkipped(Project project) {
Configuration conf = project.getConfiguration();
return conf.getBoolean("sonar.cpd." + project.getLanguageKey() + ".skip",
@@ -88,7 +72,7 @@ public class CpdSensor implements Sensor {
public void analyse(Project project, SensorContext context) {
CpdEngine engine = getEngine(project);
- Logs.INFO.info("{} is used", engine);
+ LOG.info("{} is used", engine);
engine.analyse(project, context);
}
@@ -96,4 +80,5 @@ public class CpdSensor implements Sensor {
public String toString() {
return getClass().getSimpleName();
}
+
}
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/DuplicationsData.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/DuplicationsData.java
deleted file mode 100644
index fc800738a86..00000000000
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/DuplicationsData.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-package org.sonar.plugins.cpd;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.PersistenceMode;
-import org.sonar.api.resources.Resource;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Set;
-
-public class DuplicationsData {
-
- private final String resourceKey;
- private final Set<Integer> duplicatedLines = Sets.newHashSet();
- private final List<XmlEntry> duplicationXMLEntries = Lists.newArrayList();
-
- private double duplicatedBlocks;
-
- public DuplicationsData(String resourceKey) {
- this.resourceKey = resourceKey;
- }
-
- public void cumulate(String targetResourceKey, int targetDuplicationStartLine, int duplicationStartLine, int duplicatedLines) {
- duplicationXMLEntries.add(new XmlEntry(targetResourceKey, targetDuplicationStartLine, duplicationStartLine, duplicatedLines));
- for (int duplicatedLine = duplicationStartLine; duplicatedLine < duplicationStartLine + duplicatedLines; duplicatedLine++) {
- this.duplicatedLines.add(duplicatedLine);
- }
- }
-
- public void incrementDuplicatedBlock() {
- duplicatedBlocks++;
- }
-
- public void save(SensorContext context, Resource resource) {
- context.saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
- context.saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, (double) duplicatedLines.size());
- context.saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, duplicatedBlocks);
-
- Measure data = new Measure(CoreMetrics.DUPLICATIONS_DATA, getDuplicationXMLData())
- .setPersistenceMode(PersistenceMode.DATABASE);
- context.saveMeasure(resource, data);
- }
-
- private String getDuplicationXMLData() {
- Collections.sort(duplicationXMLEntries, COMPARATOR);
- StringBuilder duplicationXML = new StringBuilder("<duplications>");
- for (XmlEntry xmlEntry : duplicationXMLEntries) {
- duplicationXML.append(xmlEntry.toString());
- }
- duplicationXML.append("</duplications>");
- return duplicationXML.toString();
- }
-
- private static final Comparator<XmlEntry> COMPARATOR = new Comparator<XmlEntry>() {
- public int compare(XmlEntry o1, XmlEntry o2) {
- if (o1.startLine == o2.startLine) {
- return o1.lines - o2.lines;
- }
- return o1.startLine - o2.startLine;
- }
- };
-
- private final class XmlEntry {
- private final String target;
- private final int targetStartLine;
- private final int startLine;
- private final int lines;
-
- private XmlEntry(String target, int targetStartLine, int startLine, int lines) {
- this.target = target;
- this.targetStartLine = targetStartLine;
- this.startLine = startLine;
- this.lines = lines;
- }
-
- @Override
- public String toString() {
- return new StringBuilder()
- .append("<g>")
- .append("<b s=\"").append(startLine).append("\" l=\"").append(lines).append("\" r=\"").append(resourceKey).append("\" />")
- .append("<b s=\"").append(targetStartLine).append("\" l=\"").append(lines).append("\" r=\"").append(target).append("\" />")
- .append("</g>")
- .toString();
- }
- }
-
-}
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/PmdEngine.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/PmdEngine.java
deleted file mode 100644
index e84f22e36de..00000000000
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/PmdEngine.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-package org.sonar.plugins.cpd;
-
-import com.google.common.annotations.VisibleForTesting;
-import net.sourceforge.pmd.cpd.AbstractLanguage;
-import net.sourceforge.pmd.cpd.TokenEntry;
-import org.apache.commons.configuration.Configuration;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.CpdMapping;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Project;
-import org.sonar.duplications.cpd.CPD;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-
-public class PmdEngine extends CpdEngine {
-
- private final CpdMapping[] mappings;
-
- public PmdEngine() {
- this.mappings = null;
- }
-
- public PmdEngine(CpdMapping[] mappings) {
- this.mappings = mappings;
- }
-
- @Override
- public boolean isLanguageSupported(Language language) {
- return getMapping(language) != null;
- }
-
- private CpdMapping getMapping(Language language) {
- if (mappings != null) {
- for (CpdMapping cpdMapping : mappings) {
- if (cpdMapping.getLanguage().equals(language)) {
- return cpdMapping;
- }
- }
- }
- return null;
- }
-
- @Override
- public void analyse(Project project, SensorContext context) {
- CpdMapping mapping = getMapping(project.getLanguage());
- CPD cpd = executeCPD(project, mapping, project.getFileSystem().getSourceCharset());
- saveResults(cpd, mapping, project, context);
- }
-
- private void saveResults(CPD cpd, CpdMapping mapping, Project project, SensorContext context) {
- CpdAnalyser cpdAnalyser = new CpdAnalyser(project, context, mapping);
- cpdAnalyser.analyse(cpd.getMatches());
- }
-
- private CPD executeCPD(Project project, CpdMapping mapping, Charset encoding) {
- try {
- CPD cpd = configureCPD(project, mapping, encoding);
- cpd.go();
- return cpd;
-
- } catch (Exception e) {
- throw new CpdException(e);
- }
- }
-
- private CPD configureCPD(Project project, CpdMapping mapping, Charset encoding) throws IOException {
- // To avoid a cpd bug generating error as "java.lang.IndexOutOfBoundsException: Index: 259, Size: 248"
- // See http://sourceforge.net/tracker/?func=detail&atid=479921&aid=1947823&group_id=56262 for more details
- TokenEntry.clearImages();
-
- int minTokens = getMinimumTokens(project);
- AbstractLanguage cpdLanguage = new AbstractLanguage(mapping.getTokenizer()) {
- };
-
- CPD cpd = new CPD(minTokens, cpdLanguage);
- cpd.setEncoding(encoding.name());
- cpd.setLoadSourceCodeSlices(false);
- cpd.add(project.getFileSystem().getSourceFiles(project.getLanguage()));
- return cpd;
- }
-
- @VisibleForTesting
- static int getMinimumTokens(Project project) {
- Configuration conf = project.getConfiguration();
- return conf.getInt("sonar.cpd." + project.getLanguageKey() + ".minimumTokens",
- conf.getInt("sonar.cpd.minimumTokens", CoreProperties.CPD_MINIMUM_TOKENS_DEFAULT_VALUE));
- }
-
-}
diff --git a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java
index 026893d031c..2b3cfe2e8bc 100644
--- a/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java
+++ b/plugins/sonar-cpd-plugin/src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java
@@ -22,8 +22,10 @@ package org.sonar.plugins.cpd;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.CpdMapping;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.*;
@@ -89,7 +91,7 @@ public class SonarBridgeEngine extends CpdEngine {
}
// Detect
- Predicate<CloneGroup> minimumTokensPredicate = DuplicationPredicates.numberOfUnitsNotLessThan(PmdEngine.getMinimumTokens(project));
+ Predicate<CloneGroup> minimumTokensPredicate = DuplicationPredicates.numberOfUnitsNotLessThan(getMinimumTokens(project));
ExecutorService executorService = Executors.newSingleThreadExecutor();
try {
@@ -137,6 +139,13 @@ public class SonarBridgeEngine extends CpdEngine {
}
}
+ @VisibleForTesting
+ static int getMinimumTokens(Project project) {
+ Configuration conf = project.getConfiguration();
+ return conf.getInt("sonar.cpd." + project.getLanguageKey() + ".minimumTokens",
+ conf.getInt("sonar.cpd.minimumTokens", CoreProperties.CPD_MINIMUM_TOKENS_DEFAULT_VALUE));
+ }
+
private CpdMapping getMapping(Language language) {
if (mappings != null) {
for (CpdMapping cpdMapping : mappings) {
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdAnalyserTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdAnalyserTest.java
deleted file mode 100644
index ada79ec7400..00000000000
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdAnalyserTest.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-package org.sonar.plugins.cpd;
-
-import net.sourceforge.pmd.cpd.TokenEntry;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.sonar.api.batch.CpdMapping;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.resources.JavaFile;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectFileSystem;
-import org.sonar.api.resources.Resource;
-import org.sonar.duplications.cpd.Match;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
-
-public class CpdAnalyserTest {
-
- @Test
- public void testOneSimpleDuplicationBetweenTwoFiles() throws Exception {
- ProjectFileSystem fileSystem = mock(ProjectFileSystem.class);
- when(fileSystem.getSourceDirs()).thenReturn(Collections.<File> emptyList());
- File file1 = new File("target/tmp/file1.ext");
- File file2 = new File("target/tmp/file2.ext");
-
- Project project = new Project("key").setFileSystem(fileSystem);
-
- SensorContext context = mock(SensorContext.class);
-
- CpdMapping cpdMapping = mock(CpdMapping.class);
- Resource resource1 = new JavaFile("foo.Foo");
- Resource resource2 = new JavaFile("foo.Bar");
- when(cpdMapping.createResource((File) anyObject(), anyList())).thenReturn(resource1).thenReturn(resource2).thenReturn(resource2)
- .thenReturn(resource1);
-
- Match match1 = new Match(5, new TokenEntry(null, file1.getAbsolutePath(), 5), new TokenEntry(null, file2.getAbsolutePath(), 15));
- match1.setLineCount(200);
-
- CpdAnalyser cpdAnalyser = new CpdAnalyser(project, context, cpdMapping);
- cpdAnalyser.analyse(Arrays.asList(match1).iterator());
-
- ArgumentCaptor<Measure> measureCaptor = ArgumentCaptor.forClass(Measure.class);
-
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(eq(resource1), measureCaptor.capture());
- Measure measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications><g>"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "</g></duplications>"));
-
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(eq(resource2), measureCaptor.capture());
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications><g>"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "</g></duplications>"));
- }
-
- @Test
- public void testClassicalCaseWithTwoDuplicatedBlocsInvolvingThreeFiles() throws Exception {
- ProjectFileSystem fileSystem = mock(ProjectFileSystem.class);
- when(fileSystem.getSourceDirs()).thenReturn(Collections.<File> emptyList());
- File file1 = new File("target/tmp/file1.ext");
- File file2 = new File("target/tmp/file2.ext");
- File file3 = new File("target/tmp/file3.ext");
-
- Project project = new Project("key").setFileSystem(fileSystem);
-
- SensorContext context = mock(SensorContext.class);
-
- CpdMapping cpdMapping = mock(CpdMapping.class);
- Resource resource1 = new JavaFile("foo.Foo");
- Resource resource2 = new JavaFile("foo.Bar");
- Resource resource3 = new JavaFile("foo.Hotel");
- when(cpdMapping.createResource((File) anyObject(), anyList())).thenReturn(resource1).thenReturn(resource2).thenReturn(resource2)
- .thenReturn(resource1).thenReturn(resource1).thenReturn(resource3).thenReturn(resource3).thenReturn(resource1);
-
- Match match1 = new Match(5, new TokenEntry(null, file1.getAbsolutePath(), 5), new TokenEntry(null, file2.getAbsolutePath(), 15));
- match1.setLineCount(200);
- Match match2 = new Match(5, new TokenEntry(null, file1.getAbsolutePath(), 5), new TokenEntry(null, file3.getAbsolutePath(), 15));
- match2.setLineCount(100);
-
- CpdAnalyser cpdAnalyser = new CpdAnalyser(project, context, cpdMapping);
- cpdAnalyser.analyse(Arrays.asList(match1, match2).iterator());
-
- ArgumentCaptor<Measure> measureCaptor = ArgumentCaptor.forClass(Measure.class);
-
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_BLOCKS, 2d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(eq(resource1), measureCaptor.capture());
-
- Measure measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"5\" l=\"100\" r=\"key:foo.Foo\" />"
- + "<b s=\"15\" l=\"100\" r=\"key:foo.Hotel\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "</g>"
- + "</duplications>"));
-
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(eq(resource2), measureCaptor.capture());
-
- measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "</g>"
- + "</duplications>"));
-
- verify(context).saveMeasure(resource3, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource3, CoreMetrics.DUPLICATED_LINES, 100d);
- verify(context).saveMeasure(resource3, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(eq(resource3), measureCaptor.capture());
-
- measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"15\" l=\"100\" r=\"key:foo.Hotel\" />"
- + "<b s=\"5\" l=\"100\" r=\"key:foo.Foo\" />"
- + "</g>"
- + "</duplications>"));
- }
-
- @Test
- public void testOneDuplicatedBlocInvolvingMoreThanTwoFiles() throws Exception {
- ProjectFileSystem fileSystem = mock(ProjectFileSystem.class);
- when(fileSystem.getSourceDirs()).thenReturn(Collections.<File> emptyList());
- File file1 = new File("target/tmp/file1.ext");
- File file2 = new File("target/tmp/file2.ext");
- File file3 = new File("target/tmp/file3.ext");
- File file4 = new File("target/tmp/file4.ext");
-
- Project project = new Project("key").setFileSystem(fileSystem);
-
- SensorContext context = mock(SensorContext.class);
-
- CpdMapping cpdMapping = mock(CpdMapping.class);
- Resource resource1 = new JavaFile("foo.Foo");
- Resource resource2 = new JavaFile("foo.Bar");
- Resource resource3 = new JavaFile("foo.Hotel");
- Resource resource4 = new JavaFile("foo.Coffee");
- when(cpdMapping.createResource((File) anyObject(), anyList())).thenReturn(resource1).thenReturn(resource2).thenReturn(resource3)
- .thenReturn(resource4).thenReturn(resource2).thenReturn(resource1).thenReturn(resource3).thenReturn(resource4)
- .thenReturn(resource3).thenReturn(resource1).thenReturn(resource2).thenReturn(resource4).thenReturn(resource4)
- .thenReturn(resource1).thenReturn(resource2).thenReturn(resource3);
-
- Match match = new Match(5, createTokenEntry(file1.getAbsolutePath(), 5), createTokenEntry(file2.getAbsolutePath(), 15));
- match.setLineCount(200);
- Set<TokenEntry> tokenEntries = new LinkedHashSet<TokenEntry>();
- tokenEntries.add(createTokenEntry(file1.getAbsolutePath(), 5));
- tokenEntries.add(createTokenEntry(file2.getAbsolutePath(), 15));
- tokenEntries.add(createTokenEntry(file3.getAbsolutePath(), 7));
- tokenEntries.add(createTokenEntry(file4.getAbsolutePath(), 10));
- match.setMarkSet(tokenEntries);
-
- CpdAnalyser cpdAnalyser = new CpdAnalyser(project, context, cpdMapping);
- cpdAnalyser.analyse(Arrays.asList(match).iterator());
-
- ArgumentCaptor<Measure> measureCaptor = ArgumentCaptor.forClass(Measure.class);
-
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(eq(resource1), measureCaptor.capture());
-
- Measure measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"7\" l=\"200\" r=\"key:foo.Hotel\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"10\" l=\"200\" r=\"key:foo.Coffee\" />"
- + "</g>"
- + "</duplications>"));
-
- verify(context).saveMeasure(resource3, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource3, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(resource3, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(eq(resource3), measureCaptor.capture());
-
- measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"7\" l=\"200\" r=\"key:foo.Hotel\" />"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"7\" l=\"200\" r=\"key:foo.Hotel\" />"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"7\" l=\"200\" r=\"key:foo.Hotel\" />"
- + "<b s=\"10\" l=\"200\" r=\"key:foo.Coffee\" />"
- + "</g>"
- + "</duplications>"));
-
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(resource2, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(eq(resource2), measureCaptor.capture());
-
- measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "<b s=\"7\" l=\"200\" r=\"key:foo.Hotel\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "<b s=\"10\" l=\"200\" r=\"key:foo.Coffee\" />"
- + "</g>"
- + "</duplications>"));
-
- verify(context).saveMeasure(resource4, CoreMetrics.DUPLICATED_LINES, 200d);
- verify(context).saveMeasure(resource4, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource4, CoreMetrics.DUPLICATED_BLOCKS, 1d);
- verify(context).saveMeasure(eq(resource4), measureCaptor.capture());
-
- measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"10\" l=\"200\" r=\"key:foo.Coffee\" />"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"10\" l=\"200\" r=\"key:foo.Coffee\" />"
- + "<b s=\"15\" l=\"200\" r=\"key:foo.Bar\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"10\" l=\"200\" r=\"key:foo.Coffee\" />"
- + "<b s=\"7\" l=\"200\" r=\"key:foo.Hotel\" />"
- + "</g>"
- + "</duplications>"));
- }
-
- @Test
- public void testDuplicationOnSameFile() throws Exception {
- ProjectFileSystem fileSystem = mock(ProjectFileSystem.class);
- when(fileSystem.getSourceDirs()).thenReturn(Collections.<File> emptyList());
- File file1 = new File("target/tmp/file1.ext");
-
- Project project = new Project("key").setFileSystem(fileSystem);
-
- SensorContext context = mock(SensorContext.class);
-
- CpdMapping cpdMapping = mock(CpdMapping.class);
- Resource resource1 = new JavaFile("foo.Foo");
- when(cpdMapping.createResource((File) anyObject(), anyList())).thenReturn(resource1).thenReturn(resource1);
-
- Match match1 = new Match(304, new TokenEntry(null, file1.getAbsolutePath(), 5), new TokenEntry(null, file1.getAbsolutePath(), 215));
- match1.setLineCount(200);
-
- CpdAnalyser cpdAnalyser = new CpdAnalyser(project, context, cpdMapping);
- cpdAnalyser.analyse(Arrays.asList(match1).iterator());
-
- ArgumentCaptor<Measure> measureCaptor = ArgumentCaptor.forClass(Measure.class);
-
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_FILES, 1d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_LINES, 400d);
- verify(context).saveMeasure(resource1, CoreMetrics.DUPLICATED_BLOCKS, 2d);
- verify(context).saveMeasure(eq(resource1), measureCaptor.capture());
-
- Measure measure = measureCaptor.getValue();
- assertThat(measure.getMetric(), is(CoreMetrics.DUPLICATIONS_DATA));
- // FIXME in fact should be only one group - see SONAR-3131
- assertThat(measure.getData(), is("<duplications>"
- + "<g>"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"215\" l=\"200\" r=\"key:foo.Foo\" />"
- + "</g>"
- + "<g>"
- + "<b s=\"215\" l=\"200\" r=\"key:foo.Foo\" />"
- + "<b s=\"5\" l=\"200\" r=\"key:foo.Foo\" />"
- + "</g>"
- + "</duplications>"));
- }
-
- private static TokenEntry createTokenEntry(String sourceId, int line) {
- TokenEntry entry = new TokenEntry(null, sourceId, line);
- entry.setHashCode(sourceId.hashCode() + line);
- return entry;
- }
-}
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java
index 028b6f707a2..66e946c6d49 100644
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java
+++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java
@@ -20,8 +20,10 @@
package org.sonar.plugins.cpd;
import org.apache.commons.configuration.PropertiesConfiguration;
+import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.batch.CpdMapping;
+import org.sonar.api.resources.Java;
+import org.sonar.api.resources.Language;
import org.sonar.api.resources.Project;
import org.sonar.plugins.cpd.index.IndexFactory;
@@ -29,9 +31,22 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
public class CpdSensorTest {
+ private SonarEngine sonarEngine;
+ private SonarBridgeEngine sonarBridgeEngine;
+ private CpdSensor sensor;
+
+ @Before
+ public void setUp() {
+ IndexFactory indexFactory = new IndexFactory(null);
+ sonarEngine = new SonarEngine(indexFactory);
+ sonarBridgeEngine = new SonarBridgeEngine(indexFactory);
+ sensor = new CpdSensor(sonarEngine, sonarBridgeEngine);
+ }
+
@Test
public void generalSkip() {
PropertiesConfiguration conf = new PropertiesConfiguration();
@@ -39,7 +54,6 @@ public class CpdSensorTest {
Project project = createJavaProject().setConfiguration(conf);
- CpdSensor sensor = new CpdSensor(new SonarEngine(new IndexFactory(null)), new PmdEngine(new CpdMapping[0]));
assertTrue(sensor.isSkipped(project));
}
@@ -47,7 +61,6 @@ public class CpdSensorTest {
public void doNotSkipByDefault() {
Project project = createJavaProject().setConfiguration(new PropertiesConfiguration());
- CpdSensor sensor = new CpdSensor(new SonarEngine(new IndexFactory(null)), new PmdEngine(new CpdMapping[0]));
assertFalse(sensor.isSkipped(project));
}
@@ -60,28 +73,26 @@ public class CpdSensorTest {
Project phpProject = createPhpProject().setConfiguration(conf);
Project javaProject = createJavaProject().setConfiguration(conf);
- CpdSensor sensor = new CpdSensor(new SonarEngine(new IndexFactory(null)), new PmdEngine(new CpdMapping[0]));
assertTrue(sensor.isSkipped(phpProject));
assertFalse(sensor.isSkipped(javaProject));
}
@Test
public void engine() {
- PropertiesConfiguration conf = new PropertiesConfiguration();
- Project project = createJavaProject().setConfiguration(conf);
- CpdSensor sensor = new CpdSensor(new SonarEngine(new IndexFactory(null)), new PmdEngine(new CpdMapping[0]));
+ Project phpProject = createPhpProject();
+ Project javaProject = createJavaProject();
- assertThat(sensor.isSonarEngineEnabled(project), is(true));
- conf.setProperty("sonar.cpd.engine", "pmd");
- assertThat(sensor.isSonarEngineEnabled(project), is(false));
+ assertThat(sensor.getEngine(javaProject), is((CpdEngine) sonarEngine));
+ assertThat(sensor.getEngine(phpProject), is((CpdEngine) sonarBridgeEngine));
}
private Project createJavaProject() {
- return new Project("java_project").setLanguageKey("java");
+ return new Project("java_project").setLanguageKey("java").setLanguage(Java.INSTANCE);
}
private Project createPhpProject() {
- return new Project("php_project").setLanguageKey("php");
+ Language phpLanguage = mock(Language.class);
+ return new Project("php_project").setLanguageKey("php").setLanguage(phpLanguage);
}
}
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/PmdEngineTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/PmdEngineTest.java
deleted file mode 100644
index 3bbedf7f787..00000000000
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/PmdEngineTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-package org.sonar.plugins.cpd;
-
-import static junit.framework.Assert.assertEquals;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.junit.Test;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.CpdMapping;
-import org.sonar.api.resources.Java;
-import org.sonar.api.resources.Language;
-import org.sonar.api.resources.Project;
-
-public class PmdEngineTest {
-
- @Test
- public void shouldNotFailWhenNoMappings() {
- PmdEngine engine = new PmdEngine();
- assertThat(engine.isLanguageSupported(Java.INSTANCE), is(false));
- }
-
- @Test
- public void shouldCheckLanguageSupport() {
- CpdMapping mapping = mock(CpdMapping.class);
- when(mapping.getLanguage()).thenReturn(Java.INSTANCE);
- PmdEngine engine = new PmdEngine(new CpdMapping[] { mapping });
- assertThat(engine.isLanguageSupported(Java.INSTANCE), is(true));
-
- Language anotherLanguage = mock(Language.class);
- assertThat(engine.isLanguageSupported(anotherLanguage), is(false));
- }
-
- @Test
- public void defaultMinimumTokens() {
- Project project = createJavaProject().setConfiguration(new PropertiesConfiguration());
-
- assertEquals(CoreProperties.CPD_MINIMUM_TOKENS_DEFAULT_VALUE, PmdEngine.getMinimumTokens(project));
- }
-
- @Test
- public void generalMinimumTokens() {
- PropertiesConfiguration conf = new PropertiesConfiguration();
- conf.setProperty("sonar.cpd.minimumTokens", "33");
- Project project = createJavaProject().setConfiguration(conf);
-
- assertEquals(33, PmdEngine.getMinimumTokens(project));
- }
-
- @Test
- public void minimumTokensByLanguage() {
- PropertiesConfiguration conf = new PropertiesConfiguration();
- conf.setProperty("sonar.cpd.minimumTokens", "100");
- conf.setProperty("sonar.cpd.php.minimumTokens", "33");
-
- Project phpProject = createPhpProject().setConfiguration(conf);
- Project javaProject = createJavaProject().setConfiguration(conf);
-
- assertEquals(100, PmdEngine.getMinimumTokens(javaProject));
- assertEquals(33, PmdEngine.getMinimumTokens(phpProject));
- }
-
- private Project createJavaProject() {
- return new Project("java_project").setLanguageKey("java");
- }
-
- private Project createPhpProject() {
- return new Project("php_project").setLanguageKey("php");
- }
-
-}
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java
index e9ae76e300f..b036804b74e 100644
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java
+++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java
@@ -19,7 +19,10 @@
*/
package org.sonar.plugins.cpd;
+import org.apache.commons.configuration.PropertiesConfiguration;
import org.junit.Test;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.resources.Project;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
@@ -34,4 +37,33 @@ public class SonarBridgeEngineTest {
assertThat(SonarBridgeEngine.getDefaultBlockSize("other"), is(10));
}
+ @Test
+ public void defaultMinimumTokens() {
+ Project project = new Project("foo").setConfiguration(new PropertiesConfiguration());
+
+ assertThat(SonarBridgeEngine.getMinimumTokens(project), is(CoreProperties.CPD_MINIMUM_TOKENS_DEFAULT_VALUE));
+ }
+
+ @Test
+ public void generalMinimumTokens() {
+ PropertiesConfiguration conf = new PropertiesConfiguration();
+ conf.setProperty("sonar.cpd.minimumTokens", "33");
+ Project project = new Project("foo").setConfiguration(conf);
+
+ assertThat(SonarBridgeEngine.getMinimumTokens(project), is(33));
+ }
+
+ @Test
+ public void minimumTokensByLanguage() {
+ PropertiesConfiguration conf = new PropertiesConfiguration();
+ conf.setProperty("sonar.cpd.java.minimumTokens", "42");
+ conf.setProperty("sonar.cpd.php.minimumTokens", "33");
+
+ Project javaProject = new Project("foo").setLanguageKey("java").setConfiguration(conf);
+ Project phpProject = new Project("foo").setLanguageKey("php").setConfiguration(conf);
+
+ assertThat(SonarBridgeEngine.getMinimumTokens(javaProject), is(42));
+ assertThat(SonarBridgeEngine.getMinimumTokens(phpProject), is(33));
+ }
+
}
diff --git a/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDListener.java b/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDListener.java
deleted file mode 100644
index 8832c31ea2f..00000000000
--- a/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-package net.sourceforge.pmd.cpd;
-
-import java.io.File;
-
-public interface CPDListener {
-
- int INIT = 0;
- int HASH = 1;
- int MATCH = 2;
- int GROUPING = 3;
- int DONE = 4;
-
- void addedFile(int fileCount, File file);
-
- void phaseUpdate(int phase);
-}
diff --git a/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDNullListener.java b/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDNullListener.java
deleted file mode 100644
index 8bf581b1fef..00000000000
--- a/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/CPDNullListener.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-package net.sourceforge.pmd.cpd;
-
-import java.io.File;
-
-public class CPDNullListener implements CPDListener {
- public void addedFile(int fileCount, File file) {
- }
-
- public void phaseUpdate(int phase) {
- }
-}
diff --git a/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/Tokens.java b/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/Tokens.java
index 1f63af26923..a9398dba4d9 100644
--- a/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/Tokens.java
+++ b/sonar-duplications/src/main/java/net/sourceforge/pmd/cpd/Tokens.java
@@ -23,8 +23,6 @@
*/
package net.sourceforge.pmd.cpd;
-import org.sonar.duplications.cpd.Match;
-
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -46,22 +44,10 @@ public class Tokens {
return tokens.iterator();
}
- private TokenEntry get(int index) {
- return tokens.get(index);
- }
-
public int size() {
return tokens.size();
}
- public int getLineCount(TokenEntry mark, Match match) {
- TokenEntry endTok = get(mark.getIndex() + match.getTokenCount() - 1);
- if (endTok == TokenEntry.EOF) {
- endTok = get(mark.getIndex() + match.getTokenCount() - 2);
- }
- return endTok.getBeginLine() - mark.getBeginLine() + 1;
- }
-
public List<TokenEntry> getTokens() {
return tokens;
}
diff --git a/sonar-duplications/src/main/java/net/sourceforge/pmd/util/FileFinder.java b/sonar-duplications/src/main/java/net/sourceforge/pmd/util/FileFinder.java
deleted file mode 100644
index fc6b365e5f9..00000000000
--- a/sonar-duplications/src/main/java/net/sourceforge/pmd/util/FileFinder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-package net.sourceforge.pmd.util;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A utility class for finding files within a directory.
- */
-public class FileFinder {
-
- private FilenameFilter filter;
- private static final String FILE_SEP = System.getProperty("file.separator");
-
- public List<File> findFilesFrom(String dir, FilenameFilter filter, boolean recurse) {
- this.filter = filter;
- List<File> files = new ArrayList<File>();
- scanDirectory(new File(dir), files, recurse);
- return files;
- }
-
- /**
- * Implements a tail recursive file scanner
- */
- private void scanDirectory(File dir, List<File> list, boolean recurse) {
- String[] candidates = dir.list(filter);
- if (candidates == null) {
- return;
- }
- for (int i = 0; i < candidates.length; i++) {
- File tmp = new File(dir + FILE_SEP + candidates[i]);
- if (tmp.isDirectory()) {
- if (recurse) {
- scanDirectory(tmp, list, true);
- }
- } else {
- list.add(new File(dir + FILE_SEP + candidates[i]));
- }
- }
- }
-}
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/CPD.java b/sonar-duplications/src/main/java/org/sonar/duplications/cpd/CPD.java
deleted file mode 100644
index 61ec8107555..00000000000
--- a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/CPD.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-package org.sonar.duplications.cpd;
-
-import net.sourceforge.pmd.cpd.*;
-import net.sourceforge.pmd.util.FileFinder;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @deprecated since 2.14, will be removed soon, and in any case should not be used for unit tests in Sonar plugins:
- * instead of using this class for tests, you should test only your implementation of {@link Tokenizer}
- */
-@Deprecated
-public class CPD {
-
- private Map<String, SourceCode> source = new HashMap<String, SourceCode>();
- private CPDListener listener = new CPDNullListener();
- private Tokens tokens = new Tokens();
- private int minimumTileSize;
- private MatchAlgorithm matchAlgorithm;
- private Language language;
- private boolean loadSourceCodeSlices = true;
- private String encoding = System.getProperty("file.encoding");
-
- public CPD(int minimumTileSize, Language language) {
- TokenEntry.clearImages(); // workaround for bug 1947823
- this.minimumTileSize = minimumTileSize;
- this.language = language;
- }
-
- public void setCpdListener(CPDListener cpdListener) {
- this.listener = cpdListener;
- }
-
- public void setEncoding(String encoding) {
- this.encoding = encoding;
- }
-
- public void setLoadSourceCodeSlices(boolean loadSourceCodeSlices) {
- this.loadSourceCodeSlices = loadSourceCodeSlices;
- }
-
- public void go() {
- TokenEntry.clearImages();
- matchAlgorithm = new MatchAlgorithm(source, tokens, minimumTileSize, listener);
- matchAlgorithm.setLoadSourceCodeSlices(loadSourceCodeSlices);
- matchAlgorithm.findMatches();
- }
-
- public Iterator<Match> getMatches() {
- return matchAlgorithm.matches();
- }
-
- public void add(File file) throws IOException {
- add(1, file);
- }
-
- public void addAllInDirectory(String dir) throws IOException {
- addDirectory(dir, false);
- }
-
- public void addRecursively(String dir) throws IOException {
- addDirectory(dir, true);
- }
-
- public void add(List<File> files) throws IOException {
- for (File f : files) {
- add(files.size(), f);
- }
- }
-
- private void addDirectory(String dir, boolean recurse) throws IOException {
- if (!(new File(dir)).exists()) {
- throw new FileNotFoundException("Couldn't find directory " + dir);
- }
- FileFinder finder = new FileFinder();
- add(finder.findFilesFrom(dir, language.getFileFilter(), recurse));
- }
-
- private void add(int fileCount, File file) throws IOException {
- if (!file.getCanonicalPath().equals(new File(file.getAbsolutePath()).getCanonicalPath())) {
- System.out.println("Skipping " + file + " since it appears to be a symlink");
- return;
- }
-
- listener.addedFile(fileCount, file);
- SourceCode sourceCode = new SourceCode(new FileCodeLoaderWithoutCache(file, encoding));
- language.getTokenizer().tokenize(sourceCode, tokens);
- source.put(sourceCode.getFileName(), sourceCode);
- }
-
-}
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/Match.java b/sonar-duplications/src/main/java/org/sonar/duplications/cpd/Match.java
deleted file mode 100644
index 02012a0d6fe..00000000000
--- a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/Match.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-package org.sonar.duplications.cpd;
-
-import net.sourceforge.pmd.cpd.TokenEntry;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.TreeSet;
-
-public class Match implements Comparable<Match> {
-
- public static final String EOL = System.getProperty("line.separator", "\n");
-
- private int tokenCount;
- private int lineCount;
- private Set<TokenEntry> markSet = new TreeSet<TokenEntry>();
- private TokenEntry[] marks = new TokenEntry[2];
- private String code;
- private MatchCode mc;
- private String label;
-
- public static final Comparator<Match> MatchesComparator = new Comparator<Match>() {
-
- public int compare(Match ma, Match mb) {
- return mb.getMarkCount() - ma.getMarkCount();
- }
- };
-
- public static final Comparator<Match> LinesComparator = new Comparator<Match>() {
-
- public int compare(Match ma, Match mb) {
- return mb.getLineCount() - ma.getLineCount();
- }
- };
-
- public static final Comparator<Match> LabelComparator = new Comparator<Match>() {
-
- public int compare(Match ma, Match mb) {
- if (ma.getLabel() == null) {
- return 1;
- }
- if (mb.getLabel() == null) {
- return -1;
- }
- return mb.getLabel().compareTo(ma.getLabel());
- }
- };
-
- public static final Comparator<Match> LengthComparator = new Comparator<Match>() {
-
- public int compare(Match ma, Match mb) {
- return mb.getLineCount() - ma.getLineCount();
- }
- };
-
- public static class MatchCode {
-
- private int first;
- private int second;
-
- public MatchCode() {
- }
-
- public MatchCode(TokenEntry m1, TokenEntry m2) {
- first = m1.getIndex();
- second = m2.getIndex();
- }
-
- @Override
- public int hashCode() {
- return first + 37 * second;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof MatchCode)) {
- return false;
- }
- MatchCode mc = (MatchCode) other;
- return mc.first == first && mc.second == second;
- }
-
- public void setFirst(int first) {
- this.first = first;
- }
-
- public void setSecond(int second) {
- this.second = second;
- }
-
- }
-
- public Match(int tokenCount, TokenEntry first, TokenEntry second) {
- markSet.add(first);
- markSet.add(second);
- marks[0] = first;
- marks[1] = second;
- this.tokenCount = tokenCount;
- }
-
- public int getMarkCount() {
- return markSet.size();
- }
-
- public void setLineCount(int lineCount) {
- this.lineCount = lineCount;
- }
-
- public int getLineCount() {
- return this.lineCount;
- }
-
- public int getTokenCount() {
- return this.tokenCount;
- }
-
- public String getSourceCodeSlice() {
- return this.code;
- }
-
- public void setSourceCodeSlice(String code) {
- this.code = code;
- }
-
- public Iterator<TokenEntry> iterator() {
- return markSet.iterator();
- }
-
- public int compareTo(Match other) {
- int diff = other.getTokenCount() - getTokenCount(); // NOSONAR Bad practice - Class defines compareTo(...) and uses Object.equals()
- if (diff != 0) {
- return diff;
- }
- return other.getFirstMark().getIndex() - getFirstMark().getIndex();
- }
-
- public TokenEntry getFirstMark() {
- return marks[0];
- }
-
- public TokenEntry getSecondMark() {
- return marks[1];
- }
-
- @Override
- public String toString() {
- return "Match: " + EOL + "tokenCount = " + tokenCount + EOL + "marks = " + markSet.size();
- }
-
- public Set<TokenEntry> getMarkSet() {
- return markSet;
- }
-
- public MatchCode getMatchCode() {
- if (mc == null) {
- mc = new MatchCode(marks[0], marks[1]);
- }
- return mc;
- }
-
- public int getEndIndex() {
- return marks[1].getIndex() + getTokenCount() - 1;
- }
-
- public void setMarkSet(Set<TokenEntry> markSet) {
- this.markSet = markSet;
- }
-
- public void setLabel(String aLabel) {
- label = aLabel;
- }
-
- public String getLabel() {
- return label;
- }
-}
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchAlgorithm.java b/sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchAlgorithm.java
deleted file mode 100644
index 0b25bbcfca5..00000000000
--- a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchAlgorithm.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-package org.sonar.duplications.cpd;
-
-import net.sourceforge.pmd.cpd.*;
-
-import java.util.*;
-
-public class MatchAlgorithm {
-
- private static final int MOD = 37;
- private int lastHash;
- private int lastMod = 1;
-
- private List<Match> matches;
- private Map<String, SourceCode> source;
- private Tokens tokens;
- private List<TokenEntry> code;
- private CPDListener cpdListener;
- private int min;
- private boolean loadSourceCodeSlices = true;
-
- public MatchAlgorithm(Map<String, SourceCode> sourceCode, Tokens tokens, int min) {
- this(sourceCode, tokens, min, new CPDNullListener());
- }
-
- public MatchAlgorithm(Map<String, SourceCode> sourceCode, Tokens tokens, int min, CPDListener listener) {
- this.source = sourceCode;
- this.tokens = tokens;
- this.code = tokens.getTokens();
- this.min = min;
- this.cpdListener = listener;
- for (int i = 0; i < min; i++) {
- lastMod *= MOD;
- }
- }
-
- public void setLoadSourceCodeSlices(boolean loadSourceCodeSlices) {
- this.loadSourceCodeSlices = loadSourceCodeSlices;
- }
-
- public void setListener(CPDListener listener) {
- this.cpdListener = listener;
- }
-
- public Iterator<Match> matches() {
- return matches.iterator();
- }
-
- public TokenEntry tokenAt(int offset, TokenEntry m) {
- return code.get(offset + m.getIndex());
- }
-
- public int getMinimumTileSize() {
- return this.min;
- }
-
- public void findMatches() {
- cpdListener.phaseUpdate(CPDListener.HASH);
- Map<TokenEntry, Object> markGroups = hash();
-
- cpdListener.phaseUpdate(CPDListener.MATCH);
- MatchCollector matchCollector = new MatchCollector(this);
- for (Iterator<Object> i = markGroups.values().iterator(); i.hasNext();) {
- Object o = i.next();
- if (o instanceof List) {
- List<TokenEntry> l = (List<TokenEntry>) o;
-
- Collections.reverse(l);
- matchCollector.collect(l);
- }
- i.remove();
- }
- cpdListener.phaseUpdate(CPDListener.GROUPING);
- matches = matchCollector.getMatches();
-
- for (Match match : matches) {
- for (Iterator<TokenEntry> occurrences = match.iterator(); occurrences.hasNext();) {
- TokenEntry mark = occurrences.next();
- match.setLineCount(tokens.getLineCount(mark, match));
- if (loadSourceCodeSlices && !occurrences.hasNext()) {
- int start = mark.getBeginLine();
- int end = start + match.getLineCount() - 1;
- SourceCode sourceCode = source.get(mark.getTokenSrcID());
- match.setSourceCodeSlice(sourceCode.getSlice(start, end));
- }
- }
- }
- cpdListener.phaseUpdate(CPDListener.DONE);
- }
-
- private Map<TokenEntry, Object> hash() {
- Map<TokenEntry, Object> markGroups = new HashMap<TokenEntry, Object>(tokens.size());
- for (int i = code.size() - 1; i >= 0; i--) {
- TokenEntry token = code.get(i);
- if (token != TokenEntry.EOF) {
- int last = tokenAt(min, token).getIdentifier();
- lastHash = MOD * lastHash + token.getIdentifier() - lastMod * last;
- token.setHashCode(lastHash);
- Object o = markGroups.get(token);
-
- // Note that this insertion method is worthwhile since the vast majority
- // markGroup keys will have only one value.
- if (o == null) {
- markGroups.put(token, token);
- } else if (o instanceof TokenEntry) {
- List<TokenEntry> l = new ArrayList<TokenEntry>();
- l.add((TokenEntry) o);
- l.add(token);
- markGroups.put(token, l);
- } else {
- List<TokenEntry> l = (List<TokenEntry>) o;
- l.add(token);
- }
- } else {
- lastHash = 0;
- for (int end = Math.max(0, i - min + 1); i > end; i--) {
- token = code.get(i - 1);
- lastHash = MOD * lastHash + token.getIdentifier();
- if (token == TokenEntry.EOF) {
- break;
- }
- }
- }
- }
- return markGroups;
- }
-
-}
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchCollector.java b/sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchCollector.java
deleted file mode 100644
index f83b183b5b2..00000000000
--- a/sonar-duplications/src/main/java/org/sonar/duplications/cpd/MatchCollector.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-package org.sonar.duplications.cpd;
-
-import net.sourceforge.pmd.cpd.TokenEntry;
-
-import java.util.*;
-
-public class MatchCollector {
-
- private MatchAlgorithm ma;
- private Map<Match.MatchCode, Match> startMap = new HashMap<Match.MatchCode, Match>();
- private Map<String, List<Match>> fileMap = new HashMap<String, List<Match>>();
-
- public MatchCollector(MatchAlgorithm ma) {
- this.ma = ma;
- }
-
- public void collect(List<TokenEntry> marks) {
- // first get a pairwise collection of all maximal matches
- for (int i = 0; i < marks.size() - 1; i++) {
- TokenEntry mark1 = marks.get(i);
- for (int j = i + 1; j < marks.size(); j++) {
- TokenEntry mark2 = marks.get(j);
- int diff = mark1.getIndex() - mark2.getIndex();
- if (-diff < ma.getMinimumTileSize()) {
- continue;
- }
- if (hasPreviousDupe(mark1, mark2)) {
- continue;
- }
-
- // "match too small" check
- int dupes = countDuplicateTokens(mark1, mark2);
- if (dupes < ma.getMinimumTileSize()) {
- continue;
- }
- // is it still too close together
- if (diff + dupes >= 1) {
- continue;
- }
- determineMatch(mark1, mark2, dupes);
- }
- }
- }
-
- @SuppressWarnings("PMD.CompareObjectsWithEquals")
- public List<Match> getMatches() {
- List<Match> matchList = new ArrayList<Match>(startMap.values());
- Collections.sort(matchList);
- Set<Match.MatchCode> matchSet = new HashSet<Match.MatchCode>();
- Match.MatchCode matchCode = new Match.MatchCode();
- for (int i = matchList.size(); i > 1; i--) {
- Match match1 = matchList.get(i - 1);
- TokenEntry mark1 = match1.getMarkSet().iterator().next();
- matchSet.clear();
- matchSet.add(match1.getMatchCode());
- for (int j = i - 1; j > 0; j--) {
- Match match2 = matchList.get(j - 1);
- if (match1.getTokenCount() != match2.getTokenCount()) {
- break;
- }
- TokenEntry mark2 = null;
- for (Iterator<TokenEntry> iter = match2.getMarkSet().iterator(); iter.hasNext();) {
- mark2 = iter.next();
- if (mark2 != mark1) {
- break;
- }
- }
- int dupes = countDuplicateTokens(mark1, mark2);
- if (dupes < match1.getTokenCount()) {
- break;
- }
- matchSet.add(match2.getMatchCode());
- match1.getMarkSet().addAll(match2.getMarkSet());
- matchList.remove(i - 2);
- i--;
- }
- if (matchSet.size() == 1) {
- continue;
- }
- // prune the mark set
- Set<TokenEntry> pruned = match1.getMarkSet();
- boolean done = false;
- ArrayList<TokenEntry> a1 = new ArrayList<TokenEntry>(match1.getMarkSet());
- Collections.sort(a1);
- for (int outer = 0; outer < a1.size() - 1 && !done; outer++) {
- TokenEntry cmark1 = a1.get(outer);
- for (int inner = outer + 1; inner < a1.size() && !done; inner++) {
- TokenEntry cmark2 = a1.get(inner);
- matchCode.setFirst(cmark1.getIndex());
- matchCode.setSecond(cmark2.getIndex());
- if (!matchSet.contains(matchCode)) {
- if (pruned.size() > 2) {
- pruned.remove(cmark2);
- }
- if (pruned.size() == 2) {
- done = true;
- }
- }
- }
- }
- }
- return matchList;
- }
-
- /**
- * A greedy algorithm for determining non-overlapping matches
- */
- private void determineMatch(TokenEntry mark1, TokenEntry mark2, int dupes) {
- Match match = new Match(dupes, mark1, mark2);
- String fileKey = mark1.getTokenSrcID() + mark2.getTokenSrcID();
- List<Match> pairMatches = fileMap.get(fileKey);
- if (pairMatches == null) {
- pairMatches = new ArrayList<Match>();
- fileMap.put(fileKey, pairMatches);
- }
- boolean add = true;
- for (int i = 0; i < pairMatches.size(); i++) {
- Match other = pairMatches.get(i);
- if (other.getFirstMark().getIndex() + other.getTokenCount() - mark1.getIndex() > 0) {
- boolean ordered = other.getSecondMark().getIndex() - mark2.getIndex() < 0;
- if ((ordered && (other.getEndIndex() - mark2.getIndex() > 0))
- || (!ordered && (match.getEndIndex() - other.getSecondMark().getIndex()) > 0)) {
- if (other.getTokenCount() >= match.getTokenCount()) {
- add = false;
- break;
- } else {
- pairMatches.remove(i);
- startMap.remove(other.getMatchCode());
- }
- }
- }
- }
- if (add) {
- pairMatches.add(match);
- startMap.put(match.getMatchCode(), match);
- }
- }
-
- private boolean hasPreviousDupe(TokenEntry mark1, TokenEntry mark2) {
- if (mark1.getIndex() == 0) {
- return false;
- }
- return !matchEnded(ma.tokenAt(-1, mark1), ma.tokenAt(-1, mark2));
- }
-
- private int countDuplicateTokens(TokenEntry mark1, TokenEntry mark2) {
- int index = 0;
- while (!matchEnded(ma.tokenAt(index, mark1), ma.tokenAt(index, mark2))) {
- index++;
- }
- return index;
- }
-
- private boolean matchEnded(TokenEntry token1, TokenEntry token2) {
- return token1.getIdentifier() != token2.getIdentifier() || token1 == TokenEntry.EOF || token2 == TokenEntry.EOF;
- }
-}
diff --git a/sonar-duplications/src/test/java/org/sonar/duplications/cpd/CPDTest.java b/sonar-duplications/src/test/java/org/sonar/duplications/cpd/CPDTest.java
deleted file mode 100644
index c7133c4387a..00000000000
--- a/sonar-duplications/src/test/java/org/sonar/duplications/cpd/CPDTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2012 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar 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.
- *
- * Sonar 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 Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-
-package org.sonar.duplications.cpd;
-
-import net.sourceforge.pmd.cpd.AbstractLanguage;
-import net.sourceforge.pmd.cpd.JavaTokenizer;
-import net.sourceforge.pmd.cpd.TokenEntry;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.nullValue;
-import static org.junit.Assert.assertThat;
-
-public class CPDTest {
-
- @Test
- public void testSetLoadSourceCodeSlicesToFalse() throws IOException {
- TokenEntry.clearImages();
- AbstractLanguage cpdLanguage = new AbstractLanguage(new JavaTokenizer()) {
- };
- CPD cpd = new CPD(20, cpdLanguage);
- cpd.setEncoding(Charset.defaultCharset().name());
- cpd.setLoadSourceCodeSlices(false);
- cpd.add(new File("test-resources/org/sonar/duplications/cpd/CPDTest/CPDFile1.java"));
- cpd.add(new File("test-resources/org/sonar/duplications/cpd/CPDTest/CPDFile2.java"));
- cpd.go();
-
- List<Match> matches = getMatches(cpd);
- assertThat(matches.size(), is(1));
-
- org.sonar.duplications.cpd.Match match = matches.get(0);
- assertThat(match.getLineCount(), is(26));
- assertThat(match.getFirstMark().getBeginLine(), is(16));
- assertThat(match.getSourceCodeSlice(), is(nullValue()));
- assertThat(match.getTokenCount(), is(116));
- }
-
- @Test
- public void testDuplicationOnSameFile() throws IOException {
- TokenEntry.clearImages();
- AbstractLanguage cpdLanguage = new AbstractLanguage(new JavaTokenizer()) {
- };
- CPD cpd = new CPD(20, cpdLanguage);
- cpd.setEncoding(Charset.defaultCharset().name());
- cpd.setLoadSourceCodeSlices(false);
- cpd.add(new File("test-resources/org/sonar/duplications/cpd/CPDTest/CPDFile3.java"));
- cpd.go();
-
- List<Match> matches = getMatches(cpd);
- assertThat(matches.size(), is(1));
-
- org.sonar.duplications.cpd.Match match = matches.get(0);
- assertThat(match.getLineCount(), is(16));
- assertThat(match.getFirstMark().getBeginLine(), is(29));
- assertThat(match.getSourceCodeSlice(), is(nullValue()));
- assertThat(match.getTokenCount(), is(160));
- }
-
- private List<Match> getMatches(CPD cpd) {
- List<Match> matches = new ArrayList<org.sonar.duplications.cpd.Match>();
- Iterator<Match> matchesIter = cpd.getMatches();
- while (matchesIter.hasNext()) {
- matches.add(matchesIter.next());
- }
- return matches;
- }
-
-}