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

Support switch expressions #289

Closed
michaelhixson opened this issue Mar 19, 2019 · 26 comments · Fixed by #520
Closed

Support switch expressions #289

michaelhixson opened this issue Mar 19, 2019 · 26 comments · Fixed by #520
Assignees

Comments

@michaelhixson
Copy link
Contributor

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
Copy link
Collaborator

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
Copy link
Contributor Author

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
Copy link
Collaborator

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
Copy link
Contributor Author

Ok, I filed the upstream issue here: typetools/checker-framework#2373

@ZacSweers
Copy link
Contributor

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

image

@msridhar
Copy link
Collaborator

msridhar commented Apr 4, 2019

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

@ZacSweers
Copy link
Contributor

Done - #299

@michaelhixson
Copy link
Contributor Author

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
Copy link
Collaborator

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

@lessthanoptimal
Copy link

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

@msridhar
Copy link
Collaborator

@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 added a commit that referenced this issue Dec 7, 2021
The key new feature here is that the dataflow library no longer crashes on switch expressions / arrow case labels in switch statements:

https://github.com/typetools/checker-framework/blob/checker-framework-3.20.0/docs/CHANGELOG.md#version-3200-december-6-2021

This is an initial step toward fixing #289, though we will need precise control-flow graphs (which is still a WIP in Checker dataflow) to really handle these constructs properly.
@msridhar
Copy link
Collaborator

msridhar commented Dec 7, 2021

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
Copy link

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 msridhar self-assigned this Dec 7, 2021
@msridhar
Copy link
Collaborator

msridhar commented Dec 7, 2021

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
Copy link

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

@msridhar
Copy link
Collaborator

msridhar commented Dec 7, 2021

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 added a commit that referenced this issue Dec 21, 2021
Fixes #289 

Checker Framework 3.21.0 added support for switch expressions; we build on that to support the expressions in NullAway.  We also add a `jdk17-unit-tests` module to test the support (which requires a JDK 12+ compiler).
@msridhar
Copy link
Collaborator

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

@lessthanoptimal
Copy link

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

@msridhar
Copy link
Collaborator

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

@lessthanoptimal
Copy link

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
Copy link
Collaborator

@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
Copy link
Collaborator

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

@lessthanoptimal
Copy link

lessthanoptimal commented Dec 22, 2021

@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
Copy link
Collaborator

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

@msridhar
Copy link
Collaborator

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
Copy link
Collaborator

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants