A tool to help eliminate NullPointerExceptions (NPEs) in your Java code with low build-time overhead

Overview

NullAway: Fast Annotation-Based Null Checking for Java Build Status Coverage Status

NullAway is a tool to help eliminate NullPointerExceptions (NPEs) in your Java code. To use NullAway, first add @Nullable annotations in your code wherever a field, method parameter, or return value may be null. Given these annotations, NullAway performs a series of type-based, local checks to ensure that any pointer that gets dereferenced in your code cannot be null. NullAway is similar to the type-based nullability checking in the Kotlin and Swift languages, and the Checker Framework and Eradicate null checkers for Java.

NullAway is fast. It is built as a plugin to Error Prone and can run on every single build of your code. In our measurements, the build-time overhead of running NullAway is usually less than 10%. NullAway is also practical: it does not prevent all possible NPEs in your code, but it catches most of the NPEs we have observed in production while imposing a reasonable annotation burden, giving a great "bang for your buck." At Uber, we combine NullAway with RAVE to obtain thorough protection against NPEs in our Android apps.

Installation

Overview

NullAway requires that you build your code with Error Prone, version 2.4.0 or higher. See the Error Prone documentation for instructions on getting started with Error Prone and integration with your build system. The instructions below assume you are using Gradle; see the docs for discussion of other build systems.

Gradle

Java (non-Android)

To integrate NullAway into your non-Android Java project, add the following to your build.gradle file:

plugins {
  // we assume you are already using the Java plugin
  id "net.ltgt.errorprone" version "0.6"
}

dependencies {
  annotationProcessor "com.uber.nullaway:nullaway:0.9.0"

  // Optional, some source of nullability annotations.
  // Not required on Android if you use the support 
  // library nullability annotations.
  compileOnly "com.google.code.findbugs:jsr305:3.0.2"

  errorprone "com.google.errorprone:error_prone_core:2.4.0"
  errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"
}

import net.ltgt.gradle.errorprone.CheckSeverity

tasks.withType(JavaCompile) {
  // remove the if condition if you want to run NullAway on test code
  if (!name.toLowerCase().contains("test")) {
    options.errorprone {
      check("NullAway", CheckSeverity.ERROR)
      option("NullAway:AnnotatedPackages", "com.uber")
    }
  }
}

Let's walk through this script step by step. The plugins section pulls in the Gradle Error Prone plugin for Error Prone integration. If you are using the older apply plugin syntax instead of a plugins block, the following is equivalent:

buildscript {
  repositories {
    gradlePluginPortal()
  }
  dependencies {
    classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.6"
  }
}

apply plugin: 'net.ltgt.errorprone'

In dependencies, the annotationProcessor line loads NullAway, and the compileOnly line loads a JSR 305 library which provides a suitable @Nullable annotation (javax.annotation.Nullable). NullAway allows for any @Nullable annotation to be used, so, e.g., @Nullable from the Android Support Library or JetBrains annotations is also fine. The errorprone line ensures that a compatible version of Error Prone is used, and the errorproneJavac line is needed for JDK 8 compatibility.

