Merge branch 'pull-request-25'
This commit is contained in:
@ -67,6 +67,9 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
@Parameter(names = "--ignore-annotations", description = "Ignore language annotations when comparing text", required = false)
|
||||
private boolean ignoreAnnotations;
|
||||
|
||||
@Parameter(names = "--ignore-usings", description = "Ignore using directives in C#", required = false)
|
||||
private boolean ignoreUsings;
|
||||
|
||||
@Parameter(names = "--skip-lexical-errors", description = "Skip files which can't be tokenized due to invalid characters instead of aborting CPD", required = false)
|
||||
private boolean skipLexicalErrors = false;
|
||||
|
||||
@ -227,6 +230,11 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
} else {
|
||||
properties.remove(Tokenizer.IGNORE_ANNOTATIONS);
|
||||
}
|
||||
if (configuration.isIgnoreUsings()) {
|
||||
properties.setProperty(Tokenizer.IGNORE_USINGS, "true");
|
||||
} else {
|
||||
properties.remove(Tokenizer.IGNORE_USINGS);
|
||||
}
|
||||
properties.setProperty(Tokenizer.OPTION_SKIP_BLOCKS, Boolean.toString(!configuration.isNoSkipBlocks()));
|
||||
properties.setProperty(Tokenizer.OPTION_SKIP_BLOCKS_PATTERN, configuration.getSkipBlocksPattern());
|
||||
configuration.getLanguage().setProperties(properties);
|
||||
@ -338,6 +346,14 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
this.ignoreAnnotations = ignoreAnnotations;
|
||||
}
|
||||
|
||||
public boolean isIgnoreUsings() {
|
||||
return ignoreUsings;
|
||||
}
|
||||
|
||||
public void setIgnoreUsings(boolean ignoreUsings) {
|
||||
this.ignoreUsings = ignoreUsings;
|
||||
}
|
||||
|
||||
public boolean isSkipLexicalErrors() {
|
||||
return skipLexicalErrors;
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public class CPDTask extends Task {
|
||||
private boolean ignoreLiterals;
|
||||
private boolean ignoreIdentifiers;
|
||||
private boolean ignoreAnnotations;
|
||||
private boolean ignoreUsings;
|
||||
private boolean skipLexicalErrors;
|
||||
private boolean skipDuplicateFiles;
|
||||
private boolean skipBlocks = true;
|
||||
@ -104,6 +105,9 @@ public class CPDTask extends Task {
|
||||
if (ignoreAnnotations) {
|
||||
p.setProperty(Tokenizer.IGNORE_ANNOTATIONS, "true");
|
||||
}
|
||||
if (ignoreUsings) {
|
||||
p.setProperty(Tokenizer.IGNORE_USINGS, "true");
|
||||
}
|
||||
p.setProperty(Tokenizer.OPTION_SKIP_BLOCKS, Boolean.toString(skipBlocks));
|
||||
p.setProperty(Tokenizer.OPTION_SKIP_BLOCKS_PATTERN, skipBlocksPattern);
|
||||
return LanguageFactory.createLanguage(language, p);
|
||||
@ -188,6 +192,10 @@ public class CPDTask extends Task {
|
||||
this.ignoreAnnotations = value;
|
||||
}
|
||||
|
||||
public void setIgnoreUsings(boolean value) {
|
||||
this.ignoreUsings = value;
|
||||
}
|
||||
|
||||
public void setSkipLexicalErrors(boolean skipLexicalErrors) {
|
||||
this.skipLexicalErrors = skipLexicalErrors;
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ public class GUI implements CPDListener {
|
||||
public boolean canIgnoreIdentifiers() { return false; }
|
||||
public boolean canIgnoreLiterals() { return false; }
|
||||
public boolean canIgnoreAnnotations() { return false; }
|
||||
public boolean canIgnoreUsings() { return false; }
|
||||
public abstract String[] extensions();
|
||||
}
|
||||
|
||||
@ -121,6 +122,10 @@ public class GUI implements CPDListener {
|
||||
public boolean canIgnoreLiterals() {
|
||||
return "java".equals(terseName);
|
||||
}
|
||||
@Override
|
||||
public boolean canIgnoreUsings() {
|
||||
return "cs".equals(terseName);
|
||||
}
|
||||
};
|
||||
}
|
||||
LANGUAGE_SETS[index][0] = "by extension...";
|
||||
@ -277,6 +282,7 @@ public class GUI implements CPDListener {
|
||||
private JCheckBox ignoreIdentifiersCheckbox = new JCheckBox("", false);
|
||||
private JCheckBox ignoreLiteralsCheckbox = new JCheckBox("", false);
|
||||
private JCheckBox ignoreAnnotationsCheckbox = new JCheckBox("", false);
|
||||
private JCheckBox ignoreUsingsCheckbox = new JCheckBox("", false);
|
||||
private JComboBox languageBox = new JComboBox();
|
||||
private JTextField extensionField = new JTextField();
|
||||
private JLabel extensionLabel = new JLabel("Extension:", SwingConstants.RIGHT);
|
||||
@ -362,6 +368,7 @@ public class GUI implements CPDListener {
|
||||
ignoreIdentifiersCheckbox.setEnabled(current.canIgnoreIdentifiers());
|
||||
ignoreLiteralsCheckbox.setEnabled(current.canIgnoreLiterals());
|
||||
ignoreAnnotationsCheckbox.setEnabled(current.canIgnoreAnnotations());
|
||||
ignoreUsingsCheckbox.setEnabled(current.canIgnoreUsings());
|
||||
extensionField.setText(current.extensions()[0]);
|
||||
boolean enableExtension = current.extensions()[0].length() == 0;
|
||||
extensionField.setEnabled(enableExtension);
|
||||
@ -414,6 +421,13 @@ public class GUI implements CPDListener {
|
||||
helper.nextRow();
|
||||
helper.addLabel("Ignore annotations?");
|
||||
helper.add(ignoreAnnotationsCheckbox);
|
||||
helper.addLabel("");
|
||||
helper.addLabel("");
|
||||
helper.nextRow();
|
||||
|
||||
helper.nextRow();
|
||||
helper.addLabel("Ignore usings?");
|
||||
helper.add(ignoreUsingsCheckbox);
|
||||
helper.add(goButton);
|
||||
helper.add(cxButton);
|
||||
helper.nextRow();
|
||||
@ -590,6 +604,7 @@ public class GUI implements CPDListener {
|
||||
config.setIgnoreIdentifiers(ignoreIdentifiersCheckbox.isSelected());
|
||||
config.setIgnoreLiterals(ignoreLiteralsCheckbox.isSelected());
|
||||
config.setIgnoreAnnotations(ignoreAnnotationsCheckbox.isSelected());
|
||||
config.setIgnoreUsings(ignoreUsingsCheckbox.isSelected());
|
||||
p.setProperty(LanguageFactory.EXTENSION, extensionField.getText());
|
||||
|
||||
LanguageConfig conf = languageConfigFor((String)languageBox.getSelectedItem());
|
||||
|
@ -9,6 +9,13 @@ public interface Tokenizer {
|
||||
String IGNORE_LITERALS = "ignore_literals";
|
||||
String IGNORE_IDENTIFIERS = "ignore_identifiers";
|
||||
String IGNORE_ANNOTATIONS = "ignore_annotations";
|
||||
|
||||
/**
|
||||
* Ignore using directives in C#.
|
||||
* The default value is <code>false</code>.
|
||||
*/
|
||||
String IGNORE_USINGS = "ignore_usings";
|
||||
|
||||
/**
|
||||
* Enables or disabled skipping of blocks like a pre-processor.
|
||||
* It is a boolean property.
|
||||
|
@ -3,15 +3,24 @@
|
||||
*/
|
||||
package net.sourceforge.pmd.cpd;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Language implementation for C#
|
||||
*/
|
||||
public class CsLanguage extends AbstractLanguage {
|
||||
|
||||
/**
|
||||
* Creates a new C# Language instance.
|
||||
*/
|
||||
public CsLanguage() {
|
||||
this(System.getProperties());
|
||||
}
|
||||
|
||||
public CsLanguage(Properties properties) {
|
||||
super("C#", "cs", new CsTokenizer(), ".cs");
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
public final void setProperties(Properties properties) {
|
||||
CsTokenizer tokenizer = (CsTokenizer)getTokenizer();
|
||||
tokenizer.setProperties(properties);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@
|
||||
package net.sourceforge.pmd.cpd;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -13,132 +14,152 @@ import org.junit.Test;
|
||||
|
||||
public class CsTokenizerTest {
|
||||
|
||||
private CsTokenizer tokenizer = new CsTokenizer();
|
||||
private CsTokenizer tokenizer;
|
||||
|
||||
private Tokens tokens;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
tokens = new Tokens();
|
||||
TokenEntry.clearImages();
|
||||
tokenizer = new CsTokenizer();
|
||||
tokens = new Tokens();
|
||||
TokenEntry.clearImages();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleClass() {
|
||||
tokenizer.tokenize(toSourceCode("class Foo {}"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
tokenizer.tokenize(toSourceCode("class Foo {}"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleClassDuplicatedTokens() {
|
||||
tokenizer.tokenize(toSourceCode("class Foo { class Foo { } }"), tokens);
|
||||
assertEquals(9, tokens.size());
|
||||
List<TokenEntry> tokenList = tokens.getTokens();
|
||||
assertEquals(tokenList.get(0).getIdentifier(), tokenList.get(3).getIdentifier());
|
||||
assertEquals(tokenList.get(1).getIdentifier(), tokenList.get(4).getIdentifier());
|
||||
assertEquals(tokenList.get(2).getIdentifier(), tokenList.get(5).getIdentifier());
|
||||
assertEquals(tokenList.get(6).getIdentifier(), tokenList.get(7).getIdentifier());
|
||||
tokenizer.tokenize(toSourceCode("class Foo { class Foo { } }"), tokens);
|
||||
assertEquals(9, tokens.size());
|
||||
List<TokenEntry> tokenList = tokens.getTokens();
|
||||
assertEquals(tokenList.get(0).getIdentifier(), tokenList.get(3).getIdentifier());
|
||||
assertEquals(tokenList.get(1).getIdentifier(), tokenList.get(4).getIdentifier());
|
||||
assertEquals(tokenList.get(2).getIdentifier(), tokenList.get(5).getIdentifier());
|
||||
assertEquals(tokenList.get(6).getIdentifier(), tokenList.get(7).getIdentifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleClassMethodMultipleLines() {
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"class Foo {\n"
|
||||
+ " public String foo(int a) {\n"
|
||||
+ " int i = a;\n"
|
||||
+ " return \"x\" + a;\n"
|
||||
+ " }\n"
|
||||
+ "}"), tokens);
|
||||
assertEquals(22, tokens.size());
|
||||
List<TokenEntry> tokenList = tokens.getTokens();
|
||||
assertEquals(1, tokenList.get(0).getBeginLine());
|
||||
assertEquals(2, tokenList.get(4).getBeginLine());
|
||||
assertEquals(3, tokenList.get(11).getBeginLine());
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"class Foo {\n"
|
||||
+ " public String foo(int a) {\n"
|
||||
+ " int i = a;\n"
|
||||
+ " return \"x\" + a;\n"
|
||||
+ " }\n"
|
||||
+ "}"), tokens);
|
||||
assertEquals(22, tokens.size());
|
||||
List<TokenEntry> tokenList = tokens.getTokens();
|
||||
assertEquals(1, tokenList.get(0).getBeginLine());
|
||||
assertEquals(2, tokenList.get(4).getBeginLine());
|
||||
assertEquals(3, tokenList.get(11).getBeginLine());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrings() {
|
||||
tokenizer.tokenize(toSourceCode("String s =\"aaa \\\"b\\n\";"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
tokenizer.tokenize(toSourceCode("String s =\"aaa \\\"b\\n\";"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenString() {
|
||||
tokenizer.tokenize(toSourceCode("String s =\"aaa \\\"b\\"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
tokenizer.tokenize(toSourceCode("String s =\"aaa \\\"b\\"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCommentsIgnored1() {
|
||||
tokenizer.tokenize(toSourceCode("class Foo { /* class * ** X */ }"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
tokenizer.tokenize(toSourceCode("class Foo { /* class * ** X */ }"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommentsIgnored2() {
|
||||
tokenizer.tokenize(toSourceCode("class Foo { // class X /* aaa */ \n }"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
tokenizer.tokenize(toSourceCode("class Foo { // class X /* aaa */ \n }"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommentsIgnored3() {
|
||||
tokenizer.tokenize(toSourceCode("class Foo { /// class X /* aaa */ \n }"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
tokenizer.tokenize(toSourceCode("class Foo { /// class X /* aaa */ \n }"), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoreTokens() {
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"class Foo {\n"
|
||||
+ " void bar() {\n"
|
||||
+ " int a = 1 >> 2; \n"
|
||||
+ " a += 1; \n"
|
||||
+ " a++; \n"
|
||||
+ " a /= 3e2; \n"
|
||||
+ " float f = -3.1; \n"
|
||||
+ " f *= 2; \n"
|
||||
+ " bool b = ! (f == 2.0 || f >= 1.0 && f <= 2.0) \n"
|
||||
+ " }\n"
|
||||
+ "}"
|
||||
), tokens);
|
||||
assertEquals(50, tokens.size());
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"class Foo {\n"
|
||||
+ " void bar() {\n"
|
||||
+ " int a = 1 >> 2; \n"
|
||||
+ " a += 1; \n"
|
||||
+ " a++; \n"
|
||||
+ " a /= 3e2; \n"
|
||||
+ " float f = -3.1; \n"
|
||||
+ " f *= 2; \n"
|
||||
+ " bool b = ! (f == 2.0 || f >= 1.0 && f <= 2.0) \n"
|
||||
+ " }\n"
|
||||
+ "}"
|
||||
), tokens);
|
||||
assertEquals(50, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLineNumberAfterMultilineComment() {
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"/* This is a multiline comment \n"
|
||||
+ " * \n"
|
||||
+ " * Lorem ipsum dolor sit amet, \n"
|
||||
+ " * consectetur adipiscing elit \n"
|
||||
+ " */\n"
|
||||
+ "\n"
|
||||
+ "class Foo {\n"
|
||||
+ "\n"
|
||||
+ "}"
|
||||
), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
assertEquals(7, tokens.getTokens().get(0).getBeginLine());
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"/* This is a multiline comment \n"
|
||||
+ " * \n"
|
||||
+ " * Lorem ipsum dolor sit amet, \n"
|
||||
+ " * consectetur adipiscing elit \n"
|
||||
+ " */\n"
|
||||
+ "\n"
|
||||
+ "class Foo {\n"
|
||||
+ "\n"
|
||||
+ "}"
|
||||
), tokens);
|
||||
assertEquals(5, tokens.size());
|
||||
assertEquals(7, tokens.getTokens().get(0).getBeginLine());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLineNumberAfterMultilineString() {
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"class Foo {\n"
|
||||
+ " void bar() {\n"
|
||||
+ " String query = \n"
|
||||
+ " @\"SELECT foo, bar\n"
|
||||
+ " FROM table \n"
|
||||
+ " WHERE id = 42\"; \n"
|
||||
+ " }\n"
|
||||
+ "}"
|
||||
), tokens);
|
||||
assertEquals(16, tokens.size());
|
||||
assertEquals(8, tokens.getTokens().get(14).getBeginLine());
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"class Foo {\n"
|
||||
+ " void bar() {\n"
|
||||
+ " String query = \n"
|
||||
+ " @\"SELECT foo, bar\n"
|
||||
+ " FROM table \n"
|
||||
+ " WHERE id = 42\"; \n"
|
||||
+ " }\n"
|
||||
+ "}"
|
||||
), tokens);
|
||||
assertEquals(16, tokens.size());
|
||||
assertEquals(8, tokens.getTokens().get(14).getBeginLine());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreUsingDirectives() {
|
||||
tokenizer.setIgnoreUsings(true);
|
||||
tokenizer.tokenize(toSourceCode("using System.Text;\n"), tokens);
|
||||
assertNotEquals("using", tokens.getTokens().get(0).toString());
|
||||
assertEquals(2, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsingStatementsAreNotIgnored() {
|
||||
tokenizer.setIgnoreUsings(true);
|
||||
tokenizer.tokenize(toSourceCode(
|
||||
"using (Font font1 = new Font(\"Arial\", 10.0f)) {\n"
|
||||
+ " byte charset = font1.GdiCharSet;\n"
|
||||
+ "}\n"
|
||||
), tokens);
|
||||
assertEquals("using", tokens.getTokens().get(0).toString());
|
||||
}
|
||||
|
||||
private SourceCode toSourceCode(String source) {
|
||||
return new SourceCode(new SourceCode.StringCodeLoader(source));
|
||||
return new SourceCode(new SourceCode.StringCodeLoader(source));
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
**Feature Request and Improvements:**
|
||||
|
||||
* CPD: New command line parameter `--ignore-usings`: Ignore using directives in C# when comparing text.
|
||||
|
||||
**New/Modified/Deprecated Rules:**
|
||||
|
||||
* Java
|
||||
@ -14,6 +16,7 @@
|
||||
|
||||
**Pull Requests:**
|
||||
|
||||
* [#25](https://github.com/adangel/pmd/pull/25): Added option to exclude C# using directives from CPD analysis
|
||||
* [#72](https://github.com/pmd/pmd/pull/72): Added capability in Java and JSP parser for tracking tokens.
|
||||
* [#73](https://github.com/pmd/pmd/pull/73): Add rule to look for invalid message format in slf4j loggers
|
||||
* [#74](https://github.com/pmd/pmd/pull/74): Fix rendering CommentDefaultAccessModifier description as code
|
||||
|
@ -154,6 +154,12 @@ The options "minimum-tokens" and "files" are the two required options; there are
|
||||
<td>no</td>
|
||||
<td>java</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>--ignore-usings</td>
|
||||
<td>Ignore using directives in C# when comparing text</td>
|
||||
<td>no</td>
|
||||
<td>C#</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>--no-skip-blocks</td>
|
||||
<td>Do not skip code blocks marked with --skip-blocks-pattern (e.g. #if 0 until #endif)</td>
|
||||
@ -339,6 +345,14 @@ Andy Glover wrote an Ant task for CPD; here's how to use it:
|
||||
<td valign="top">java</td>
|
||||
<td valign="top" align="center">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">ignoreUsings</td>
|
||||
<td valign="top">
|
||||
Ignore using directives in C#.
|
||||
</td>
|
||||
<td valign="top">C#</td>
|
||||
<td valign="top" align="center">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">skipDuplicateFiles</td>
|
||||
<td valign="top">
|
||||
|
Reference in New Issue
Block a user