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

Improve AbstractMatcherTestChecker #599

Merged
merged 1 commit into from
May 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.TypeCastTree;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreeScanner;
import org.jspecify.annotations.Nullable;

Expand All @@ -31,18 +34,27 @@ abstract class AbstractMatcherTestChecker extends BugChecker implements Compilat

@Override
public Description matchCompilationUnit(CompilationUnitTree compilationUnit, VisitorState state) {
new TreeScanner<@Nullable Void, @Nullable Void>() {
new TreeScanner<@Nullable Void, TreePath>() {
@Override
public @Nullable Void scan(Tree tree, @Nullable Void unused) {
if (tree instanceof ExpressionTree && delegate.matches((ExpressionTree) tree, state)) {
state.reportMatch(describeMatch(tree));
public @Nullable Void scan(@Nullable Tree tree, TreePath treePath) {
if (tree == null) {
return null;
}

return super.scan(tree, unused);
TreePath path = new TreePath(treePath, tree);
if (tree instanceof ExpressionTree) {
ExpressionTree expressionTree = (ExpressionTree) tree;
if (!isMethodSelect(expressionTree, path)
&& delegate.matches(expressionTree, state.withPath(path))) {
state.reportMatch(describeMatch(tree));
}
}

return super.scan(tree, path);
}

@Override
public @Nullable Void visitImport(ImportTree node, @Nullable Void unused) {
public @Nullable Void visitImport(ImportTree tree, TreePath path) {
/*
* We're not interested in matching import statements. While components of these
* can be `ExpressionTree`s, they will never be matched by Refaster.
Expand All @@ -51,15 +63,42 @@ public Description matchCompilationUnit(CompilationUnitTree compilationUnit, Vis
}

@Override
public @Nullable Void visitMethod(MethodTree node, @Nullable Void unused) {
public @Nullable Void visitMethod(MethodTree tree, TreePath path) {
/*
* We're not interested in matching e.g. parameter and return type declarations. While these
* can be `ExpressionTree`s, they will never be matched by Refaster.
*/
return scan(node.getBody(), unused);
return scan(tree.getBody(), new TreePath(path, tree));
}

@Override
public @Nullable Void visitTypeCast(TypeCastTree tree, TreePath path) {
/*
* We're not interested in matching the parenthesized type subtree that is part of a type
* cast expression. While such trees can be `ExpressionTree`s, they will never be matched by
* Refaster.
*/
return scan(tree.getExpression(), new TreePath(path, tree));
}
}.scan(compilationUnit, null);
}.scan(compilationUnit, state.getPath());

return Description.NO_MATCH;
}

/**
* Tells whether the given {@link ExpressionTree} is the {@link
* MethodInvocationTree#getMethodSelect() method select} portion of a method invocation.
*
* <p>Such {@link ExpressionTree}s will never be matched by Refaster.
*/
private static boolean isMethodSelect(ExpressionTree tree, TreePath path) {
TreePath parentPath = path.getParentPath();
if (parentPath == null) {
return false;
}

Tree parentTree = parentPath.getLeaf();
return parentTree instanceof MethodInvocationTree
&& ((MethodInvocationTree) parentTree).getMethodSelect().equals(tree);
}
}