google / error-prone

Catch common Java mistakes as compile-time errors

Home Page:https://errorprone.info

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: make `ASTHelpers#getSymbol(MethodInvocationTree)` throw rather than return `null`

msridhar opened this issue · comments

Currently, ASTHelpers#getSymbol(MethodInvocationTree) can return null if there are errors in the AST:

/** Gets the symbol for a method invocation. */
@Nullable
public static MethodSymbol getSymbol(MethodInvocationTree tree) {
Symbol sym = ASTHelpers.getSymbol(tree.getMethodSelect());
if (!(sym instanceof MethodSymbol)) {
// Defensive. Would only occur if there are errors in the AST.
return null;
}
return (MethodSymbol) sym;
}

But does Error Prone even run when there are AST errors? If not, it would be helpful for nullability checking if this method just threw an (unchecked) exception in this case rather than returning null. I am working on running NullAway on itself (uber/NullAway#560), and one of the most common "fixes" I had to do was to add castToNonNull around calls to ASTHelpers.getSymbol(MethodInvocationTree) because we have just been assuming it will never return null (and have never observed a case I know of where it did so).

A quick test suggests that this may somehow break on https://github.com/google/error-prone/blob/master/core/src/test/java/com/google/errorprone/refaster/testdata/template/WildcardUnificationTemplate.java:

1) freeIdentWildcardCapture(com.google.errorprone.refaster.TemplateIntegrationTest)
java.lang.RuntimeException: Error analysing: containsAllOf
  at com.google.errorprone.refaster.RefasterRuleBuilderScanner.visitMethod(RefasterRuleBuilderScanner.java:148)
  at com.google.errorprone.refaster.RefasterRuleBuilderScanner.visitMethod(RefasterRuleBuilderScanner.java:58)
  at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:898)
  at jdk.compiler/com.sun.source.util.SimpleTreeVisitor.visit(SimpleTreeVisitor.java:80)
  at jdk.compiler/com.sun.source.util.SimpleTreeVisitor.visit(SimpleTreeVisitor.java:94)
  at com.google.errorprone.refaster.RefasterRuleBuilderScanner.extractRules(RefasterRuleBuilderScanner.java:97)
  at com.google.errorprone.refaster.TemplateIntegrationTest.extractRefasterRule(TemplateIntegrationTest.java:61)
  at com.google.errorprone.refaster.TemplateIntegrationTest.runTest(TemplateIntegrationTest.java:84)
  at com.google.errorprone.refaster.TemplateIntegrationTest.freeIdentWildcardCapture(TemplateIntegrationTest.java:219)
  ... 27 trimmed
Caused by: java.lang.IllegalArgumentException
  at com.google.errorprone.util.ASTHelpers.getSymbol(ASTHelpers.java:317)
  at com.google.errorprone.util.ASTHelpers.getSymbol(ASTHelpers.java:263)
  at com.google.errorprone.refaster.UTemplater.placeholder(UTemplater.java:724)
  at com.google.errorprone.refaster.UTemplater.visitExpressionStatement(UTemplater.java:730)
  at com.google.errorprone.refaster.UTemplater.visitExpressionStatement(UTemplater.java:129)
  at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1460)
  at com.google.errorprone.refaster.UTemplater.template(UTemplater.java:682)
  at com.google.errorprone.refaster.UTemplater.createTemplate(UTemplater.java:182)
  at com.google.errorprone.refaster.RefasterRuleBuilderScanner.visitMethod(RefasterRuleBuilderScanner.java:135)
  ... 36 more

I'm not sure what to make of that.

...perhaps because IterableSubject.containsAllIn hasn't existed since 2019 :)

Possibly WildcardUnificationTemplate hasn't been exercising what we intended since then.

Anyway, I have more tests running on the actual depot, so we'll see how that goes.

Awesome thanks for looking @cpovirk!

BTW getSymbol(MemberReferenceTree) and getSymbol(NewClassTree) also currently return @Nullable, and if this change works out for the MethodInvocationTree case, maybe those can be changed as well.

Thanks. My in-progress test includes the MemberReferenceTree overload, which I'd noticed, but not the NewClassTree one, which I had not. Depending on how that goes, I'll see about adding NewClassTree or giving up entirely :)

I think this is worth revisiting and will be interested to see what Chris' testing turns up.

But does Error Prone even run when there are AST errors?

It isn't supposed to, the relevant logic is here:

if (JavaCompiler.instance(context).errorCount() > errorProneErrors) {
return;
}

The other thing we'll want to watch out for here is that we run Error Prone in a couple of environments where the compilation class path has been 'optimized' using heuristics to make it shorter. Sometimes having Error Prone try to handle missing symbols allows reporting some diagnostics when there's missing information, especially if javac doesn't need to load those symbols itself.