Skip to content

Commit

Permalink
Create ASTHelpersSuggestions
Browse files Browse the repository at this point in the history
to recommend wrapper APIs that work around crashes.

PiperOrigin-RevId: 469617698
  • Loading branch information
cushon authored and Error Prone Team committed Aug 24, 2022
1 parent ece3b63 commit 91b4f56
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2022 The Error Prone Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.errorprone.bugpatterns;

import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
import static com.google.errorprone.matchers.Description.NO_MATCH;
import static com.google.errorprone.matchers.method.MethodMatchers.instanceMethod;
import static com.google.errorprone.util.ASTHelpers.getReceiver;
import static com.google.errorprone.util.ASTHelpers.getSymbol;
import static com.google.errorprone.util.ASTHelpers.isSameType;

import com.google.common.collect.ImmutableMap;
import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.suppliers.Supplier;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Type;

/** A BugPattern; see the summary */
@BugPattern(summary = "Prefer ASTHelpers instead of calling this API directly", severity = WARNING)
public class ASTHelpersSuggestions extends BugChecker implements MethodInvocationTreeMatcher {

private static final Matcher<ExpressionTree> SYMBOL =
instanceMethod()
.onExactClass("com.sun.tools.javac.code.Symbol")
.namedAnyOf("isLocal", "packge", "isStatic");

private static final Matcher<ExpressionTree> SCOPE =
instanceMethod().onDescendantOf("com.sun.tools.javac.code.Scope");

private static final ImmutableMap<String, String> NAMES =
ImmutableMap.of(
"packge", "enclosingPackage",
"isLocal", "isDirectlyOrIndirectlyLocal");

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
ExpressionTree receiver = getReceiver(tree);
if (receiver == null) {
return NO_MATCH;
}
if (SYMBOL.matches(tree, state)) {
MethodSymbol sym = getSymbol(tree);
String name = sym.getSimpleName().toString();
name = NAMES.getOrDefault(name, name);
return describeMatch(
tree,
SuggestedFix.builder()
.addStaticImport("com.google.errorprone.util.ASTHelpers." + name)
.prefixWith(tree, name + "(")
.replace(state.getEndPosition(receiver), state.getEndPosition(tree), ")")
.build());
}
if (SCOPE.matches(tree, state)) {
MethodSymbol sym = getSymbol(tree);
Type filter = COM_SUN_TOOLS_JAVAC_UTIL_FILTER.get(state);
Type predicate = JAVA_UTIL_FUNCTION_PREDICATE.get(state);
if (sym.getParameters().stream()
.anyMatch(
p ->
isSameType(filter, p.asType(), state)
|| isSameType(predicate, p.asType(), state))) {
return describeMatch(
tree,
SuggestedFix.builder()
.addStaticImport("com.google.errorprone.util.ASTHelpers.scope")
.prefixWith(receiver, "scope(")
.postfixWith(receiver, ")")
.build());
}
}
return NO_MATCH;
}

private static final Supplier<Type> COM_SUN_TOOLS_JAVAC_UTIL_FILTER =
VisitorState.memoize(state -> state.getTypeFromString("com.sun.tools.javac.util.Filter"));

private static final Supplier<Type> JAVA_UTIL_FUNCTION_PREDICATE =
VisitorState.memoize(state -> state.getTypeFromString("java.util.function.Predicate"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import com.google.errorprone.BugCheckerInfo;
import com.google.errorprone.bugpatterns.ASTHelpersSuggestions;
import com.google.errorprone.bugpatterns.AlreadyChecked;
import com.google.errorprone.bugpatterns.AlwaysThrows;
import com.google.errorprone.bugpatterns.AmbiguousMethodReference;
Expand Down Expand Up @@ -783,6 +784,7 @@ public static ScannerSupplier errorChecks() {
public static final ImmutableSet<BugCheckerInfo> ENABLED_WARNINGS =
getSuppliers(
// keep-sorted start
ASTHelpersSuggestions.class,
AlmostJavadoc.class,
AlreadyChecked.class,
AmbiguousMethodReference.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2022 The Error Prone Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.errorprone.bugpatterns;

import com.google.errorprone.BugCheckerRefactoringTestHelper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class ASTHelpersSuggestionsTest {
private final BugCheckerRefactoringTestHelper testHelper =
BugCheckerRefactoringTestHelper.newInstance(ASTHelpersSuggestions.class, getClass());

@Test
public void positive() {
testHelper
.addInputLines(
"Test.java",
"import com.sun.tools.javac.code.Symbol;",
"class Test {",
" void f(Symbol s) {",
" s.isStatic();",
" s.packge();",
" s.members().anyMatch(x -> x.isStatic());",
" }",
"}")
.addOutputLines(
"Test.java",
"import static com.google.errorprone.util.ASTHelpers.enclosingPackage;",
"import static com.google.errorprone.util.ASTHelpers.isStatic;",
"import static com.google.errorprone.util.ASTHelpers.scope;",
"import com.sun.tools.javac.code.Symbol;",
"class Test {",
" void f(Symbol s) {",
" isStatic(s);",
" enclosingPackage(s);",
" scope(s.members()).anyMatch(x -> isStatic(x));",
" }",
"}")
.addModules(
"jdk.compiler/com.sun.tools.javac.code", "jdk.compiler/com.sun.tools.javac.util")
.doTest();
}
}

0 comments on commit 91b4f56

Please sign in to comment.