diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/IncompatibleModifiersChecker.java b/core/src/main/java/com/google/errorprone/bugpatterns/IncompatibleModifiersChecker.java index 0a26c96d506..99dc0a1a48a 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/IncompatibleModifiersChecker.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/IncompatibleModifiersChecker.java @@ -19,12 +19,11 @@ import static com.google.errorprone.BugPattern.LinkType.NONE; import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; import static com.google.errorprone.matchers.Description.NO_MATCH; +import static com.google.errorprone.util.MoreAnnotations.getValue; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.errorprone.BugPattern; import com.google.errorprone.VisitorState; -import com.google.errorprone.annotations.IncompatibleModifiers; import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher; import com.google.errorprone.fixes.SuggestedFixes; import com.google.errorprone.matchers.Description; @@ -32,8 +31,16 @@ import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.ModifiersTree; import com.sun.source.tree.Tree; +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.Symbol; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; +import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Modifier; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.SimpleAnnotationValueVisitor8; /** @author sgoldfeder@google.com (Steven Goldfeder) */ @BugPattern( @@ -45,15 +52,28 @@ severity = ERROR) public class IncompatibleModifiersChecker extends BugChecker implements AnnotationTreeMatcher { + private static final String INCOMPATIBLE_MODIFIERS = + "com.google.errorprone.annotations.IncompatibleModifiers"; + @Override public Description matchAnnotation(AnnotationTree tree, VisitorState state) { - IncompatibleModifiers annotation = ASTHelpers.getAnnotation(tree, IncompatibleModifiers.class); + Symbol sym = ASTHelpers.getSymbol(tree); + if (sym == null) { + return NO_MATCH; + } + Attribute.Compound annotation = + sym.getRawAttributes().stream() + .filter(a -> a.type.tsym.getQualifiedName().contentEquals(INCOMPATIBLE_MODIFIERS)) + .findAny() + .orElse(null); if (annotation == null) { return NO_MATCH; } - ImmutableSet incompatibleModifiers = ImmutableSet.copyOf(annotation.value()); + Set incompatibleModifiers = new LinkedHashSet<>(); + getValue(annotation, "value").ifPresent(a -> getModifiers(incompatibleModifiers, a)); + getValue(annotation, "modifier").ifPresent(a -> getModifiers(incompatibleModifiers, a)); if (incompatibleModifiers.isEmpty()) { - return Description.NO_MATCH; + return NO_MATCH; } Tree parent = state.getPath().getParentPath().getLeaf(); @@ -83,4 +103,21 @@ public Description matchAnnotation(AnnotationTree tree, VisitorState state) { .setMessage(message) .build(); } + + private static void getModifiers(Collection modifiers, Attribute attribute) { + class Visitor extends SimpleAnnotationValueVisitor8 { + @Override + public Void visitEnumConstant(VariableElement c, Void unused) { + modifiers.add(Modifier.valueOf(c.getSimpleName().toString())); + return null; + } + + @Override + public Void visitArray(List vals, Void unused) { + vals.forEach(val -> val.accept(this, null)); + return null; + } + } + attribute.accept(new Visitor(), null); + } } diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/RequiredModifiersChecker.java b/core/src/main/java/com/google/errorprone/bugpatterns/RequiredModifiersChecker.java index cc59e688889..66fc60ff2cf 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/RequiredModifiersChecker.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/RequiredModifiersChecker.java @@ -18,12 +18,12 @@ import static com.google.errorprone.BugPattern.LinkType.NONE; import static com.google.errorprone.BugPattern.SeverityLevel.ERROR; +import static com.google.errorprone.matchers.Description.NO_MATCH; +import static com.google.errorprone.util.MoreAnnotations.getValue; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.errorprone.BugPattern; import com.google.errorprone.VisitorState; -import com.google.errorprone.annotations.RequiredModifiers; import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher; import com.google.errorprone.fixes.SuggestedFixes; import com.google.errorprone.matchers.Description; @@ -31,8 +31,16 @@ import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.ModifiersTree; import com.sun.source.tree.Tree; +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.Symbol; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; +import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Modifier; +import javax.lang.model.element.VariableElement; +import javax.lang.model.util.SimpleAnnotationValueVisitor8; /** @author sgoldfeder@google.com (Steven Goldfeder) */ @BugPattern( @@ -46,28 +54,40 @@ public class RequiredModifiersChecker extends BugChecker implements AnnotationTr private static final String MESSAGE_TEMPLATE = "%s has specified that it must be used together with the following modifiers: %s"; + private static final String REQUIRED_MODIFIERS = + "com.google.errorprone.annotations.RequiredModifiers"; @Override public Description matchAnnotation(AnnotationTree tree, VisitorState state) { - RequiredModifiers annotation = ASTHelpers.getAnnotation(tree, RequiredModifiers.class); + Symbol sym = ASTHelpers.getSymbol(tree); + if (sym == null) { + return NO_MATCH; + } + Attribute.Compound annotation = + sym.getRawAttributes().stream() + .filter(a -> a.type.tsym.getQualifiedName().contentEquals(REQUIRED_MODIFIERS)) + .findAny() + .orElse(null); if (annotation == null) { - return Description.NO_MATCH; + return NO_MATCH; } - Set requiredModifiers = ImmutableSet.copyOf(annotation.value()); + Set requiredModifiers = new LinkedHashSet<>(); + getValue(annotation, "value").ifPresent(a -> getModifiers(requiredModifiers, a)); + getValue(annotation, "modifier").ifPresent(a -> getModifiers(requiredModifiers, a)); if (requiredModifiers.isEmpty()) { - return Description.NO_MATCH; + return NO_MATCH; } Tree parent = state.getPath().getParentPath().getLeaf(); if (!(parent instanceof ModifiersTree)) { // e.g. An annotated package name - return Description.NO_MATCH; + return NO_MATCH; } Set missing = Sets.difference(requiredModifiers, ((ModifiersTree) parent).getFlags()); if (missing.isEmpty()) { - return Description.NO_MATCH; + return NO_MATCH; } String annotationName = ASTHelpers.getAnnotationName(tree); @@ -86,4 +106,21 @@ public Description matchAnnotation(AnnotationTree tree, VisitorState state) { .setMessage(customMessage) .build(); } + + private static void getModifiers(Collection modifiers, Attribute attribute) { + class Visitor extends SimpleAnnotationValueVisitor8 { + @Override + public Void visitEnumConstant(VariableElement c, Void unused) { + modifiers.add(Modifier.valueOf(c.getSimpleName().toString())); + return null; + } + + @Override + public Void visitArray(List vals, Void unused) { + vals.forEach(val -> val.accept(this, null)); + return null; + } + } + attribute.accept(new Visitor(), null); + } }