uber / NullAway

A tool to help eliminate NullPointerExceptions (NPEs) in your Java code with low build-time overhead
MIT License
3.62k stars 291 forks source link

Support switch expressions #289

Closed michaelhixson closed 2 years ago

michaelhixson commented 5 years ago

Support switch expressions, which are a preview feature in Java 12.

Currently, if I use a switch expression in my code, NullAway will throw an error during compilation. Removing NullAway from my <annotationProcessorPaths> and removing the NullAway-related compiler arguments makes the error go away.

I've seen two kinds of errors so far.

Error 1: "java.lang.AssertionError: case visitor is implemented in SwitchBuilder"

Source code:

public static void main(String[] args) {
  String s = switch (args.length) {
    case 0 -> null;
    case 1 -> args[0];
    default -> { throw new IllegalArgumentException("invalid args"); }
  };

  System.out.println(s);

Output:

[ERROR]      error-prone version: 2.3.3
[ERROR]      BugPattern: NullAway
[ERROR]      Stack Trace:
[ERROR]      com.google.common.util.concurrent.ExecutionError: java.lang.AssertionError: case visitor is implemented in SwitchBuilder
[ERROR]         at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2048)
[ERROR]         at com.google.common.cache.LocalCache.get(LocalCache.java:3952)
[ERROR]         at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3974)
[ERROR]         at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4958)
[ERROR]         at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4964)
[ERROR]         at com.uber.nullaway.dataflow.DataFlow.dataflow(DataFlow.java:140)
[ERROR]         at com.uber.nullaway.dataflow.DataFlow.resultFor(DataFlow.java:251)
[ERROR]         at com.uber.nullaway.dataflow.DataFlow.resultForExpr(DataFlow.java:228)
[ERROR]         at com.uber.nullaway.dataflow.DataFlow.expressionDataflow(DataFlow.java:173)
[ERROR]         at com.uber.nullaway.dataflow.AccessPathNullnessAnalysis.getNullness(AccessPathNullnessAnalysis.java:89)
[ERROR]         at com.uber.nullaway.NullAway.nullnessFromDataflow(NullAway.java:1885)
[ERROR]         at com.uber.nullaway.NullAway.mayBeNullExpr(NullAway.java:1854)
[ERROR]         at com.uber.nullaway.NullAway.matchDereference(NullAway.java:1935)
[ERROR]         at com.uber.nullaway.NullAway.matchMemberSelect(NullAway.java:457)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:433)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitMemberSelect(ErrorProneScanner.java:712)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitMemberSelect(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2197)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitParenthesized(TreeScanner.java:599)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitParenthesized(ErrorProneScanner.java:785)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitParenthesized(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCParens.accept(JCTree.java:1934)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitSwitchExpression(TreeScanner.java:353)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCSwitchExpression.accept(JCTree.java:1325)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:91)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitVariable(TreeScanner.java:224)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitVariable(ErrorProneScanner.java:871)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitVariable(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:980)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:249)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:507)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1038)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:91)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitMethod(TreeScanner.java:207)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:726)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:904)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:91)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:114)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:188)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:535)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:814)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:114)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:145)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:546)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:597)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:55)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
[ERROR]         at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:151)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
[ERROR]         at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1418)
[ERROR]         at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1365)
[ERROR]         at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:966)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:147)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
[ERROR]         at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess(JavaxToolsCompiler.java:126)
[ERROR]         at org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile(JavacCompiler.java:174)
[ERROR]         at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:1129)
[ERROR]         at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:188)
[ERROR]         at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
[ERROR]         at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
[ERROR]         at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
[ERROR]         at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
[ERROR]         at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
[ERROR]         at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
[ERROR]         at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
[ERROR]         at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
[ERROR]         at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
[ERROR]         at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
[ERROR]         at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
[ERROR]         at org.apache.maven.cli.MavenCli.execute(MavenCli.java:956)
[ERROR]         at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
[ERROR]         at org.apache.maven.cli.MavenCli.main(MavenCli.java:192)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[ERROR]         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR]         at java.base/java.lang.reflect.Method.invoke(Method.java:567)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
[ERROR]   Caused by: java.lang.AssertionError: case visitor is implemented in SwitchBuilder
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitCase(CFGBuilder.java:3381)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitCase(CFGBuilder.java:1416)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCase.accept(JCTree.java:1293)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:114)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitSwitchExpression(TreeScanner.java:354)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCSwitchExpression.accept(JCTree.java:1325)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.translateAssignment(CFGBuilder.java:2687)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitVariable(CFGBuilder.java:4766)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitVariable(CFGBuilder.java:1416)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:980)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitBlock(CFGBuilder.java:3258)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitBlock(CFGBuilder.java:1416)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1038)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.process(CFGBuilder.java:1571)
[ERROR]         at shadow.checkerframework.dataflow.cfg.CFGBuilder.build(CFGBuilder.java:255)
[ERROR]         at com.uber.nullaway.dataflow.DataFlow$2.load(DataFlow.java:124)
[ERROR]         at com.uber.nullaway.dataflow.DataFlow$2.load(DataFlow.java:94)
[ERROR]         at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3528)
[ERROR]         at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2277)
[ERROR]         at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2154)
[ERROR]         at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2044)
[ERROR]         ... 110 more

