pmd/cpd: adding documentation and switches for suppressing ability and new ignore_annotations switch.
This commit is contained in:
parent
b2f3c070f5
commit
d1dfc93eb4
@ -104,8 +104,9 @@ public class CPD {
|
||||
}
|
||||
|
||||
private static void setSystemProperties(String[] args) {
|
||||
boolean ignoreLiterals = CPDConfiguration.findBooleanSwitch(args, "--ignore-literals"),
|
||||
ignoreIdentifiers = CPDConfiguration.findBooleanSwitch(args, "--ignore-identifiers");
|
||||
boolean ignoreLiterals = CPDConfiguration.findBooleanSwitch(args, "--ignore-literals");
|
||||
boolean ignoreIdentifiers = CPDConfiguration.findBooleanSwitch(args, "--ignore-identifiers");
|
||||
boolean ignoreAnnotations = CPDConfiguration.findBooleanSwitch(args, "--ignore-annotations");
|
||||
Properties properties = System.getProperties();
|
||||
if (ignoreLiterals) {
|
||||
properties.setProperty(JavaTokenizer.IGNORE_LITERALS, "true");
|
||||
@ -113,6 +114,9 @@ public class CPD {
|
||||
if (ignoreIdentifiers) {
|
||||
properties.setProperty(JavaTokenizer.IGNORE_IDENTIFIERS, "true");
|
||||
}
|
||||
if (ignoreAnnotations) {
|
||||
properties.setProperty(JavaTokenizer.IGNORE_ANNOTATIONS, "true");
|
||||
}
|
||||
System.setProperties(properties);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ import java.util.Properties;
|
||||
* <project name="CPDProj" default="main" basedir=".">
|
||||
* <taskdef name="cpd" classname="net.sourceforge.pmd.cpd.CPDTask" />
|
||||
* <target name="main">
|
||||
* <cpd encoding="UTF-16LE" language="java" ignoreIdentifiers="true" ignoreLiterals="true" minimumTokenCount="100" outputFile="c:\cpdrun.txt">
|
||||
* <cpd encoding="UTF-16LE" language="java" ignoreIdentifiers="true" ignoreLiterals="true" ignoreAnnotations="true" minimumTokenCount="100" outputFile="c:\cpdrun.txt">
|
||||
* <fileset dir="/path/to/my/src">
|
||||
* <include name="*.java"/>
|
||||
* </fileset>
|
||||
@ -45,6 +45,7 @@ public class CPDTask extends Task {
|
||||
private int minimumTokenCount;
|
||||
private boolean ignoreLiterals;
|
||||
private boolean ignoreIdentifiers;
|
||||
private boolean ignoreAnnotations;
|
||||
private File outputFile;
|
||||
private String encoding = System.getProperty("file.encoding");
|
||||
private List<FileSet> filesets = new ArrayList<FileSet>();
|
||||
@ -86,6 +87,9 @@ public class CPDTask extends Task {
|
||||
if (ignoreIdentifiers) {
|
||||
p.setProperty(JavaTokenizer.IGNORE_IDENTIFIERS, "true");
|
||||
}
|
||||
if (ignoreAnnotations) {
|
||||
p.setProperty(JavaTokenizer.IGNORE_ANNOTATIONS, "true");
|
||||
}
|
||||
return new LanguageFactory().createLanguage(language, p);
|
||||
}
|
||||
|
||||
@ -157,6 +161,10 @@ public class CPDTask extends Task {
|
||||
this.ignoreIdentifiers = value;
|
||||
}
|
||||
|
||||
public void setIgnoreAnnotations(boolean value) {
|
||||
this.ignoreAnnotations = value;
|
||||
}
|
||||
|
||||
public void setOutputFile(File outputFile) {
|
||||
this.outputFile = outputFile;
|
||||
}
|
||||
|
@ -79,45 +79,42 @@ public class GUI implements CPDListener {
|
||||
{ "CSV (tab)", new Renderer() { public String render(Iterator<Match> items) { return new CSVRenderer('\t').render(items); } } }
|
||||
};
|
||||
|
||||
private interface LanguageConfig {
|
||||
Language languageFor(LanguageFactory lf, Properties p);
|
||||
boolean ignoreLiteralsByDefault();
|
||||
String[] extensions();
|
||||
private static abstract class LanguageConfig {
|
||||
public abstract Language languageFor(LanguageFactory lf, Properties p);
|
||||
public boolean canIgnoreIdentifiers() { return false; }
|
||||
public boolean canIgnoreLiterals() { return false; }
|
||||
public boolean canIgnoreAnnotations() { return false; }
|
||||
public abstract String[] extensions();
|
||||
};
|
||||
|
||||
private static final Object[][] LANGUAGE_SETS = new Object[][] {
|
||||
{"Java", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("java"); }
|
||||
public boolean ignoreLiteralsByDefault() { return true; }
|
||||
public boolean canIgnoreIdentifiers() { return true; }
|
||||
public boolean canIgnoreLiterals() { return true; }
|
||||
public boolean canIgnoreAnnotations() { return true; }
|
||||
public String[] extensions() { return new String[] {".java", ".class" }; }; } },
|
||||
{"JSP", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("jsp"); }
|
||||
public boolean ignoreLiteralsByDefault() { return false; }
|
||||
public String[] extensions() { return new String[] {".jsp" }; }; } },
|
||||
{"C++", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("cpp"); }
|
||||
public boolean ignoreLiteralsByDefault() { return false; }
|
||||
public String[] extensions() { return new String[] {".cpp", ".c" }; }; } },
|
||||
{"Ruby", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("ruby"); }
|
||||
public boolean ignoreLiteralsByDefault() { return false; }
|
||||
public String[] extensions() { return new String[] {".rb" }; }; } },
|
||||
{"Fortran", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("fortran"); }
|
||||
public boolean ignoreLiteralsByDefault() { return false; }
|
||||
public String[] extensions() { return new String[] {".rb" }; }; } },
|
||||
{"by extension...", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.BY_EXTENSION, p); }
|
||||
public boolean ignoreLiteralsByDefault() { return false; }
|
||||
public String[] extensions() { return new String[] {"" }; }; } },
|
||||
{"PHP", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("php"); }
|
||||
public boolean ignoreLiteralsByDefault() { return false; }
|
||||
public String[] extensions() { return new String[] {".php" }; }; } },
|
||||
{"C#", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("cs"); }
|
||||
public boolean ignoreLiteralsByDefault() { return false; }
|
||||
public String[] extensions() { return new String[] {".cs" }; }; } },
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("cs"); }
|
||||
public String[] extensions() { return new String[] {".cs" }; }; } },
|
||||
};
|
||||
|
||||
private static final int DEFAULT_CPD_MINIMUM_LENGTH = 75;
|
||||
@ -258,7 +255,9 @@ public class GUI implements CPDListener {
|
||||
private JProgressBar tokenizingFilesBar = new JProgressBar();
|
||||
private JTextArea resultsTextArea = new JTextArea();
|
||||
private JCheckBox recurseCheckbox = new JCheckBox("", true);
|
||||
private JCheckBox ignoreIdentifiersCheckbox = new JCheckBox("", false);
|
||||
private JCheckBox ignoreLiteralsCheckbox = new JCheckBox("", false);
|
||||
private JCheckBox ignoreAnnotationsCheckbox = new JCheckBox("", false);
|
||||
private JComboBox languageBox = new JComboBox();
|
||||
private JTextField extensionField = new JTextField();
|
||||
private JLabel extensionLabel = new JLabel("Extension:", SwingConstants.RIGHT);
|
||||
@ -341,7 +340,9 @@ public class GUI implements CPDListener {
|
||||
}
|
||||
|
||||
private void adjustLanguageControlsFor(LanguageConfig current) {
|
||||
ignoreLiteralsCheckbox.setEnabled(current.ignoreLiteralsByDefault());
|
||||
ignoreIdentifiersCheckbox.setEnabled(current.canIgnoreIdentifiers());
|
||||
ignoreLiteralsCheckbox.setEnabled(current.canIgnoreLiterals());
|
||||
ignoreAnnotationsCheckbox.setEnabled(current.canIgnoreAnnotations());
|
||||
extensionField.setText(current.extensions()[0]);
|
||||
boolean enableExtension = current.extensions()[0].length() == 0;
|
||||
extensionField.setEnabled(enableExtension);
|
||||
@ -378,8 +379,22 @@ public class GUI implements CPDListener {
|
||||
helper.add(extensionField);
|
||||
|
||||
helper.nextRow();
|
||||
helper.addLabel("Ignore literals and identifiers?");
|
||||
helper.addLabel("Ignore literals?");
|
||||
helper.add(ignoreLiteralsCheckbox);
|
||||
helper.addLabel("");
|
||||
helper.addLabel("");
|
||||
helper.nextRow();
|
||||
|
||||
helper.nextRow();
|
||||
helper.addLabel("Ignore identifiers?");
|
||||
helper.add(ignoreIdentifiersCheckbox);
|
||||
helper.addLabel("");
|
||||
helper.addLabel("");
|
||||
helper.nextRow();
|
||||
|
||||
helper.nextRow();
|
||||
helper.addLabel("Ignore annotations?");
|
||||
helper.add(ignoreAnnotationsCheckbox);
|
||||
helper.add(goButton);
|
||||
helper.add(cxButton);
|
||||
helper.nextRow();
|
||||
@ -550,7 +565,9 @@ public class GUI implements CPDListener {
|
||||
setProgressControls(true);
|
||||
|
||||
Properties p = new Properties();
|
||||
p.setProperty(JavaTokenizer.IGNORE_IDENTIFIERS, String.valueOf(ignoreIdentifiersCheckbox.isSelected()));
|
||||
p.setProperty(JavaTokenizer.IGNORE_LITERALS, String.valueOf(ignoreLiteralsCheckbox.isSelected()));
|
||||
p.setProperty(JavaTokenizer.IGNORE_ANNOTATIONS, String.valueOf(ignoreAnnotationsCheckbox.isSelected()));
|
||||
p.setProperty(LanguageFactory.EXTENSION, extensionField.getText());
|
||||
LanguageConfig conf = languageConfigFor((String)languageBox.getSelectedItem());
|
||||
Language language = conf.languageFor(new LanguageFactory(), p);
|
||||
|
@ -74,6 +74,11 @@
|
||||
<td valign="top">Similar to <code>ignoreLiterals</code> but for identifiers; i.e., variable names, methods names, and so forth; defaults to <code>false</code>.</td>
|
||||
<td valign="top" align="center">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">ignoreAnnotations</td>
|
||||
<td valign="top">Ignore annotations. More and more modern frameworks use annotations on classes and methods, which can be very redundant and trigger CPD matches. With J2EE (CDI, Transaction Handling, etc) and Spring (everything) annotations become very redundant. Often classes or methods have the same 5-6 lines of annotations. This causes false positives.</td>
|
||||
<td valign="top" align="center">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">language</td>
|
||||
<td valign="top">Flag to select the appropriate language (e.g. <code>cpp</code>, <code>cs</code> <code>java</code>, <code>php</code>, <code>ruby</code>, and <code>ecmascript</code>); defaults to <code>java</code>.</td>
|
||||
@ -136,10 +141,26 @@ $ java net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /usr/local/java/
|
||||
$ java -Xmx512m net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files /usr/local/java/src/java
|
||||
</source>
|
||||
|
||||
</subsection>
|
||||
<p>Please note that if CPD detects duplicated source code, it will exit with status 4 (since 5.0). This behavior has been introduced to ease CPD integration into scrips or
|
||||
hook, such as SVN hooks.</p>
|
||||
</subsection>
|
||||
|
||||
<subsection name="Suppression">
|
||||
By adding the annotations <strong>@SuppressWarnings("CPD-START")</strong> and <strong>@SuppressWarnings("CPD-END")</strong>
|
||||
all code within will be ignored by CPD - thus you can avoid false positivs.
|
||||
This provides the ability to ignore sections of source code, such as switch/case statements or parameterized factories.
|
||||
<source>
|
||||
//enable suppression
|
||||
@SuppressWarnings("CPD-START")
|
||||
public Object someParameterizedFactoryMethod(int x) throws Exception {
|
||||
// any code here will be ignored for the duplication detection
|
||||
}
|
||||
//disable suppression
|
||||
@SuppressWarnings("CPD-END)
|
||||
public void nextMethod() {
|
||||
}
|
||||
</source>
|
||||
</subsection>
|
||||
</section>
|
||||
</body>
|
||||
</document>
|
||||
|
@ -78,26 +78,32 @@ public class JavaTokensTokenizerTest {
|
||||
assertEquals(6, tokens.size());
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testIgnoreComments() throws Throwable {
|
||||
// JavaTokenizer t = new JavaTokenizer();
|
||||
// t.setIgnoreAnnotations(false);
|
||||
// SourceCode sourceCode = new SourceCode(
|
||||
// new SourceCode.StringCodeLoader(
|
||||
// "package foo.bar.baz;" +
|
||||
// PMD.EOL +
|
||||
// "/*****" +
|
||||
// PMD.EOL +
|
||||
// " * ugh" +
|
||||
// PMD.EOL +
|
||||
// " *****/" +
|
||||
// PMD.EOL +
|
||||
// "public class Foo {}"
|
||||
// ));
|
||||
// Tokens tokens = new Tokens();
|
||||
// t.tokenize(sourceCode, tokens);
|
||||
// assertEquals(6, tokens.size());
|
||||
// }
|
||||
/**
|
||||
* Comments are discarded already by the Java parser.
|
||||
* It would be nice, however, to use simple comments like
|
||||
* //CPD-START or //CPD-END
|
||||
* to enable discard-mode of CPD
|
||||
*/
|
||||
@Test
|
||||
public void testIgnoreComments() {
|
||||
JavaTokenizer t = new JavaTokenizer();
|
||||
t.setIgnoreAnnotations(false);
|
||||
SourceCode sourceCode = new SourceCode(
|
||||
new SourceCode.StringCodeLoader(
|
||||
"package foo.bar.baz;" +
|
||||
PMD.EOL +
|
||||
"/*****" +
|
||||
PMD.EOL +
|
||||
" * ugh" +
|
||||
PMD.EOL +
|
||||
" *****/" +
|
||||
PMD.EOL +
|
||||
"public class Foo {}"
|
||||
));
|
||||
Tokens tokens = new Tokens();
|
||||
t.tokenize(sourceCode, tokens);
|
||||
assertEquals(6, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiscardOneLineAnnotationWithParams() throws Throwable {
|
||||
|
Loading…
x
Reference in New Issue
Block a user