False positive in `UnnecessaryDefaultInEnumSwitch` triggered by (presumed) compiler bug
- Dominant language
- Java
- Stars
- 7.2k
- Forks
- 820
- Avg merge
- 5h 9m
- Merged PRs (30d)
- 50
Description
I cannot provide a small reproduction case yet, but let me describe the situation.
Some code triggers the following warning:
```
[WARNING] /some/path/to/SomeClass.java:[430,13] [UnnecessaryDefaultInEnumSwitch] Switch handles all enum values; an explicit default case is unnecessary and defeats error checking for non-exhaustive switches.
(see http://errorprone.info/bugpattern/UnnecessaryDefaultInEnumSwitch)
Did you mean to remove this line?
```
In actuality this code is covered by [case 3](https://github.com/google/error-prone/blob/effc868a934bee11d1a085a3db8f611c4fba98f9/core/src/main/java/com/google/errorprone/bugpatterns/UnnecessaryDefaultInEnumSwitch.java#L130): the `default` clause cannot be removed without breaking the code.
Above this warning the following stacktrace is logged:
```
java.lang.RuntimeException: java.lang.NullPointerException
at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:158)
at com.sun.tools.javac.api.JavacTaskImpl.analyze(JavacTaskImpl.java:363)
at com.google.errorprone.fixes.SuggestedFixes.compilesWithFix(SuggestedFixes.java:660)
at com.google.errorprone.bugpatterns.UnnecessaryDefaultInEnumSwitch.matchSwitch(UnnecessaryDefaultInEnumSwitch.java:143)
at com.google.errorprone.scanner.ErrorProneScanner.visitSwitch(ErrorProneScanner.java:1030)
at com.google.errorprone.scanner.ErrorProneScanner.visitSwitch(ErrorProneScanner.java:146)
at com.sun.tools.javac.tree.JCTree$JCSwitch.accept(JCTree.java:1223)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:42)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
at com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
at com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:248)
at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:530)
at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:146)
at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1026)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:42)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
at com.sun.source.util.TreeScanner.visitMethod(TreeScanner.java:206)
at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:898)
at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:146)
at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:898)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:42)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:90)
at com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:113)
at com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:187)
at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:590)
at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:146)
at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:808)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:82)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:42)
at com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:113)
at com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:144)
at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:605)
at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:146)
at com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:591)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
at com.google.errorprone.scanner.Scanner.scan(Scanner.java:64)
at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:41)
at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:152)
at com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:120)
at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1425)
at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1374)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:973)
at com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:100)
at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:142)
at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:96)
at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:90)
at com.google.errorprone.BaseErrorProneCompiler.run(BaseErrorProneCompiler.java:137)
at com.google.errorprone.BaseErrorProneCompiler.run(BaseErrorProneCompiler.java:108)
at com.google.errorprone.ErrorProneCompiler.run(ErrorProneCompiler.java:118)
at org.codehaus.plexus.compiler.javac.errorprone.JavacCompilerWithErrorProne$CompilerInvoker.compile(JavacCompilerWithErrorProne.java:222)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.plexus.compiler.javac.errorprone.JavacCompilerWithErrorProne.performCompile(JavacCompilerWithErrorProne.java:91)
at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:1075)
at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:168)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:154)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:146)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call(MultiThreadedBuilder.java:200)
at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call(MultiThreadedBuilder.java:196)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
at com.sun.tools.javac.model.JavacTypes.getOverriddenMethods(JavacTypes.java:327)
at com.sun.tools.doclint.Env.setCurrent(Env.java:208)
at com.sun.tools.doclint.Checker.scan(Checker.java:152)
at com.sun.tools.doclint.DocLint$2.visitDecl(DocLint.java:314)
at com.sun.tools.doclint.DocLint$DeclScanner.visitClass(DocLint.java:398)
at com.sun.tools.doclint.DocLint$DeclScanner.visitClass(DocLint.java:382)
at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:808)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
at com.sun.source.util.TreeScanner.scan(TreeScanner.java:105)
at com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:113)
at com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:144)
at com.sun.tools.doclint.DocLint$DeclScanner.visitCompilationUnit(DocLint.java:426)
at com.sun.tools.doclint.DocLint$DeclScanner.visitCompilationUnit(DocLint.java:382)
at com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:591)
at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:82)
at com.sun.tools.doclint.DocLint$3.started(DocLint.java:325)
at com.sun.tools.javac.api.ClientCodeWrapper$WrappedTaskListener.started(ClientCodeWrapper.java:806)
at com.sun.tools.javac.api.MultiTaskListener.started(MultiTaskListener.java:112)
at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1342)
at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1323)
at com.sun.tools.javac.api.JavacTaskImpl.analyze(JavacTaskImpl.java:384)
at com.sun.tools.javac.api.JavacTaskImpl.lambda$analyze$1(JavacTaskImpl.java:363)
at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:142)
... 78 more
```
This stacktrace is logged at [SuggestedFixes.java:662](https://github.com/google/error-prone/blob/effc868a934bee11d1a085a3db8f611c4fba98f9/check_api/src/main/java/com/google/errorprone/fixes/SuggestedFixes.java#L662). When I drop the `-Xdoclint:reference` flag from our build configuration no stacktrace is logged and the false positive goes away.
I have two questions for the Error Prone team:
* Should there perhaps be a `return false` statement after `SuggestedFixes.java:662`, just to be safe?
* What do you think about pruning the arguments passed in to the secondary compilation at [SuggestedFixes.java:648](https://github.com/google/error-prone/blob/effc868a934bee11d1a085a3db8f611c4fba98f9/check_api/src/main/java/com/google/errorprone/fixes/SuggestedFixes.java#L648)? Invocation of `#compilesWithFix` is very expensive, so perhaps it's worthwhile to drop `-Xdoclint` and certain other flags. (Such as `-verbose`; nobody's reading the output anyway.)
Contributor guide
Assessment
This issue has not been assessed yet.