Error 2: "java.lang.RuntimeException: whoops, better handle SWITCH_EXPRESSION"

Source code:

// ResourceMode is an enum with two values.
private static String defaultRoot(ResourceMode mode) {
  return switch (mode) {
    case CLASS_PATH -> "assets";
    case FILE_SYSTEM -> "src/main/resources/assets";
  };
}

Output:

[ERROR]      error-prone version: 2.3.3
[ERROR]      BugPattern: NullAway
[ERROR]      Stack Trace:
[ERROR]      java.lang.RuntimeException: whoops, better handle SWITCH_EXPRESSION switch (mode) {
[ERROR]   case CLASS_PATH -> break "assets";
[ERROR]   case FILE_SYSTEM -> break "src/main/resources/assets";
[ERROR]   }
[ERROR]         at com.uber.nullaway.NullAway.mayBeNullExpr(NullAway.java:1864)
[ERROR]         at com.uber.nullaway.NullAway.checkReturnExpression(NullAway.java:608)
[ERROR]         at com.uber.nullaway.NullAway.matchReturn(NullAway.java:314)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:433)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:802)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1629)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:249)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:507)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1038)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:91)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitMethod(TreeScanner.java:207)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:726)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:904)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:91)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:114)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:188)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:535)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:814)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:71)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:45)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:114)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:145)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:546)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:150)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:597)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
[ERROR]         at com.google.errorprone.scanner.Scanner.scan(Scanner.java:55)
[ERROR]         at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
[ERROR]         at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:151)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
[ERROR]         at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1418)
[ERROR]         at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1365)
[ERROR]         at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:966)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:147)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
[ERROR]         at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
[ERROR]         at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess(JavaxToolsCompiler.java:126)
[ERROR]         at org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile(JavacCompiler.java:174)
[ERROR]         at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:1129)
[ERROR]         at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:188)
[ERROR]         at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
[ERROR]         at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
[ERROR]         at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
[ERROR]         at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
[ERROR]         at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
[ERROR]         at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
[ERROR]         at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
[ERROR]         at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
[ERROR]         at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
[ERROR]         at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
[ERROR]         at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
[ERROR]         at org.apache.maven.cli.MavenCli.execute(MavenCli.java:956)
[ERROR]         at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
[ERROR]         at org.apache.maven.cli.MavenCli.main(MavenCli.java:192)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[ERROR]         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR]         at java.base/java.lang.reflect.Method.invoke(Method.java:567)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
[ERROR]         at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
msridhar commented 5 years ago

Thanks for the report, @michaelhixson! For the java.lang.RuntimeException, fixing should conceptually be easy, though some thought may be required as to how to do it while still allowing NullAway to build on JDK 8.

For the java.lang.AssertionError, looks like that is an issue in the Checker Dataflow library from the Checker Framework and we'll need a fix there. Could you possibly file an issue on the Checker Framework regarding support for switch expressions in Checker Dataflow to get their thoughts on difficulty of fixing?

michaelhixson commented 5 years ago

