Skip to content

Commit

Permalink
Update IncompatibleModifiersChecker and RequiredModifiersChecker
Browse files Browse the repository at this point in the history
in preparation for introducing a new `Modifier` enum.

#2122

PiperOrigin-RevId: 375545113
  • Loading branch information
cushon authored and Error Prone Team committed May 24, 2021
1 parent 94d41df commit 5213327
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 13 deletions.
Expand Up @@ -19,21 +19,28 @@
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;
import com.google.errorprone.util.ASTHelpers;
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(
Expand All @@ -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<Modifier> incompatibleModifiers = ImmutableSet.copyOf(annotation.value());
Set<Modifier> 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();
Expand Down Expand Up @@ -83,4 +103,21 @@ public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
.setMessage(message)
.build();
}

private static void getModifiers(Collection<Modifier> modifiers, Attribute attribute) {
class Visitor extends SimpleAnnotationValueVisitor8<Void, Void> {
@Override
public Void visitEnumConstant(VariableElement c, Void unused) {
modifiers.add(Modifier.valueOf(c.getSimpleName().toString()));
return null;
}

@Override
public Void visitArray(List<? extends AnnotationValue> vals, Void unused) {
vals.forEach(val -> val.accept(this, null));
return null;
}
}
attribute.accept(new Visitor(), null);
}
}
Expand Up @@ -18,21 +18,29 @@

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;
import com.google.errorprone.util.ASTHelpers;
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(
Expand All @@ -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<Modifier> requiredModifiers = ImmutableSet.copyOf(annotation.value());
Set<Modifier> 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<Modifier> missing = Sets.difference(requiredModifiers, ((ModifiersTree) parent).getFlags());

if (missing.isEmpty()) {
return Description.NO_MATCH;
return NO_MATCH;
}

String annotationName = ASTHelpers.getAnnotationName(tree);
Expand All @@ -86,4 +106,21 @@ public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
.setMessage(customMessage)
.build();
}

private static void getModifiers(Collection<Modifier> modifiers, Attribute attribute) {
class Visitor extends SimpleAnnotationValueVisitor8<Void, Void> {
@Override
public Void visitEnumConstant(VariableElement c, Void unused) {
modifiers.add(Modifier.valueOf(c.getSimpleName().toString()));
return null;
}

@Override
public Void visitArray(List<? extends AnnotationValue> vals, Void unused) {
vals.forEach(val -> val.accept(this, null));
return null;
}
}
attribute.accept(new Visitor(), null);
}
}

0 comments on commit 5213327

Please sign in to comment.