Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update IncompatibleModifiersChecker and RequiredModifiersChecker #2355

Merged
merged 1 commit into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
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);
}
}
Original file line number Diff line number Diff line change
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);
}
}