Finally, in the tasks.withType(JavaCompile) section, we pass some configuration options to NullAway. First check("NullAway", CheckSeverity.ERROR) sets NullAway issues to the error level (it's equivalent to the -Xep:NullAway:ERROR standard Error Prone argument); by default NullAway emits warnings. Then, option("NullAway:AnnotatedPackages", "com.uber") (equivalent to the -XepOpt:NullAway:AnnotatedPackages=com.uber standard Error Prone argument), tells NullAway that source code in packages under the com.uber namespace should be checked for null dereferences and proper usage of @Nullable annotations, and that class files in these packages should be assumed to have correct usage of @Nullable (see the docs for more detail). NullAway requires at least the AnnotatedPackages configuration argument to run, in order to distinguish between annotated and unannotated code. See the configuration docs for other useful configuration options.

We recommend addressing all the issues that Error Prone reports, particularly those reported as errors (rather than warnings). But, if you'd like to try out NullAway without running other Error Prone checks, you can use options.errorprone.disableAllChecks (equivalent to passing "-XepDisableAllChecks" to the compiler, before the NullAway-specific arguments).

Snapshots of the development version are available in Sonatype's snapshots repository.

Android

The configuration for an Android project is very similar to the Java case, with one key difference: The com.google.code.findbugs:jsr305:3.0.2 dependency can be removed; you can use the android.support.annotation.Nullable annotation from the Android Support library.

dependencies {
  annotationProcessor "com.uber.nullaway:nullaway:0.9.0"
  errorprone "com.google.errorprone:error_prone_core:2.4.0"
  errorproneJavac "com.google.errorprone:javac:9+181-r4173-1"  
}

A complete Android build.gradle example is here. Also see our sample app. (The sample app's build.gradle is not suitable for direct copy-pasting, as some configuration is inherited from the top-level build.gradle.)

Annotation Processors / Generated Code

Some annotation processors like Dagger and AutoValue generate code into the same package namespace as your own code. This can cause problems when setting NullAway to the ERROR level as suggested above, since errors in this generated code will block the build. Currently the best solution to this problem is to completely disable Error Prone on generated code, using the -XepExcludedPaths option added in Error Prone 2.13 (documented here, use options.errorprone.excludedPaths= in Gradle). To use, figure out which directory contains the generated code, and add that directory to the excluded path regex.

Note for Dagger users: Dagger versions older than 2.12 can have bad interactions with NullAway; see here. Please update to Dagger 2.12 to fix the problem.

Lombok

Unlike other annotation processors above, Lombok modifies the in-memory AST of the code it processes, which is the source of numerous incompatibilities with Error Prone and, consequently, NullAway.

We do not particularly recommend using NullAway with Lombok. However, NullAway encodes some knowledge of common Lombok annotations and we do try for best-effort compatibility. In particular, common usages like @lombok.Builder and @Data classes should be supported.

In order for NullAway to successfully detect Lombok generated code within the in-memory Java AST, the following configuration option must be passed to Lombok as part of an applicable lombok.config file:

addLombokGeneratedAnnotation

This causes Lombok to add @lombok.Generated to the methods/classes it generates. NullAway will ignore (i.e. not check) the implementation of this generated code, treating it as unannotated.

Code Example

Let's see how NullAway works on a simple code example:

static void log(Object x) {
    System.out.println(x.toString());
}
static void foo() {
    log(null);
}

This code is buggy: when foo() is called, the subsequent call to log() will fail with an NPE. You can see this error in the NullAway sample app by running:

cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build

By default, NullAway assumes every method parameter, return value, and field is non-null, i.e., it can never be assigned a null value. In the above code, the x parameter of log() is assumed to be non-null. So, NullAway reports the following error:

warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
    log(null);
        ^

We can fix this error by allowing null to be passed to log(), with a @Nullable annotation:

static void log(@Nullable Object x) {
    System.out.println(x.toString());
}

With this annotation, NullAway points out the possible null dereference:

warning: [NullAway] dereferenced expression x is @Nullable
    System.out.println(x.toString());
                        ^

We can fix this warning by adding a null check:

static void log(@Nullable Object x) {
    if (x != null) {
        System.out.println(x.toString());
    }
}

With this change, all the NullAway warnings are fixed.

For more details on NullAway's checks, error messages, and limitations, see our detailed guide.

Support

Please feel free to open a GitHub issue if you have any questions on how to use NullAway. Or, you can join the NullAway Discord server and ask us a question there.

Contributors

We'd love for you to contribute to NullAway! Please note that once you create a pull request, you will be asked to sign our Uber Contributor License Agreement.

License

NullAway is licensed under the MIT license. See the LICENSE.txt file for more information.

Comments
  • IncompatibleClassChangeError with 0.9.0, JDK 8, and error-prone 2.5.1

    IncompatibleClassChangeError with 0.9.0, JDK 8, and error-prone 2.5.1

    When trying to update to 0.9.0, we see this runtime error from dataflow come up

    > Task :libraries:foundation:slack-commons:compileReleaseJavaWithJavac
    <path≥/slack/commons/logger/DebugLogger.java:27: error: An unhandled exception was thrown by the Error Prone static analysis plugin.
    public class DebugLogger implements Logger {
           ^
         Please report this at https://github.com/google/error-prone/issues/new and include the following:
      
         error-prone version: 2.5.1
         BugPattern: NullAway
         Stack Trace:
         java.lang.IncompatibleClassChangeError: Implementing class
            at java.lang.ClassLoader.defineClass1(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
            at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
            at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
            at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
            at java.lang.ClassLoader.defineClass1(Native Method)
            at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
            at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
            at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
            at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
            at com.uber.nullaway.dataflow.DataFlow.<init>(DataFlow.java:78)
            at com.uber.nullaway.dataflow.AccessPathNullnessAnalysis.<init>(AccessPathNullnessAnalysis.java:74)
            at com.uber.nullaway.dataflow.AccessPathNullnessAnalysis.instance(AccessPathNullnessAnalysis.java:104)
            at com.uber.nullaway.NullAway.getNullnessAnalysis(NullAway.java:1971)
            at com.uber.nullaway.NullAway.matchClass(NullAway.java:1139)
            at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:450)
            at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:548)
            at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:151)
            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:74)
            at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
            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:561)
            at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:151)
            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:58)
            at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
            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:1404)
            at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1353)
            at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:946)
            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 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 ...more gradle lines
    1 error
    

    Let me know what else I can help test. Possibly using a non-JDK8-compatible dataflow version?

    bug 
    opened by ZacSweers 31
  • Support switch expressions

    Support switch expressions

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

    • Switch expressions: http://openjdk.java.net/jeps/325
    • Preview features: http://openjdk.java.net/jeps/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)
    
    
    opened by michaelhixson 26
  • NoSuchMethodError

    NoSuchMethodError

    I was following up the sample in below link to setup NullAway in my project, but I saw below NoSuchMethodError. Is there any suggestion for fixing this error?

    https://gist.github.com/msridhar/6cacd429567f1d1ad9a278e06809601c

    An exception has occurred in the compiler ((version info not available)). Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com) for duplicates. Include your program and the following diagnostic in your report. Thank you. java.lang.NoSuchMethodError: com.google.common.collect.ImmutableSet.toImmutableSet()Ljava/util/stream/Collector; at com.google.errorprone.BugCheckerInfo.customSuppressionAnnotations(BugCheckerInfo.java:144) at com.google.errorprone.BugCheckerInfo.(BugCheckerInfo.java:122) at com.google.errorprone.BugCheckerInfo.create(BugCheckerInfo.java:110) at com.google.errorprone.scanner.BuiltInCheckerSuppliers.getSuppliers(BuiltInCheckerSuppliers.java:298) at com.google.errorprone.scanner.BuiltInCheckerSuppliers.getSuppliers(BuiltInCheckerSuppliers.java:291) at com.google.errorprone.scanner.BuiltInCheckerSuppliers.(BuiltInCheckerSuppliers.java:327) at com.google.errorprone.ErrorProneJavacPlugin.init(ErrorProneJavacPlugin.java:42) at com.sun.tools.javac.api.BasicJavacTask.initPlugins(BasicJavacTask.java:214) at com.sun.tools.javac.api.JavacTaskImpl.prepareCompiler(JavacTaskImpl.java:192) at com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:97) 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 org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:93) at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57) at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:54) at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:39) at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerWorkAction.execute(AbstractDaemonCompiler.java:113) at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:47) at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:46) at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:36) at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:98) at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:36) at org.gradle.workers.internal.FlatClassLoaderWorker.execute(FlatClassLoaderWorker.java:31) at org.gradle.workers.internal.WorkerDaemonServer.execute(WorkerDaemonServer.java:56) 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.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:118) 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.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:412) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) at java.lang.Thread.run(Thread.java:748)

    Task :Teams:compileDevDebugJavaWithJavac FAILED

    opened by wecheng 24
  • Stream support

    Stream support

    Thank you for contributing to NullAway!

    Please note that once you click "Create Pull Request" you will be asked to sign our Uber Contributor License Agreement via CLA assistant.

    Before pressing the "Create Pull Request" button, please provide the following:

    • [ ] A description about what and why you are contributing, even if it's trivial. Solve nullability check
    • [ ] The issue number(s) or PR number(s) in the description if you are contributing in response to those. Trying to solve #332
    • [ ] If applicable, unit tests.

    This is not ready by any means. Just wanted to let you know that copying the rxhandler and configuring it works fine.

    I just want to define the scope. This PR is just for regular Streams, not primitive streams. I will configure the stream function. After all cases are covered, do you want to unite the logic of rx streams and java streams (DRY school) or are you more of the copy school till the logic was implemented x times?

    opened by david-gang 23
  • CheckerFramework's @Nullable

    CheckerFramework's @Nullable

    Migrating from JSR-305 to the CheckerFramework and ErrorProne annotations resulted in false positives. Is org.checkerframework.checker.nullness.qual.Nullable supported? It doesn't appear to be.

    bug 
    opened by ben-manes 23
  • Does not work with Java + Kotlin Android based projects

    Does not work with Java + Kotlin Android based projects

    Repro:

    buildscript {
      repositories {
        google()
        maven { url "https://plugins.gradle.org/m2/" }
      }
    
      dependencies {
        classpath "com.android.tools.build:gradle:2.3.3"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.0"
        classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.11"
      }
    }
    
    repositories {
      google()
      maven { url "https://plugins.gradle.org/m2/" }
    }
    
    apply plugin: "com.android.application"
    apply plugin: "com.kotlin-android"
    apply plugin: "com.kotlin-kapt"
    apply plugin: "net.ltgt.errorprone"
    
    android {
      ...
    }
    
    dependencies {
      kapt "com.uber.nullaway:nullaway:0.2.2"
    
      errorprone "com.google.errorprone:error_prone_core:2.1.1"
    }
    
    tasks.withType(JavaCompile) {
      // remove the if condition if you want to run NullAway on test code
      if (!name.toLowerCase().contains("test")) {
        options.compilerArgs += ["-Xep:NullAway:ERROR", "-XepOpt:NullAway:AnnotatedPackages=com.uber"]
      }
    }
    

    Error:

    > Task :app:compileDebugJavaWithJavac FAILED
    Note: Some input files use or override a deprecated API.
    Note: Recompile with -Xlint:deprecation for details.
    com.google.errorprone.InvalidCommandLineOptionException: NullAway is not a valid checker name
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':app:compileDebugJavaWithJavac'.
    > Compilation failed with exit code 2; see the compiler error output for details.
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 1m 25s
    77 actionable tasks: 77 executed
    
    opened by jaredsburrows 23
  • Spring bean properties

    Spring bean properties

    We have a similar issue as described in #94, but wanted to call out explicitly as it may not be quite the same.

    We have a very common pattern of something like:

    private MyObject myObject;

    in a class, and its value is set via spring bean property injection.

    These always yield initializer warnings.

    Is our best option here to use @SuppressWarnings("NullAway.Init") everywhere we have a field like this?

    or register @Inject in ExcludedFieldAnnotations -- but this seems to be effectively the same as @SuppressWarnings("NullAway.Init")

    opened by ctcpip 22
  • NullAway doesn't recognize Guava Preconditions checks

    NullAway doesn't recognize Guava Preconditions checks

    I'm using Google Guava Preconditions to raise errors on null parameters. So basically, when I write something like:

    Preconditions.checkArgument(item != null, "Unable to find an element with name '%s'.", name);
    return item;
    

    item is null safe, but NullAway still raises an error.

    image

    enhancement 
    opened by MatteoJoliveau 21
  • Serialization of Type Change Suggestions for Type Violations.

    Serialization of Type Change Suggestions for Type Violations.

    Overview

    This PR enables NullAway to serialize information on code locations to resolve the reporting errors if they can be resolved via a type change. This information can be used by other tools such as AutoFixer to have an understanding of the source code, code points where violations occurred, and possible solutions. In the example below, NullAway will report the error: assigning @Nullable null to @Nonnull bar.

    class Foo {
         Object bar = new Object();
         
         void baz(){
               this.bar = null;
         }
    }
    

    This PR enables NullAway to suggest bar type to be @Nullable to resolve the error and creates two output files. errors.tsv where all reporting errors are stored and fixes.tsv where all the type change suggestions are stored.

    1. errors.tsv: Every row represents a reporting error with the format: MESSAGE_TYPE, MESSAGE, ENCLOSING CLASS, ENCLOSING METHOD For instance: ASSIGN_FIELD_NULLABLE, assigning nullable null to field bar, Foo, baz
    2. fixes.tsv: Every row represents a type change suggestion with the format: LOCATION, MESSAGE_TYPE, ANNOT For instance: Field bar of Foo, ASSIGN_FIELD_NULLABLE, @Nullable

    To activate the feature above the following flags must be passed to NullAway via ErrorProneFlags:

    "-XepOpt:NullAway:SerializeFixMetadata=true"
    "-XepOpt:NullAway:FixSerializationConfigPath=configpath"
    

    When -XepOpt:NullAway:SerializeFixMetadata=true is observed in the flags, NullAway will look for a file at FixSerializationConfigPath to activate/deactivate serialization features.

    Below is the FixMetadataConfigPath format:

    <serialization>
        <suggest activation="true" enclosing="true"/>
        <output>
               "outputdir"
        </output>
        <annotation>
            <nullable>javax.annotation.Nullable</nullable>
            <nonnull>javax.annotation.Nonnull</nonnull>
        </annotation>
    </serialization>
    

    If -XepOpt:NullAway:SerializeFixMetadata=true is observed, NullAway will serialize all reporting errors to errors.tsv regardless of flag values in FixSerializationConfig.

    Finding enclosing method/class for suggested fixes is costly and not always required, they can be controlled using enclosing attribute in the config file above. If any of the keys in the template config above is not found, the default value will be considered.

    Please note, at the places where explicit @Nonnull is observed, NullAway will acknowledge that annotation and will not suggest any type change.

    Implementation

    All implemented classes reside in the fixserialization package. The goal of this PR is to create SuggestedFixInfo objects which are type change suggestions of elements in the source code. Each of these objects contains a single Location instance and an Annotation . Location instances target an element in the source code. Throughout this PR the only suggested annotation in SuggestedFixInfo instances is @Nullable.

    The creation of SuggestedFixInfo objects is implemented through ErrorBuilder. The createErrorDescription signature is changed and now it accepts a fifth argument called nonNullTarget. If this parameter is non-null, the error involved a pseudo-assignment of a @Nullable expression into a @NonNull target, and this parameter is the Symbol for that target. Whenever ErrorBuilder is asked to create an ErrorDescription object, it also creates a SuggestedFixInfo targeting the parameter nonNullTarget to be @Nullable.

    opened by nimakarimipour 17
  • Initial support for JSpecify's @NullMarked annotation.

    Initial support for JSpecify's @NullMarked annotation.

    This is the first step towards NullAway adoption of the JSpecify standard.

    Our support for JSpecify must be understood as EXPERIMENTAL for the time being.

    Currently, all we do is ensure that we treat any @NullMarked third-party packages as @NonNull-by-default, using the existing semantics NullAway applies to "annotated packages" (as passed in EP flags). We have made no attempt to match the proper semantics of JSpecify yet, but we are open to looking at issues where NullAway's behavior differs from the standard.

    Note that, in particular, we are aware NullAway doesn't support type use annotations/annotations in generics. Long term, that's on the roadmap, but it will likely take a while.

    This PR also makes NullAway dependant on the JSpecify annotations artifact. We could (and might, if needed), remove that dependency by looking at the annotation's names at runtime as strings, same as we do for @Nullable, but the JSpecify annotations artifact is intended to be fairly lightweight and we are also expecting it to long-term become the default way to annotate code for analysis by NullAway.

    jspecify 
    opened by lazaroclapp 17
  • Optional get call on assignment gives a correct warning

    Optional get call on assignment gives a correct warning

    Assigning potentially empty optional get value to an object now gives a correct error

    Optional<Integer> optionalFoo = someFunction();
    Integer x = optionalFoo.get();
    x.toString();
    

    It will give error that optionalFoo can be empty.

    Fixes #351

    opened by shubhamugare 17
  • Add an initial annotations artifact (with sample @Initializer implementation)

    Add an initial annotations artifact (with sample @Initializer implementation)

    The main purpose of this change is to introduce our own annotations artifact, which can be leveraged to implement more general contracts and other annotations of interest to NullAway.

    Additionally, we start by having our own @Initializer annotation "implementation" in this annotations jar. I believe Facebook/Meta's Eradicate is being sunset in favor of Nullsafe (internally at Meta) and NullAway (for OSS), and either way recommending their annotation jar for NullAway is more of a historical artifact of nullness checking at Uber and our previous use of Infer/Eradicate than anything else. NullAway will still acknowledge any annotation with simple name @Initializer, but now we can recommend a canonical alternative which we can make sure remains supported.

    Additionally, we take the opportunity to make our @Initializer valid only on method declarations (which is the only place NullAway checks for it).

    We use annotations rather than annotation, because that's the choice JSpecify 0.3.0 went with in the end, and I refuse to spend another year discussing that 😉

    opened by lazaroclapp 2
  • Proper support for type use annotation locations + develop a deprecation path for incorrect locations

    Proper support for type use annotation locations + develop a deprecation path for incorrect locations

    For context, see #706 and particularly this summary by @msridhar (slightly edited from here):

    Let me try to summarize the overall situation here so we can think about potential solutions and their tradeoffs. #702 addressed an issue where writing List<@Nullable String> list made list itself @Nullable, due to the type use annotation on the type argument (identified in https://github.com/uber/NullAway/issues/674#issuecomment-1363205545). The change there was to only consider a type-use @Nullable annotation to be relevant a field / parameter / return type if the annotation was not in an array, inner type, wildcard, or type argument position.

    Unfortunately, this change was bad for a couple of reasons:

    1. As shown in #705, sometimes type use annotations are in an inner type position even when it doesn't syntactically look like it (see example in https://github.com/uber/NullAway/issues/705#issuecomment-1368082909).
    2. Syntactically, the "correct" location for a type use annotation is not what NullAway users (who mostly use declaration annotations) are used to. Relevant discussion is in the JSpecify user guide. The change in #702 unintentionally broke cases where users used a type use annotation (like the Checker Framework or JSpecify @Nullable) and wrote @Nullable Object[] foo2 = null;, as it changed NullAway to only look for the annotations in the syntactically-correct place (Object @Nullable [] foo2).

    For inner types, we have a fix, with caveats, in #706. It fixes point 1 above and gets rid of the surprising change in checking behavior for inner types from point 2. It does lead to a bit of weirdness, as shown in here:

    https://github.com/uber/NullAway/blob/1b1a5b1008612606a36062a99e7f5e21eb704680/nullaway/src/test/java/com/uber/nullaway/NullAwayCoreTests.java#L1113-L1117

    In particular, writing A.@Nullable B.C foo2 makes foo2 @Nullable. But this seems like a corner case that shouldn't affect users much right now.

    Dealing with arrays is a bit more complicated, since users may want to write annotations to express the nullability of array contents. If we adopt a solution like the one used in this PR for inner types, writing either @Nullable Object[] foo or Object @Nullable[] foo would make foo @Nullable. But, this would mean that if foo were intended to be a @NonNull reference to an array containing @Nullable Objects, a user could not write the correct annotation for this case (@Nullable Object[] foo) without adverse impacts from NullAway (since foo itself would then be treated as @Nullable). Such NullAway users would be forced to either not write the correct annotations for the nullability of array contents for now or to deal with references becoming unintentionally @Nullable (the latter seems worse). A similar issue is seen in #674 for varargs arrays. While this downside is unfortunate, it does match the behavior of NullAway before #702 landed.

    We could also just stick with requiring users to write type use nullability annotations for arrays in the right spot. But that kind of breaking change seems weird to introduce by accident, and I'm not sure of other unintended consequences. That seems like a change we should introduce deliberately and possibly behind a flag at first to let users adopt gradually.

    So, I think our best option is to handle inner type and array type use annotations in the same way for now, as inner types are currently being handled in this PR. I'm not sure about a combination of these, e.g., A.B.@Nullable C [][] foo = null;. This annotation does not make foo @Nullable under proper usage of type use annotations nor in a backward compatibility scenario. So I guess we can just treat foo as @NonNull for this case?

    The stop gap fix for the issues above implemented in #706 does the following:

    • Interpret an annotation on any inner or outer type of the field/argument declaration as annotating the field/argument itself (equivalently: as an annotation on the innermost inner type in proper type use annotation semantics)
    • Interpret an annotation on any sequence of array locations (including @Nullable Foo [][], Foo @Nullable [][], and Foo [] @Nullable []) as marking the array itself as being nullable.
    • We don't support type use annotations on generics or wildcards
    • We don't support type use annotations in locations that involve both inner classes and arrays (so, for A.B.C [] foo the only two valid places for the annotation are @Nullable A.B.C [] foo and A.B.C @Nullable [] foo)

    Still, this means we fail to correctly follow standard semantics for type use annotations, which will only get more confusing once we want to introduce JSpecify-like support for annotating the nullability of array elements.

    We should, relatively soon, introduce a breaking change intentionally that prevents adding @Nullable in the wrong position for arrays and inner types. To do this, we probably need to refactor some of our location parsing logic in NullabilityUtil to provide more information about what is being annotated/queried. We also want a reasonable UX for developers upgrading past this breaking change and/or switching between declaration and type use annotations at any point after the change (i.e. If possible, we should avoid a situation where changing the imports for @Nullable to a different annotation silently causes nullability to switch from applying to the array reference itself to applying to the elements! Though I am not whether we can do something here...)

    At any rate, the version introducing this breaking change should bump the "minor" release number, not the "patch" number (not that NullAway follows semver, per se)

    opened by lazaroclapp 0
  • Null propagation doesn't work between Java Stream operations

    Null propagation doesn't work between Java Stream operations

    A common pattern in some codebases is to filter streams by the keys of a map:

      private Stream<String> filterBasedOnMapKeys(Map<String, String> map, Stream<String> stream) {
        return stream
                .filter(map::containsKey)
                .map(value -> someMethod(map.get(value)));
      }
    

    This fails the null check, claiming that the method someMethod is being passed a nullable value when not null is required. However, as the stream has already been filtered, the .get(...) call is safe.

    opened by alxhill 7
  • Support StreamEx and EntryStream

    Support StreamEx and EntryStream

    StreamEx is a library that adds utility methods to streams in Java. The EntryStream class is particularly useful for using Maps with streams. For example:

    EntryStream.of(map)
        .filterKeys(key -> anotherMap.containsKey(key))
        .mapKeyValue((key, value) -> doSomething(value, anotherMap.get(key)))
        .toMap()
    

    Currently, NullAway complains that anotherMap.get() is nullable in spite of the containsKey filtering.

    Would this be suitable for a contribution? Any thoughts/guidance on how challenging it might be?

    opened by alxhill 2
  • Respect annotated AtomicReference's

    Respect annotated AtomicReference's

    In this example code, I've annotated my AtomicReference to show that it can never be null. However, NullAway still has a warning [NullAway] returning @Nullable expression from method with @NonNull return type. I believe this stems from https://github.com/uber/NullAway/blob/master/nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java#L618, which (based on my quick skim of the code) looks like it pre-annotates the AtomicReference::get method with @Nullable, even when that isn't necessarily true.

    Could NullAway consider supporting this better, or is there a good workaround here that I might be missing?

    import java.util.concurrent.atomic.AtomicReference;
    import org.checkerframework.checker.nullness.qual.NonNull;
    
    public final class MyClass {
    
        private final AtomicReference<@NonNull String> ref;
    
        MyClass() {
            ref = new AtomicReference<>("starting value");
        }
    
        public String getCurrentValue() {
            return ref.get(); // returning @Nullable expression from method with @NonNull return type
        }
    
        public void updateValue(@NonNull String newValue) {
            ref.set(newValue);
        }
    }
    

    Using nullaway 0.9.9 via https://github.com/palantir/gradle-baseline (cc @carterkozak @schlosna )

    jspecify 
    opened by lycarter 2
