diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreASTHelpers.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreASTHelpers.java index 86251762219..1659478d324 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreASTHelpers.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreASTHelpers.java @@ -1,32 +1,34 @@ package tech.picnic.errorprone.bugpatterns.util; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableList.toImmutableList; import com.google.common.collect.ImmutableList; import com.google.errorprone.VisitorState; import com.sun.source.tree.ClassTree; import com.sun.source.tree.MethodTree; -import com.sun.source.tree.Tree; /** - * A set of helper methods for working with the AST. + * A collection of helper methods for working with the AST. * - *

These helper methods are additions to the ones from {@link + *

These methods are additions to the ones found in {@link * com.google.errorprone.util.ASTHelpers}. */ public final class MoreASTHelpers { private MoreASTHelpers() {} /** - * Finds methods with the given name in the enclosing class. + * Finds methods with the specified name in given the {@link VisitorState}'s current enclosing + * class. * * @param methodName The method name to search for. - * @param state A {@link VisitorState} describing the context in which the given {@link Tree} is - * to be found. + * @param state The {@link VisitorState} from which to derive the enclosing class of interest. * @return The {@link MethodTree}s of the methods with the given name in the enclosing class. */ - public static ImmutableList findMethods(String methodName, VisitorState state) { - return state.findEnclosing(ClassTree.class).getMembers().stream() + public static ImmutableList findMethods(CharSequence methodName, VisitorState state) { + ClassTree clazz = state.findEnclosing(ClassTree.class); + checkArgument(clazz != null, "Visited node is not enclosed by a class"); + return clazz.getMembers().stream() .filter(MethodTree.class::isInstance) .map(MethodTree.class::cast) .filter(method -> method.getName().contentEquals(methodName)) @@ -34,14 +36,14 @@ public static ImmutableList findMethods(String methodName, VisitorSt } /** - * Determines if there are any methods with the given name in the enclosing class. + * Determines whether there are any methods with the specified name in given the {@link + * VisitorState}'s current enclosing class. * * @param methodName The method name to search for. - * @param state A {@link VisitorState} describing the context in which the given {@link Tree} is - * to be found. + * @param state The {@link VisitorState} from which to derive the enclosing class of interest. * @return Whether there are any methods with the given name in the enclosing class. */ - public static boolean isMethodInEnclosingClass(String methodName, VisitorState state) { + public static boolean isMethodInEnclosingClass(CharSequence methodName, VisitorState state) { return !findMethods(methodName, state).isEmpty(); } } diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreJUnitMatchers.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreJUnitMatchers.java index 732a9454535..276b1c00a6d 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreJUnitMatchers.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreJUnitMatchers.java @@ -1,27 +1,26 @@ package tech.picnic.errorprone.bugpatterns.util; +import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE; import static com.google.errorprone.matchers.Matchers.annotations; import static com.google.errorprone.matchers.Matchers.anyOf; import static com.google.errorprone.matchers.Matchers.isType; import static tech.picnic.errorprone.bugpatterns.util.MoreMatchers.hasMetaAnnotation; -import com.google.common.collect.Iterables; +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.matchers.AnnotationMatcherUtils; import com.google.errorprone.matchers.Matcher; import com.google.errorprone.matchers.MultiMatcher; import com.google.errorprone.util.ASTHelpers; import com.sun.source.tree.AnnotationTree; -import com.sun.source.tree.AssignmentTree; import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.MethodTree; -import com.sun.tools.javac.code.Type; -import java.util.Optional; -import javax.lang.model.type.TypeKind; +import com.sun.source.tree.NewArrayTree; /** - * A set of JUnit-specific helper methods and {@link Matcher Matchers}. + * A collection of JUnit-specific helper methods and {@link Matcher}s. * - *

These helper methods are additions to the ones from {@link + *

These constants and methods are additions to the ones found in {@link * com.google.errorprone.matchers.JUnitMatchers}. */ public final class MoreJUnitMatchers { @@ -32,7 +31,6 @@ public final class MoreJUnitMatchers { anyOf( isType("org.junit.jupiter.api.Test"), hasMetaAnnotation("org.junit.jupiter.api.TestTemplate"))); - /** Matches JUnit setup and teardown methods. */ public static final MultiMatcher SETUP_OR_TEARDOWN_METHOD = annotations( @@ -42,7 +40,6 @@ public final class MoreJUnitMatchers { isType("org.junit.jupiter.api.AfterEach"), isType("org.junit.jupiter.api.BeforeAll"), isType("org.junit.jupiter.api.BeforeEach"))); - /** * Matches methods that have a {@link org.junit.jupiter.params.provider.MethodSource} annotation. */ @@ -52,22 +49,25 @@ public final class MoreJUnitMatchers { private MoreJUnitMatchers() {} /** - * Extracts the name of the JUnit factory method from a {@link + * Returns the names of the JUnit value factory methods specified by the given {@link * org.junit.jupiter.params.provider.MethodSource} annotation. * - * @param methodSourceAnnotation The {@link org.junit.jupiter.params.provider.MethodSource} - * annotation to extract a method name from. - * @return The name of the factory method referred to in the annotation. Alternatively, {@link - * Optional#empty()} if there is more than one. + * @param methodSourceAnnotation The annotation from which to extract value factory method names. + * @return One or more value factory names. */ - public static Optional extractSingleFactoryMethodName( - AnnotationTree methodSourceAnnotation) { - ExpressionTree attributeExpression = - ((AssignmentTree) Iterables.getOnlyElement(methodSourceAnnotation.getArguments())) - .getExpression(); - Type attributeType = ASTHelpers.getType(attributeExpression); - return attributeType.getKind() == TypeKind.ARRAY - ? Optional.empty() - : Optional.of(attributeType.stringValue()); + static ImmutableSet getMethodSourceFactoryNames( + AnnotationTree methodSourceAnnotation, MethodTree method) { + ExpressionTree value = AnnotationMatcherUtils.getArgument(methodSourceAnnotation, "value"); + + if (!(value instanceof NewArrayTree)) { + return ImmutableSet.of(ASTHelpers.constValue(value, String.class)); + } + + NewArrayTree arrayTree = (NewArrayTree) value; + return arrayTree.getInitializers().isEmpty() + ? ImmutableSet.of(method.getName().toString()) + : arrayTree.getInitializers().stream() + .map(name -> ASTHelpers.constValue(name, String.class)) + .collect(toImmutableSet()); } } diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchers.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchers.java index ad835aa23dd..49748d9127c 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchers.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchers.java @@ -8,24 +8,27 @@ import com.sun.tools.javac.code.Symbol; /** - * A collection of methods to enhance the use of {@link Matcher}s. + * A collection of general-purpose {@link Matcher}s. * - *

These methods are additions to the ones from {@link Matchers}. + *

These methods are additions to the ones found in {@link Matchers}. */ public final class MoreMatchers { private MoreMatchers() {} /** - * Determines whether a tree has a meta annotation of the given class name. This includes - * annotations inherited from superclasses due to {@link java.lang.annotation.Inherited}. + * Returns a {@link Matcher} that determines whether a given tree has a meta annotation of the + * specified type. * - * @param The type of the tree. - * @param annotationClass The binary class name of the annotation (e.g. " - * org.jspecify.nullness.Nullable", or "some.package.OuterClassName$InnerClassName") + *

This includes annotations inherited from superclasses due to {@link + * java.lang.annotation.Inherited}. + * + * @param The type of tree to match against. + * @param annotationType The binary type name of the annotation (e.g. + * "org.jspecify.nullness.Nullable", or "some.package.OuterClassName$InnerClassName") * @return A {@link Matcher} that matches trees with the specified meta annotation. */ - public static Matcher hasMetaAnnotation(String annotationClass) { - TypePredicate typePredicate = hasAnnotation(annotationClass); + public static Matcher hasMetaAnnotation(String annotationType) { + TypePredicate typePredicate = hasAnnotation(annotationType); return (tree, state) -> { Symbol sym = ASTHelpers.getSymbol(tree); return sym != null && typePredicate.apply(sym.type, state);