Could you possibly file an issue on the Checker Framework regarding support for switch expressions in Checker Dataflow to get their thoughts on difficulty of fixing?

Any idea how I can craft a test case that uses Checker Dataflow directly, without NullAway, to demonstrate the problem to them? I gave it a shot and couldn't figure out how to use anything in the org.checkerframework.dataflow package.

msridhar commented 5 years ago

Yeah a standalone example will be tricky. You can probably just point them to this issue. Here is the relevant part of the exception stack that you can paste:

[ERROR]   Caused by: java.lang.AssertionError: case visitor is implemented in SwitchBuilder
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitCase(CFGBuilder.java:3381)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitCase(CFGBuilder.java:1416)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCase.accept(JCTree.java:1293)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:106)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:114)
[ERROR]         at jdk.compiler/com.sun.source.util.TreeScanner.visitSwitchExpression(TreeScanner.java:354)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCSwitchExpression.accept(JCTree.java:1325)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.translateAssignment(CFGBuilder.java:2687)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitVariable(CFGBuilder.java:4766)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitVariable(CFGBuilder.java:1416)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:980)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitBlock(CFGBuilder.java:3258)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.visitBlock(CFGBuilder.java:1416)
[ERROR]         at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1038)
[ERROR]         at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder$CFGTranslationPhaseOne.process(CFGBuilder.java:1571)
[ERROR]         at org.checkerframework.dataflow.cfg.CFGBuilder.build(CFGBuilder.java:255)

And here is the line throwing the exception on the Checker Framework master branch.

michaelhixson commented 5 years ago

Ok, I filed the upstream issue here: https://github.com/typetools/checker-framework/issues/2373

ZacSweers commented 5 years ago

Does NullAway cover standard switch statements on enums today? I noticed this in our codebase today

image

msridhar commented 5 years ago

Good catch, @ZacSweers! That one should be easy to fix. Can you file a separate issue for it?

ZacSweers commented 5 years ago

Done - #299

michaelhixson commented 4 years ago

For the java.lang.RuntimeException, fixing should conceptually be easy, though some thought may be required as to how to do it while still allowing NullAway to build on JDK 8.

@msridhar What do you think of an approach like this?

diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java
index a600c5d..ce823b6 100644
--- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java
+++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java
@@ -1962,6 +1962,10 @@ public class NullAway extends BugChecker
         exprMayBeNull = nullnessFromDataflow(state, expr);
         break;
       default:
+        if (expr.getKind().name().equals("SWITCH_EXPRESSION")) {
+          exprMayBeNull = nullnessFromDataflow(state, expr);
+          break;
+        }
         throw new RuntimeException(
             "whoops, better handle " + expr.getKind() + " " + state.getSourceForNode(expr));
     }

With that change to NullAway and the following change to dataflow, my code with switch expressions compiles.

diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/CFGBuilder.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/CFGBuilder.java
index 505b5a3ec..58ed6738b 100644
--- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/CFGBuilder.java
+++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/CFGBuilder.java
@@ -3382,11 +3382,6 @@ public class CFGBuilder {
             }
         }

-        @Override
-        public Node visitCase(CaseTree tree, Void p) {
-            throw new AssertionError("case visitor is implemented in SwitchBuilder");
-        }
-
         @Override
         public Node visitCatch(CatchTree tree, Void p) {
             scan(tree.getParameter(), p);

This doesn't catch nullness errors involving switch expressions, but it seems like a good intermediate step.

msridhar commented 4 years ago

@michaelhixson I'm ok with a change like this, though as you know we'll also need an updated Checker Framework dataflow library.

lessthanoptimal commented 4 years ago

Any updates or a work around? Ran into this problem on a Java 14 project.

msridhar commented 4 years ago

@lessthanoptimal unfortunately, no. We would still need a fix for typetools/checker-framework#2373 before we could ship a NullAway fix for this problem. We will definitely post an update here when we make some progress

msridhar commented 2 years ago

With #510 landed the latest NullAway snapshot should no longer crash on the new kinds of switch though it may be imprecise. Is anyone able to test this out? @lessthanoptimal?

lessthanoptimal commented 2 years ago

It threw this exception:

     error-prone version: 2.10.0
     BugPattern: NullAway
     Stack Trace:
     java.lang.RuntimeException: whoops, better handle SWITCH_EXPRESSION switch (index) {
                        case 0 -> a;
                        case 1 -> b;
                        case 2 -> c;
                        case 3 -> d;
                        default -> throw new IllegalArgumentException("Requested index out of range. " + index);
                }
        at com.uber.nullaway.NullAway.mayBeNullExpr(NullAway.java:1948)
        at com.uber.nullaway.NullAway.checkReturnExpression(NullAway.java:630)
        at com.uber.nullaway.NullAway.matchReturn(NullAway.java:293)
        at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:449)
        at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:816)
        at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1665)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:250)
        at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:520)
        at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:150)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1059)