Owner
Uber Open Source
Open Source Software at Uber
Uber Open Source
mobsfscan is a static analysis tool that can find insecure code patterns in your Android and iOS source code.

mobsfscan is a static analysis tool that can find insecure code patterns in your Android and iOS source code. Supports Java, Kotlin, Swift, and Objective C Code. mobsfscan uses MobSF static analysis rules and is powered by semgrep and libsast pattern matcher.

Mobile Security Framework 347 Dec 29, 2022
Inria 1.4k Dec 29, 2022
Your Software. Your Structures. Your Rules.

jQAssistant Master Repository We splitted jQAssistant in multiple single repositories to be able to build a better and more flexible build an release

null 179 Dec 19, 2022
Astra: a Java tool for analysing and refactoring Java source code

What is Astra? Astra is a Java tool for analysing and refactoring Java source code. For example: "References to type A should instead reference type B

Alfa 51 Dec 26, 2022
SpotBugs is FindBugs' successor. A tool for static analysis to look for bugs in Java code.

SpotBugs is the spiritual successor of FindBugs, carrying on from the point where it left off with support of its community. SpotBugs is licensed unde

null 2.9k Jan 4, 2023
Catch common Java mistakes as compile-time errors

Error Prone Error Prone is a static analysis tool for Java that catches common programming mistakes at compile-time. public class ShortSet { public

Google 6.3k Dec 31, 2022
Reformats Java source code to comply with Google Java Style.

google-java-format google-java-format is a program that reformats Java source code to comply with Google Java Style. Using the formatter from the comm

Google 4.8k Dec 31, 2022
:coffee: SonarSource Static Analyzer for Java Code Quality and Security

Code Quality and Security for Java This SonarSource project is a code analyzer for Java projects. Information about the analysis of Java features is a

SonarSource 976 Jan 5, 2023
OpenGrok is a fast and usable source code search and cross reference engine, written in Java

Copyright (c) 2006, 2020 Oracle and/or its affiliates. All rights reserved. OpenGrok - a wicked fast source browser OpenGrok - a wicked fast source br

Oracle 3.8k Jan 8, 2023
Java library for parsing report files from static code analysis.

Violations Lib This is a Java library for parsing report files like static code analysis. Example of supported reports are available here. A number of

Tomas Bjerre 127 Nov 23, 2022
An extensible multilanguage static code analyzer.

PMD About PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and

PMD 4.1k Jan 2, 2023
A static analyzer for Java, C, C++, and Objective-C

Infer Infer is a static analysis tool for Java, C++, Objective-C, and C. Infer is written in OCaml. Installation Read our Getting Started page for det

Facebook 13.7k Dec 28, 2022
A free injection hacked client for Minecraft using Java-agents

Swift Swift is a free and open-source injection hacked client base for Minecraft using Java-agents. Issues If you notice any bugs, you can let us know

static final 36 Oct 8, 2022
Java bytecode static analyzer

This project is abandoned and unlikely will be supported in future HuntBugs 0.0.11 New Java bytecode static analyzer tool based on Procyon Compiler To

Tagir Valeev 302 Aug 13, 2022
Low-overhead, non-blocking I/O, external Process implementation for Java

NuProcess NuProcess is proud to power Facebook's Buck build. A low-overhead, non-blocking I/O, external Process execution implementation for Java. It

Brett Wooldridge 644 Dec 29, 2022
Slicer4J is an accurate, low-overhead dynamic slicer for Java programs.

Slicer4J This repository hosts Slicer4J, an accurate, low-overhead dynamic slicer for Java programs. Slicer4J automatically generates a backward dynam

The Reliable, Secure, and Sustainable Software Lab 25 Dec 19, 2022
Easy to use, very low overhead, Java APM

Glowroot Requirements Java 8+ Quick start Download and unzip glowroot-0.14.0-beta.2-dist.zip Add -javaagent:path/to/glowroot.jar to your application's

null 1.1k Dec 14, 2022
Business Application Platform - no-code/low-code platform to build business applications

Orienteer What is Orienteer Orienteer is Business Application Platform: Easy creation of business applications Extendable to fit your needs Dynamic da

Orienteer 189 Dec 6, 2022