Skip to content

Commit

Permalink
Suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephan202 committed Nov 13, 2022
1 parent 687923d commit 6bcc3bd
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,47 +1,49 @@
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.
*
* <p>These helper methods are additions to the ones from {@link
* <p>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<MethodTree> findMethods(String methodName, VisitorState state) {
return state.findEnclosing(ClassTree.class).getMembers().stream()
public static ImmutableList<MethodTree> 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))
.collect(toImmutableList());
}

/**
* 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();
}
}
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>These helper methods are additions to the ones from {@link
* <p>These constants and methods are additions to the ones found in {@link
* com.google.errorprone.matchers.JUnitMatchers}.
*/
public final class MoreJUnitMatchers {
Expand All @@ -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<MethodTree, AnnotationTree> SETUP_OR_TEARDOWN_METHOD =
annotations(
Expand All @@ -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.
*/
Expand All @@ -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<String> 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<String> 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>These methods are additions to the ones from {@link Matchers}.
* <p>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 <T> 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")
* <p>This includes annotations inherited from superclasses due to {@link
* java.lang.annotation.Inherited}.
*
* @param <T> 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 <T extends Tree> Matcher<T> hasMetaAnnotation(String annotationClass) {
TypePredicate typePredicate = hasAnnotation(annotationClass);
public static <T extends Tree> Matcher<T> hasMetaAnnotation(String annotationType) {
TypePredicate typePredicate = hasAnnotation(annotationType);
return (tree, state) -> {
Symbol sym = ASTHelpers.getSymbol(tree);
return sym != null && typePredicate.apply(sym.type, state);
Expand Down

0 comments on commit 6bcc3bd

Please sign in to comment.