Here's how I added the dependency:

        project.ext.nullaway_version = '0.9.3-SNAPSHOT'
        annotationProcessor "com.uber.nullaway:nullaway:$project.nullaway_version"
        testAnnotationProcessor "com.uber.nullaway:nullaway:$project.nullaway_version"
msridhar commented 2 years ago

Thanks! I should have known that something wouldn't work. I will work on fixing that crash and putting together a proper test case (may take a bit of time as we currently don't test on JDK 17).

lessthanoptimal commented 2 years ago

Sounds good an thanks for working on this issue! FYI I got that error in JDK 15.

msridhar commented 2 years ago

Sounds good an thanks for working on this issue! FYI I got that error in JDK 15.

Thanks! I'm sure the same error will appear in JDK 17. FWIW I don't think we have resources to test and fix NullAway bugs on non-LTS JDK releases, though if it's an easy fix we will try.

msridhar commented 2 years ago

@lessthanoptimal this should be fixed now! Any chance you can again test the snapshot build on your code base?

lessthanoptimal commented 2 years ago

@msridhar Just tried it and the SNAPSHOT is working! Thanks! I tested it in two projects.

msridhar commented 2 years ago

Thanks for checking! We'll get this out in a new release soon though it may be after the holidays

lessthanoptimal commented 2 years ago

