Revert "Revert "Merge branch 'pr-287'""

This reverts commit 63ea1906af.
This commit is contained in:
Juan Martín Sotuyo Dodero
2017-10-05 17:03:57 -03:00
parent 6fc758c21a
commit d5a83ae807
16 changed files with 518 additions and 17 deletions

View File

@ -4,10 +4,20 @@
package net.sourceforge.pmd.lang.apex.ast;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import net.sourceforge.pmd.Rule;
import apex.jorje.semantic.ast.modifier.Annotation;
public class ASTAnnotation extends AbstractApexNode<Annotation> {
private static final Pattern IMAGE_EXTRACTOR = Pattern.compile("value = ([^\\)]*)\\)");
public ASTAnnotation(Annotation annotation) {
super(annotation);
}
@ -15,4 +25,33 @@ public class ASTAnnotation extends AbstractApexNode<Annotation> {
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public String getImage() {
final Matcher m = IMAGE_EXTRACTOR.matcher(node.toString());
if (m.find()) {
return m.group(1);
}
return null;
}
public boolean suppresses(Rule rule) {
final String ruleAnno = "PMD." + rule.getName();
if (hasImageEqualTo("SuppressWarnings")) {
for (ASTAnnotationParameter param : findChildrenOfType(ASTAnnotationParameter.class)) {
String image = param.getImage();
if (image != null) {
Set<String> paramValues = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
paramValues.addAll(Arrays.asList(image.replaceAll("\\s+", "").split(",")));
if (paramValues.contains("PMD") || paramValues.contains(ruleAnno) || paramValues.contains("all")) {
return true;
}
}
}
}
return false;
}
}

View File

@ -4,10 +4,15 @@
package net.sourceforge.pmd.lang.apex.ast;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import apex.jorje.semantic.ast.modifier.AnnotationParameter;
public class ASTAnnotationParameter extends AbstractApexNode<AnnotationParameter> {
private static final Pattern IMAGE_EXTRACTOR = Pattern.compile("value = ([^\\)]*)\\)");
public ASTAnnotationParameter(AnnotationParameter annotationParameter) {
super(annotationParameter);
}
@ -15,4 +20,16 @@ public class ASTAnnotationParameter extends AbstractApexNode<AnnotationParameter
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public String getImage() {
if (node.getValue() != null) {
final Matcher m = IMAGE_EXTRACTOR.matcher(node.getValue().toString());
if (m.find()) {
return m.group(1);
}
}
return null;
}
}

View File

@ -4,9 +4,11 @@
package net.sourceforge.pmd.lang.apex.ast;
import net.sourceforge.pmd.Rule;
import apex.jorje.semantic.ast.member.Field;
public class ASTField extends AbstractApexNode<Field> {
public class ASTField extends AbstractApexNode<Field> implements CanSuppressWarnings {
public ASTField(Field field) {
super(field);
@ -20,4 +22,15 @@ public class ASTField extends AbstractApexNode<Field> {
public String getImage() {
return node.getFieldInfo().getName();
}
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
for (ASTModifierNode modifier : findChildrenOfType(ASTModifierNode.class)) {
for (ASTAnnotation a : modifier.findChildrenOfType(ASTAnnotation.class)) {
if (a.suppresses(rule)) {
return true;
}
}
}
return false;
}
}

View File

@ -4,9 +4,12 @@
package net.sourceforge.pmd.lang.apex.ast;
import net.sourceforge.pmd.Rule;
import apex.jorje.semantic.ast.statement.FieldDeclarationStatements;
public class ASTFieldDeclarationStatements extends AbstractApexNode<FieldDeclarationStatements> {
public class ASTFieldDeclarationStatements extends AbstractApexNode<FieldDeclarationStatements>
implements CanSuppressWarnings {
public ASTFieldDeclarationStatements(FieldDeclarationStatements fieldDeclarationStatements) {
super(fieldDeclarationStatements);
@ -15,4 +18,15 @@ public class ASTFieldDeclarationStatements extends AbstractApexNode<FieldDeclara
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
for (ASTModifierNode modifier : findChildrenOfType(ASTModifierNode.class)) {
for (ASTAnnotation a : modifier.findChildrenOfType(ASTAnnotation.class)) {
if (a.suppresses(rule)) {
return true;
}
}
}
return false;
}
}

View File

@ -4,12 +4,14 @@
package net.sourceforge.pmd.lang.apex.ast;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.lang.apex.metrics.signature.ApexOperationSignature;
import net.sourceforge.pmd.lang.ast.SignedNode;
import apex.jorje.semantic.ast.member.Method;
public class ASTMethod extends AbstractApexNode<Method> implements ApexQualifiableNode, SignedNode<ASTMethod> {
public class ASTMethod extends AbstractApexNode<Method> implements ApexQualifiableNode,
SignedNode<ASTMethod>, CanSuppressWarnings {
public ASTMethod(Method method) {
super(method);
@ -44,7 +46,6 @@ public class ASTMethod extends AbstractApexNode<Method> implements ApexQualifiab
return super.getEndColumn();
}
@Override
public ApexQualifiedName getQualifiedName() {
return ApexQualifiedName.ofMethod(this);
@ -55,4 +56,16 @@ public class ASTMethod extends AbstractApexNode<Method> implements ApexQualifiab
public ApexOperationSignature getSignature() {
return ApexOperationSignature.of(this);
}
@Override
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
for (ASTModifierNode modifier : findChildrenOfType(ASTModifierNode.class)) {
for (ASTAnnotation a : modifier.findChildrenOfType(ASTAnnotation.class)) {
if (a.suppresses(rule)) {
return true;
}
}
}
return false;
}
}

View File

@ -4,9 +4,11 @@
package net.sourceforge.pmd.lang.apex.ast;
import net.sourceforge.pmd.Rule;
import apex.jorje.semantic.ast.member.Parameter;
public class ASTParameter extends AbstractApexNode<Parameter> {
public class ASTParameter extends AbstractApexNode<Parameter> implements CanSuppressWarnings {
public ASTParameter(Parameter parameter) {
super(parameter);
@ -20,4 +22,15 @@ public class ASTParameter extends AbstractApexNode<Parameter> {
public String getImage() {
return node.getName().value;
}
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
for (ASTModifierNode modifier : findChildrenOfType(ASTModifierNode.class)) {
for (ASTAnnotation a : modifier.findChildrenOfType(ASTAnnotation.class)) {
if (a.suppresses(rule)) {
return true;
}
}
}
return false;
}
}

View File

@ -6,14 +6,16 @@ package net.sourceforge.pmd.lang.apex.ast;
import java.lang.reflect.Field;
import net.sourceforge.pmd.Rule;
import apex.jorje.data.ast.Identifier;
import apex.jorje.semantic.ast.compilation.UserClass;
public class ASTUserClass extends ApexRootNode<UserClass> implements ASTUserClassOrInterface<UserClass> {
public class ASTUserClass extends ApexRootNode<UserClass> implements ASTUserClassOrInterface<UserClass>,
CanSuppressWarnings {
private ApexQualifiedName qname;
public ASTUserClass(UserClass userClass) {
super(userClass);
}
@ -37,7 +39,6 @@ public class ASTUserClass extends ApexRootNode<UserClass> implements ASTUserClas
return super.getImage();
}
@Override
public ApexQualifiedName getQualifiedName() {
if (qname == null) {
@ -59,4 +60,16 @@ public class ASTUserClass extends ApexRootNode<UserClass> implements ASTUserClas
public TypeKind getTypeKind() {
return TypeKind.CLASS;
}
@Override
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
for (ASTModifierNode modifier : findChildrenOfType(ASTModifierNode.class)) {
for (ASTAnnotation a : modifier.findChildrenOfType(ASTAnnotation.class)) {
if (a.suppresses(rule)) {
return true;
}
}
}
return false;
}
}

View File

@ -6,10 +6,13 @@ package net.sourceforge.pmd.lang.apex.ast;
import java.lang.reflect.Field;
import net.sourceforge.pmd.Rule;
import apex.jorje.data.ast.Identifier;
import apex.jorje.semantic.ast.compilation.UserInterface;
public class ASTUserInterface extends ApexRootNode<UserInterface> implements ASTUserClassOrInterface<UserInterface> {
public class ASTUserInterface extends ApexRootNode<UserInterface> implements ASTUserClassOrInterface<UserInterface>,
CanSuppressWarnings {
private ApexQualifiedName qname;
@ -34,13 +37,11 @@ public class ASTUserInterface extends ApexRootNode<UserInterface> implements AST
return super.getImage();
}
@Override
public TypeKind getTypeKind() {
return TypeKind.INTERFACE;
}
@Override
public ApexQualifiedName getQualifiedName() {
if (qname == null) {
@ -56,4 +57,16 @@ public class ASTUserInterface extends ApexRootNode<UserInterface> implements AST
return qname;
}
@Override
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
for (ASTModifierNode modifier : findChildrenOfType(ASTModifierNode.class)) {
for (ASTAnnotation a : modifier.findChildrenOfType(ASTAnnotation.class)) {
if (a.suppresses(rule)) {
return true;
}
}
}
return false;
}
}

View File

@ -4,9 +4,11 @@
package net.sourceforge.pmd.lang.apex.ast;
import net.sourceforge.pmd.Rule;
import apex.jorje.semantic.ast.statement.VariableDeclaration;
public class ASTVariableDeclaration extends AbstractApexNode<VariableDeclaration> {
public class ASTVariableDeclaration extends AbstractApexNode<VariableDeclaration> implements CanSuppressWarnings {
public ASTVariableDeclaration(VariableDeclaration variableDeclaration) {
super(variableDeclaration);
@ -20,4 +22,17 @@ public class ASTVariableDeclaration extends AbstractApexNode<VariableDeclaration
public String getImage() {
return node.getLocalInfo().getName();
}
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
ASTVariableDeclarationStatements parent = (ASTVariableDeclarationStatements) jjtGetParent();
for (ASTModifierNode modifier : parent.findChildrenOfType(ASTModifierNode.class)) {
for (ASTAnnotation a : modifier.findChildrenOfType(ASTAnnotation.class)) {
if (a.suppresses(rule)) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,11 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex.ast;
import net.sourceforge.pmd.Rule;
public interface CanSuppressWarnings {
boolean hasSuppressWarningsAnnotationFor(Rule rule);
}

View File

@ -0,0 +1,67 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex.rule;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.apex.ast.CanSuppressWarnings;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
/**
* This is an Apex RuleViolation. It knows how to try to extract the following
* extra information from the violation node:
* <ul>
* <li>Package name</li>
* <li>Class name</li>
* <li>Method name</li>
* <li>Variable name</li>
* <li>Suppression indicator</li>
* </ul>
* @param <T>
*/
public class ApexRuleViolation<T> extends ParametricRuleViolation<Node> {
public ApexRuleViolation(Rule rule, RuleContext ctx, Node node, String message, int beginLine, int endLine) {
this(rule, ctx, node, message);
setLines(beginLine, endLine);
}
public ApexRuleViolation(Rule rule, RuleContext ctx, Node node, String message) {
super(rule, ctx, node, message);
if (node != null) {
if (!suppressed) {
suppressed = isSupressed(node, getRule());
}
}
}
/**
* Check for suppression on this node, on parents, and on contained types
* for ASTCompilationUnit
*
* @param node
*/
public static boolean isSupressed(Node node, Rule rule) {
boolean result = suppresses(node, rule);
if (!result) {
Node parent = node.jjtGetParent();
while (!result && parent != null) {
result = suppresses(parent, rule);
parent = parent.jjtGetParent();
}
}
return result;
}
private static boolean suppresses(final Node node, Rule rule) {
return node instanceof CanSuppressWarnings
&& ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule);
}
}

View File

@ -10,7 +10,6 @@ import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.apex.ast.ApexNode;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory;
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
public final class ApexRuleViolationFactory extends AbstractRuleViolationFactory {
@ -22,11 +21,12 @@ public final class ApexRuleViolationFactory extends AbstractRuleViolationFactory
@SuppressWarnings("rawtypes")
@Override
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) {
return new ParametricRuleViolation<>(rule, ruleContext, (ApexNode) node, message);
return new ApexRuleViolation<>(rule, ruleContext, (ApexNode) node, message);
}
@SuppressWarnings("rawtypes")
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message,
int beginLine, int endLine) {
return null; // FIXME
return new ApexRuleViolation(rule, ruleContext, (ApexNode) node, message, beginLine, endLine);
}
}

View File

@ -0,0 +1,58 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex;
import net.sourceforge.pmd.lang.apex.ast.ASTField;
import net.sourceforge.pmd.lang.apex.ast.ASTParameter;
import net.sourceforge.pmd.lang.apex.ast.ASTUserClass;
import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
/**
* Sample rule that detect any node with an image of "Foo". Used for testing.
*/
public class FooRule extends AbstractApexRule {
public FooRule() {
setMessage("No Foo allowed");
}
@Override
public Object visit(ASTUserClass c, Object ctx) {
if (c.getImage().equalsIgnoreCase("Foo")) {
addViolation(ctx, c);
}
return super.visit(c, ctx);
}
@Override
public Object visit(ASTVariableDeclaration c, Object ctx) {
if (c.getImage().equalsIgnoreCase("Foo")) {
addViolation(ctx, c);
}
return super.visit(c, ctx);
}
@Override
public Object visit(ASTField c, Object ctx) {
if (c.getImage().equalsIgnoreCase("Foo")) {
addViolation(ctx, c);
}
return super.visit(c, ctx);
}
@Override
public Object visit(ASTParameter c, Object ctx) {
if (c.getImage().equalsIgnoreCase("Foo")) {
addViolation(ctx, c);
}
return super.visit(c, ctx);
}
@Override
public String getName() {
return "NoFoo";
}
}

View File

@ -0,0 +1,184 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.apex.ast.ASTUserClass;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
import net.sourceforge.pmd.testframework.RuleTst;
public class SuppressWarningsTest extends RuleTst {
private static class BarRule extends AbstractApexRule {
@Override
public Object visit(ASTUserClass clazz, Object ctx) {
if (clazz.getImage().equalsIgnoreCase("bar")) {
addViolation(ctx, clazz);
}
return super.visit(clazz, ctx);
}
@Override
public String getName() {
return "NoBar";
}
}
@Test
public void testClassLevelSuppression() {
Report rpt = new Report();
runTestFromString(TEST1, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(0, rpt.size());
runTestFromString(TEST2, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(0, rpt.size());
}
@Test
public void testInheritedSuppression() {
Report rpt = new Report();
runTestFromString(TEST3, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(0, rpt.size());
}
@Test
public void testMethodLevelSuppression() {
Report rpt = new Report();
runTestFromString(TEST4, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(1, rpt.size());
}
@Test
public void testConstructorLevelSuppression() {
Report rpt = new Report();
runTestFromString(TEST5, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(0, rpt.size());
}
@Test
public void testFieldLevelSuppression() {
Report rpt = new Report();
runTestFromString(TEST6, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(1, rpt.size());
}
@Test
public void testParameterLevelSuppression() {
Report rpt = new Report();
runTestFromString(TEST7, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(1, rpt.size());
}
@Test
public void testLocalVariableLevelSuppression() {
Report rpt = new Report();
runTestFromString(TEST8, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(1, rpt.size());
}
@Test
public void testSpecificSuppression() {
Report rpt = new Report();
runTestFromString(TEST9, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(1, rpt.size());
}
@Test
public void testSpecificSuppressionMulitpleValues() {
Report rpt = new Report();
runTestFromString(TEST9_MULTIPLE_VALUES, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(0, rpt.size());
}
@Test
public void testNoSuppressionBlank() {
Report rpt = new Report();
runTestFromString(TEST10, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(2, rpt.size());
}
@Test
public void testNoSuppressionSomethingElseS() {
Report rpt = new Report();
runTestFromString(TEST11, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(2, rpt.size());
}
@Test
public void testSuppressAll() {
Report rpt = new Report();
runTestFromString(TEST12, new FooRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(0, rpt.size());
}
@Test
public void testSpecificSuppressionAtTopLevel() {
Report rpt = new Report();
runTestFromString(TEST13, new BarRule(), rpt,
LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getVersion("35"));
assertEquals(0, rpt.size());
}
private static final String TEST1 = "@SuppressWarnings('PMD')" + PMD.EOL + "public class Foo {}";
private static final String TEST2 = "@SuppressWarnings('PMD')" + PMD.EOL + "public class Foo {" + PMD.EOL
+ " void bar() {" + PMD.EOL + " Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST3 = "public class Baz {" + PMD.EOL + " @SuppressWarnings('PMD')" + PMD.EOL
+ " public class Bar {" + PMD.EOL + " void bar() {" + PMD.EOL + " Integer foo;" + PMD.EOL + " }" + PMD.EOL
+ " }" + PMD.EOL + "}";
private static final String TEST4 = "public class Foo {" + PMD.EOL + " @SuppressWarnings('PMD')" + PMD.EOL
+ " void bar() {" + PMD.EOL + " Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST5 = "public class Bar {" + PMD.EOL + " @SuppressWarnings('PMD')" + PMD.EOL
+ " public Bar() {" + PMD.EOL + " Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST6 = "public class Bar {" + PMD.EOL + " @SuppressWarnings('PMD')" + PMD.EOL
+ " Integer foo;" + PMD.EOL + " void bar() {" + PMD.EOL + " Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST7 = "public class Bar {" + PMD.EOL + " Integer foo;" + PMD.EOL
+ " void bar(@SuppressWarnings('PMD') Integer foo) {}" + PMD.EOL + "}";
private static final String TEST8 = "public class Bar {" + PMD.EOL + " Integer foo;" + PMD.EOL + " void bar() {"
+ PMD.EOL + " @SuppressWarnings('PMD') Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST9 = "public class Bar {" + PMD.EOL + " Integer foo;" + PMD.EOL + " void bar() {"
+ PMD.EOL + " @SuppressWarnings('PMD.NoFoo') Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST9_MULTIPLE_VALUES = "@SuppressWarnings('PMD.NoFoo, PMD.NoBar')"
+ PMD.EOL + "public class Bar {" + PMD.EOL + " Integer foo;" + PMD.EOL + " void bar() {" + PMD.EOL
+ " Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST10 = "public class Bar {" + PMD.EOL + " Integer foo;" + PMD.EOL + " void bar() {"
+ PMD.EOL + " @SuppressWarnings('') Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST11 = "public class Bar {" + PMD.EOL + " Integer foo;" + PMD.EOL + " void bar() {"
+ PMD.EOL + " @SuppressWarnings('SomethingElse') Integer foo;" + PMD.EOL + " }" + PMD.EOL + "}";
private static final String TEST12 = "public class Bar {" + PMD.EOL + " @SuppressWarnings('all') Integer foo;"
+ PMD.EOL + "}";
private static final String TEST13 = "@SuppressWarnings('PMD.NoBar')" + PMD.EOL + "public class Bar {" + PMD.EOL
+ "}";
}