Skip to content

Commit

Permalink
Move matcher to refaster-support
Browse files Browse the repository at this point in the history
  • Loading branch information
oxkitsune authored and Stephan202 committed May 25, 2023
1 parent cedebc9 commit 0dcb8c1
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
import com.google.errorprone.predicates.TypePredicate;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol;

/**
Expand Down Expand Up @@ -37,35 +32,6 @@ public static <T extends AnnotationTree> Matcher<T> hasMetaAnnotation(String ann
};
}

/**
* Returns a {@link Matcher} that determines whether a given {@link ExpressionTree} has type
* arguments.
*
* @param <T> The type of tree to match against.
* @return A {@link Matcher} that matches trees with type arguments.
*/
public static <T extends ExpressionTree> Matcher<T> hasTypeArguments() {
return (tree, state) -> {
switch (tree.getKind()) {
case METHOD_INVOCATION:
return !((MethodInvocationTree) tree).getTypeArguments().isEmpty();
case NEW_CLASS:
NewClassTree classTree = (NewClassTree) tree;
if (!classTree.getTypeArguments().isEmpty()) {
return true;
}

if (classTree.getIdentifier().getKind() != Tree.Kind.PARAMETERIZED_TYPE) {
return false;
}

return !((ParameterizedTypeTree) classTree.getIdentifier()).getTypeArguments().isEmpty();
default:
return false;
}
};
}

// XXX: Consider moving to a `MoreTypePredicates` utility class.
private static TypePredicate hasAnnotation(String annotationClassName) {
return (type, state) -> ASTHelpers.hasAnnotation(type.tsym, annotationClassName, state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,15 @@
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.AnnotationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import org.junit.jupiter.api.Test;

final class MoreMatchersTest {
@Test
void hasMetaAnnotation() {
CompilationTestHelper.newInstance(MetaAnnotationTestMatcher.class, getClass())
CompilationTestHelper.newInstance(TestMatcher.class, getClass())
.addSourceLines(
"A.java",
"import org.junit.jupiter.api.AfterAll;",
Expand Down Expand Up @@ -54,8 +49,7 @@ void hasMetaAnnotation() {

/** A {@link BugChecker} that delegates to {@link MoreMatchers#hasMetaAnnotation(String)} . */
@BugPattern(summary = "Interacts with `MoreMatchers` for testing purposes", severity = ERROR)
public static final class MetaAnnotationTestMatcher extends BugChecker
implements AnnotationTreeMatcher {
public static final class TestMatcher extends BugChecker implements AnnotationTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<AnnotationTree> DELEGATE =
MoreMatchers.hasMetaAnnotation("org.junit.jupiter.api.TestTemplate");
Expand All @@ -65,44 +59,4 @@ public Description matchAnnotation(AnnotationTree tree, VisitorState state) {
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
}
}

@Test
void hasTypeArgumentsMatcher() {
CompilationTestHelper.newInstance(HasTypeArgumentsTestMatcher.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableSet;",
"import java.util.ArrayList;",
"import java.util.List;",
"",
"class A {",
" <E> void foo(E first) {",
" // BUG: Diagnostic contains:",
" ImmutableSet.<E>builder().add(first).build();",
" // BUG: Diagnostic contains:",
" new ImmutableSet.Builder<E>().add(first).build();",
"",
" ImmutableSet<Integer> foo = new ImmutableSet.Builder().add(1).build();",
" List<Integer> bar = new ArrayList<>();",
" }",
"}")
.doTest();
}
/** A {@link BugChecker} that delegates to {@link MoreMatchers#hasTypeArguments()} . */
@BugPattern(summary = "Interacts with `MoreMatchers` for testing purposes", severity = ERROR)
public static final class HasTypeArgumentsTestMatcher extends BugChecker
implements MethodInvocationTreeMatcher, NewClassTreeMatcher {
private static final long serialVersionUID = 1L;
private static final Matcher<ExpressionTree> DELEGATE = MoreMatchers.hasTypeArguments();

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
}

@Override
public Description matchNewClass(NewClassTree tree, VisitorState state) {
return DELEGATE.matches(tree, state) ? describeMatch(tree) : Description.NO_MATCH;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package tech.picnic.errorprone.refaster.matchers;

import com.google.errorprone.VisitorState;
import com.google.errorprone.matchers.Matcher;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.Tree;

/** A matcher of expressions with type arguments. */
public final class HasTypeArguments implements Matcher<ExpressionTree> {
private static final long serialVersionUID = 1L;

/** Instantiates a new {@link HasTypeArguments} instance. */
public HasTypeArguments() {}

@Override
public boolean matches(ExpressionTree tree, VisitorState state) {
switch (tree.getKind()) {
case METHOD_INVOCATION:
return !((MethodInvocationTree) tree).getTypeArguments().isEmpty();
case NEW_CLASS:
NewClassTree classTree = (NewClassTree) tree;
if (!classTree.getTypeArguments().isEmpty()) {
return true;
}

if (classTree.getIdentifier().getKind() != Tree.Kind.PARAMETERIZED_TYPE) {
return false;
}

return !((ParameterizedTypeTree) classTree.getIdentifier()).getTypeArguments().isEmpty();
default:
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package tech.picnic.errorprone.refaster.matchers;

import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;

import com.google.errorprone.BugPattern;
import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.bugpatterns.BugChecker;
import org.junit.jupiter.api.Test;

final class HasTypeArgumentsTest {
@Test
void matches() {
CompilationTestHelper.newInstance(MatcherTestChecker.class, getClass())
.addSourceLines(
"A.java",
"import com.google.common.collect.ImmutableSet;",
"import java.util.ArrayList;",
"import java.util.List;",
"",
"class A {",
" Object negative1() {",
" return alwaysNull();",
" }",
"",
" Object negative2() {",
" return new Object();",
" }",
"",
" List<Integer> negative3() {",
" return new ArrayList<>();",
" }",
"",
" <E> ImmutableSet<E> positive1() {",
" // BUG: Diagnostic contains:",
" return ImmutableSet.<E>builder().build();",
" }",
"",
" <E> ImmutableSet<E> positive2() {",
" // BUG: Diagnostic contains:",
" return new ImmutableSet.Builder<E>().build();",
" }",
"",
" private static <T> T alwaysNull() {",
" return null;",
" }",
"}")
.doTest();
}

/** A {@link BugChecker} that simply delegates to {@link HasTypeArguments}. */
@BugPattern(summary = "Flags expressions matched by `HasTypeArguments`", severity = ERROR)
public static final class MatcherTestChecker extends AbstractMatcherTestChecker {
private static final long serialVersionUID = 1L;

// XXX: This is a false positive reported by Checkstyle. See
// https://github.com/checkstyle/checkstyle/issues2/10161#issuecomment-1242732120.
@SuppressWarnings("RedundantModifier")
public MatcherTestChecker() {
super(new HasTypeArguments());
}
}
}

0 comments on commit 0dcb8c1

Please sign in to comment.