Celebration might be premature. Was in the process of adding null checks to a project and ran into a situation where it blew up.

    (see http://t.uber.com/nullaway )
/home/pja/projects/boofcv/main/boofcv-geo/src/main/java/boofcv/factory/geo/FactoryMultiViewRobust.java:190: error: An unhandled exception was thrown by the Error Prone static analysis plugin.
                                () -> switch (_configFundamental.errorModel) {
                                                                ^
     Please report this at https://github.com/google/error-prone/issues/new and include the following:

     error-prone version: 2.9.0
     BugPattern: NullAway
     Stack Trace:
     com.google.common.util.concurrent.ExecutionError: java.lang.AssertionError: case visitor is implemented in SwitchBuilder
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2053)
        at com.google.common.cache.LocalCache.get(LocalCache.java:3966)
        at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3989)
        at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4950)
        at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4956)
        at com.uber.nullaway.dataflow.DataFlow.dataflow(DataFlow.java:146)
        at com.uber.nullaway.dataflow.DataFlow.resultFor(DataFlow.java:276)
        at com.uber.nullaway.dataflow.DataFlow.resultForExpr(DataFlow.java:253)
        at com.uber.nullaway.dataflow.DataFlow.expressionDataflow(DataFlow.java:196)
        at com.uber.nullaway.dataflow.AccessPathNullnessAnalysis.getNullness(AccessPathNullnessAnalysis.java:127)
        at com.uber.nullaway.NullAway.nullnessFromDataflow(NullAway.java:1979)
        at com.uber.nullaway.NullAway.mayBeNullExpr(NullAway.java:1942)
        at com.uber.nullaway.NullAway.matchDereference(NullAway.java:2016)
        at com.uber.nullaway.NullAway.matchMemberSelect(NullAway.java:439)
        at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:450)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMemberSelect(ErrorProneScanner.java:727)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMemberSelect(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2293)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitParenthesized(TreeScanner.java:591)
        at com.google.errorprone.scanner.ErrorProneScanner.visitParenthesized(ErrorProneScanner.java:800)
        at com.google.errorprone.scanner.ErrorProneScanner.visitParenthesized(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCParens.accept(JCTree.java:1970)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitSwitchExpression(TreeScanner.java:347)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCSwitchExpression.accept(JCTree.java:1338)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitLambdaExpression(TreeScanner.java:578)
        at com.google.errorprone.scanner.ErrorProneScanner.visitLambdaExpression(ErrorProneScanner.java:703)
        at com.google.errorprone.scanner.ErrorProneScanner.visitLambdaExpression(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1926)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:113)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitMethodInvocation(TreeScanner.java:528)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMethodInvocation(ErrorProneScanner.java:752)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMethodInvocation(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1761)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitExpressionStatement(TreeScanner.java:452)
        at com.google.errorprone.scanner.ErrorProneScanner.visitExpressionStatement(ErrorProneScanner.java:634)
        at com.google.errorprone.scanner.ErrorProneScanner.visitExpressionStatement(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1540)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:250)
        at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:521)
        at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1059)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitMethod(TreeScanner.java:208)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:741)
        at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:925)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:113)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:189)
        at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:549)
        at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:832)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:113)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:144)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:561)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:603)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:58)
        at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
        at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:152)
        at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1421)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1368)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:960)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:147)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
        at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:74)
        at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:94)
        at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:55)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:40)
        at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerWorkAction.execute(AbstractDaemonCompiler.java:135)
        at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
        at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:49)
        at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:43)
        at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:97)
        at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:43)
        at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:32)
        at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:22)
        at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:85)
        at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:55)
        at org.gradle.process.internal.worker.request.WorkerAction$1.call(WorkerAction.java:138)
        at org.gradle.process.internal.worker.child.WorkerLogEventListener.withWorkerLoggingProtocol(WorkerLogEventListener.java:41)
        at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:135)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
        at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
        at java.base/java.lang.Thread.run(Thread.java:832)
  Caused by: java.lang.AssertionError: case visitor is implemented in SwitchBuilder
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitCase(CFGTranslationPhaseOne.java:2407)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.visitCase(CFGTranslationPhaseOne.java:193)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCase.accept(JCTree.java:1307)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.scan(CFGTranslationPhaseOne.java:491)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.scan(CFGTranslationPhaseOne.java:193)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:113)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitSwitchExpression(TreeScanner.java:348)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCSwitchExpression.accept(JCTree.java:1338)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGTranslationPhaseOne.process(CFGTranslationPhaseOne.java:426)
        at org.checkerframework.nullaway.dataflow.cfg.builder.CFGBuilder.build(CFGBuilder.java:91)
        at com.uber.nullaway.dataflow.DataFlow$2.load(DataFlow.java:130)
        at com.uber.nullaway.dataflow.DataFlow$2.load(DataFlow.java:97)
        at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3533)
        at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2282)
        at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2159)
        at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2049)
        ... 135 more
msridhar commented 2 years ago

@lessthanoptimal oof that looks like a Checker Framework issue. Any chance you can reduce to a self-contained small-ish example with the same crash?

msridhar commented 2 years ago

Also, if you add @SuppressWarnings("NullAway") to the containing method or class, does the crash go away?

lessthanoptimal commented 2 years ago

@msridhar Adding @SuppressWarnings("NullAway") stopped it from crashing there.

I'll see if I can create a stand alone example. This particular project is fairly large. Not sure if this is relevant, but the switch expression is inside a lambda which is not typical in my use cases.

() -> switch (_configFundamental.errorModel) {
    case SAMPSON -> new DistanceFromModelResidual<>(new FundamentalResidualSampson());
    case GEOMETRIC -> new DistanceFundamentalGeometric();
});
msridhar commented 2 years ago

Ok, thanks! I may be able to repro just based on your excerpt; will report back.

msridhar commented 2 years ago

Managed to reproduce; opened #524 on it. While we work to fix, you'll have to use @SuppressWarnings("NullAway") as a workaround. Hope that's ok for the time being; getting a full fix may take a few weeks given Checker Framework release cycle, and I'd rather not hold up the next NullAway release on that.

msridhar commented 2 years ago

FYI our current switch expression support is now released in version 0.9.3