[java] Allow CPD suppression through comments
This commit is contained in:
@ -127,7 +127,7 @@ public class JavaTokenizer implements Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
public void skipPackageAndImport(Token currentToken) {
|
||||
private void skipPackageAndImport(Token currentToken) {
|
||||
if (currentToken.kind == JavaParserConstants.PACKAGE || currentToken.kind == JavaParserConstants.IMPORT) {
|
||||
discardingKeywords = true;
|
||||
} else if (discardingKeywords && currentToken.kind == JavaParserConstants.SEMICOLON) {
|
||||
@ -135,7 +135,7 @@ public class JavaTokenizer implements Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
public void skipSemicolon(Token currentToken) {
|
||||
private void skipSemicolon(Token currentToken) {
|
||||
if (currentToken.kind == JavaParserConstants.SEMICOLON) {
|
||||
discardingSemicolon = true;
|
||||
} else if (discardingSemicolon && currentToken.kind != JavaParserConstants.SEMICOLON) {
|
||||
@ -143,7 +143,21 @@ public class JavaTokenizer implements Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
public void skipCPDSuppression(Token currentToken) {
|
||||
private void skipCPDSuppression(Token currentToken) {
|
||||
// Check if a comment is altering the suppression state
|
||||
Token st = currentToken.specialToken;
|
||||
while (st != null) {
|
||||
if (st.image.contains("CPD-OFF")) {
|
||||
discardingSuppressing = true;
|
||||
break;
|
||||
}
|
||||
if (st.image.contains("CPD-ON")) {
|
||||
discardingSuppressing = false;
|
||||
break;
|
||||
}
|
||||
st = st.specialToken;
|
||||
}
|
||||
|
||||
// if processing an annotation, look for a CPD-START or CPD-END
|
||||
if (isAnnotation) {
|
||||
if (!discardingSuppressing && currentToken.kind == JavaParserConstants.STRING_LITERAL
|
||||
@ -156,7 +170,7 @@ public class JavaTokenizer implements Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
public void skipAnnotations() {
|
||||
private void skipAnnotations() {
|
||||
if (!discardingAnnotations && isAnnotation) {
|
||||
discardingAnnotations = true;
|
||||
} else if (discardingAnnotations && !isAnnotation) {
|
||||
@ -170,7 +184,7 @@ public class JavaTokenizer implements Tokenizer {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void detectAnnotations(Token currentToken) {
|
||||
private void detectAnnotations(Token currentToken) {
|
||||
if (isAnnotation && nextTokenEndsAnnotation) {
|
||||
isAnnotation = false;
|
||||
nextTokenEndsAnnotation = false;
|
||||
|
@ -87,11 +87,6 @@ public class JavaTokensTokenizerTest {
|
||||
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();
|
||||
@ -117,6 +112,55 @@ public class JavaTokensTokenizerTest {
|
||||
assertEquals(6, tokens.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreBetweenSpecialComments() throws IOException {
|
||||
JavaTokenizer t = new JavaTokenizer();
|
||||
t.setIgnoreAnnotations(false);
|
||||
SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader("package foo.bar.baz;" + PMD.EOL
|
||||
+ "// CPD-OFF" + PMD.EOL + "// CPD-OFF" + PMD.EOL
|
||||
+ "@ MyAnnotation (\"ugh\")" + PMD.EOL + "@NamedQueries({" + PMD.EOL + "@NamedQuery(" + PMD.EOL + ")})"
|
||||
+ PMD.EOL + "public class Foo {" + "// CPD-ON" + PMD.EOL
|
||||
+ "}"
|
||||
));
|
||||
Tokens tokens = new Tokens();
|
||||
t.tokenize(sourceCode, tokens);
|
||||
TokenEntry.getEOF();
|
||||
assertEquals(2, tokens.size()); // 2 tokens: "}" + EOF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreBetweenSpecialCommentsMultiple() throws IOException {
|
||||
JavaTokenizer t = new JavaTokenizer();
|
||||
t.setIgnoreAnnotations(false);
|
||||
SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader("package foo.bar.baz;" + PMD.EOL
|
||||
+ "// CPD-OFF" + PMD.EOL + "// another irrelevant comment" + PMD.EOL
|
||||
+ "@ MyAnnotation (\"ugh\")" + PMD.EOL + "@NamedQueries({" + PMD.EOL + "@NamedQuery(" + PMD.EOL + ")})"
|
||||
+ PMD.EOL + "public class Foo {" + "// CPD-ON" + PMD.EOL
|
||||
+ "}"
|
||||
));
|
||||
Tokens tokens = new Tokens();
|
||||
t.tokenize(sourceCode, tokens);
|
||||
TokenEntry.getEOF();
|
||||
assertEquals(2, tokens.size()); // 2 tokens: "}" + EOF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreBetweenSpecialCommentsMultiline() throws IOException {
|
||||
JavaTokenizer t = new JavaTokenizer();
|
||||
t.setIgnoreAnnotations(false);
|
||||
SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader("package foo.bar.baz;" + PMD.EOL
|
||||
+ "/* " + PMD.EOL + " * CPD-OFF" + PMD.EOL + "*/" + PMD.EOL
|
||||
+ "@ MyAnnotation (\"ugh\")" + PMD.EOL + "@NamedQueries({" + PMD.EOL + "@NamedQuery(" + PMD.EOL + ")})"
|
||||
+ PMD.EOL + "public class Foo {" + PMD.EOL
|
||||
+ "/* " + PMD.EOL + " * CPD-ON" + PMD.EOL + "*/" + PMD.EOL
|
||||
+ "}"
|
||||
));
|
||||
Tokens tokens = new Tokens();
|
||||
t.tokenize(sourceCode, tokens);
|
||||
TokenEntry.getEOF();
|
||||
assertEquals(2, tokens.size()); // 2 tokens: "}" + EOF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreBetweenSpecialAnnotation() throws IOException {
|
||||
JavaTokenizer t = new JavaTokenizer();
|
||||
|
@ -443,9 +443,33 @@ Here's a [screenshot](../images/screenshot_cpd.png) of CPD after running on the
|
||||
|
||||
## Suppression
|
||||
|
||||
By adding the annotations **@SuppressWarnings("CPD-START")** and **@SuppressWarnings("CPD-END")**
|
||||
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.
|
||||
Arbitrary blocks of code can be ignored through comments on **Java** by including the keywords `CPD-OFF` and `CPD-ON`.
|
||||
|
||||
public Object someParameterizedFactoryMethod(int x) throws Exception {
|
||||
// some unignored code
|
||||
|
||||
// tell cpd to start ignoring code - CPD-OFF
|
||||
|
||||
// mission critical code, manually loop unroll
|
||||
goDoSomethingAwesome(x + x / 2);
|
||||
goDoSomethingAwesome(x + x / 2);
|
||||
goDoSomethingAwesome(x + x / 2);
|
||||
goDoSomethingAwesome(x + x / 2);
|
||||
goDoSomethingAwesome(x + x / 2);
|
||||
goDoSomethingAwesome(x + x / 2);
|
||||
|
||||
// resume CPD analysis - CPD-ON
|
||||
|
||||
// further code will *not* be ignored
|
||||
}
|
||||
|
||||
|
||||
Additionally, **Java** allows to toggle suppression by adding the annotations
|
||||
**`@SuppressWarnings("CPD-START")`** and **`@SuppressWarnings("CPD-END")`**
|
||||
all code within will be ignored by CPD.
|
||||
|
||||
This approach however, is limited to the locations were `@SuppressWarnings` is accepted.
|
||||
It's legacy and the new comment's based approch should be favored.
|
||||
|
||||
//enable suppression
|
||||
@SuppressWarnings("CPD-START")
|
||||
@ -457,3 +481,7 @@ This provides the ability to ignore sections of source code, such as switch/case
|
||||
public void nextMethod() {
|
||||
}
|
||||
|
||||
|
||||
Other languages currently have no support to suppress CPD reports. In the future,
|
||||
the comment based approach will be extended to those of them that can support it.
|
||||
|
||||
|
Reference in New Issue
Block a user