Giter Site home page Giter Site logo

uber / nullaway Goto Github PK

View Code? Open in Web Editor NEW
3.5K 67.0 282.0 5.01 MB

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

License: MIT License

Java 99.79% Shell 0.05% Python 0.16%
java static-analysis android nullability nullability-analysis static-code-analysis

nullaway's Introduction

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."

Installation

Overview

NullAway requires that you build your code with Error Prone, version 2.10.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 "<plugin version>"
}

dependencies {
  errorprone "com.uber.nullaway:nullaway:<NullAway version>"

  // 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:<Error Prone version>"
}

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.

In dependencies, the first errorprone 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 second errorprone line sets the version of Error Prone is used.

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. For even simpler configuration of NullAway options, use the Gradle NullAway plugin.

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

Versions 3.0.0 and later of the Gradle Error Prone Plugin no longer support Android. So if you're using a recent version of this plugin, you'll need to add some further configuration to run Error Prone and NullAway. Our sample app build.gradle file shows one way to do this, but your Android project may require tweaks. Alternately, 2.x versions of the Gradle Error Prone Plugin still support Android and may still work with your project.

Beyond that, compared to the Java configuration, 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 instead.

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.1.3 (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:

lombok.addLombokGeneratedAnnotation = true

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.

nullaway's People

Contributors

akulk022 avatar armughan11 avatar carterkozak avatar crispy-fried-chicken avatar david-gang avatar joschi avatar kageiit avatar kjim avatar lazaroclapp avatar lycheeicy avatar mdcfe avatar mernst avatar michaelhixson avatar msridhar avatar navahgar avatar nikitaaware avatar nimakarimipour avatar oliviernotteghem avatar pablogrisafi1975 avatar shtke avatar shubhamugare avatar sparky983 avatar subarnob avatar tbroyer avatar uhafner avatar xn137 avatar yanislavm avatar ybroeker avatar yuxincs avatar zacsweers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nullaway's Issues

Is there a way to reverse the default assumption about nullability?

Couldn't find this anywhere in the doco, so I'm assuming no... but thought I'd ask the question. I have a couple of quite large code bases that pretty much assume all fields and parameters are nullable. Eg they have null checks already for everything. There have lots of hibernate and json model objects while have to have empty constructors and null initialised fields.
For these existing code bases, it seems it would be a lot less annotation effort to reverse the assumption and assume @nullable by default. Then the checker would pick up non checked uses straight away, and we could gradually add @nonnull annotations.
As it is, its going to be too big a task (currently 5k+ combined NullAway and ErrorProne warnings on one of the code bases) to get this happening.

latest checker dataflow failing on try-finally

I get a crash when computing a dataflow graph for this code:

    static Object tryFinally() {
        Object x = new Object();
        try {
            return new Object();
        } finally {
            if (x != null) {
                return x;
            }
        }
    }

Top of the stack:

 Caused by: java.lang.NoSuchFieldError: operator
  	at org.checkerframework.javacutil.trees.FullyTreeCopier.visitBinary(FullyTreeCopier.java:67)
  	at org.checkerframework.javacutil.trees.FullyTreeCopier.visitBinary(FullyTreeCopier.java:40)
  	at com.sun.tools.javac.tree.JCTree$JCBinary.accept(JCTree.java:1993)
  	at com.sun.tools.javac.tree.TreeCopier.copy(TreeCopier.java:61)
  	at org.checkerframework.javacutil.trees.FullyTreeCopier.copy(FullyTreeCopier.java:48)
  	at org.checkerframework.javacutil.trees.FullyTreeCopier.copy(FullyTreeCopier.java:40)
  	at com.sun.tools.javac.tree.TreeCopier.visitParenthesized(TreeCopier.java:333)
  	at com.sun.tools.javac.tree.TreeCopier.visitParenthesized(TreeCopier.java:45)
  	at com.sun.tools.javac.tree.JCTree$JCParens.accept(JCTree.java:1849)
  	at com.sun.tools.javac.tree.TreeCopier.copy(TreeCopier.java:61)
  	at org.checkerframework.javacutil.trees.FullyTreeCopier.copy(FullyTreeCopier.java:48)
  	at org.checkerframework.javacutil.trees.FullyTreeCopier.copy(FullyTreeCopier.java:40)
  	at com.sun.tools.javac.tree.TreeCopier.visitIf(TreeCopier.java:238)
  	at com.sun.tools.javac.tree.TreeCopier.visitIf(TreeCopier.java:45)

Might be a bad interaction with JDK 9 javac. If we can't find an easy workaround, may have to revert back to 2.1.14.

Recognize JUnit 5's @BeforeAll and @BeforeEach as initializers

NullAway should recognize JUnit 5's @BeforeAll and @BeforeEach as initializer annotations by default. Currently it recognizes JUnit 4's @Before and @BeforeClass, but in JUnit 5 these were renamed:

Since you provided the CustomInitializerAnnotations option, users can work around this by passing an argument to javac:

-XepOpt:NullAway:CustomInitializerAnnotations=org.junit.jupiter.api.BeforeAll,org.junit.jupiter.api.BeforeEach

...but I think it makes sense to support this by default so users don't have to do that.

Resolving this issue should be a matter of changing these lines:

static final ImmutableSet<String> DEFAULT_INITIALIZER_ANNOT =
ImmutableSet.of(
"org.junit.Before",
"org.junit.BeforeClass"); // + Anything with @Initializer as its "simple name"

to this:

static final ImmutableSet<String> DEFAULT_INITIALIZER_ANNOT =
    ImmutableSet.of(
        "org.junit.Before",
        "org.junit.BeforeClass",
        "org.junit.jupiter.api.BeforeAll",
        "org.junit.jupiter.api.BeforeEach");

Adding test cases could be awkward since you'd need to bring in a JUnit 5 dependency probably? Or you could not add tests.

basic support for checking @NonNull fields not used before initialization

Right now, NullAway does not check that a @NonNull field is initialized before it is used. We should add some basic checking of this property to account for common cases. I propose the following:

  • We check field reads in initializer blocks and constructors. We do not check field reads in methods invoked from blocks / constructors or in other initializer methods.
  • For a relevant read of field f, we check that f has been assigned on all control-flow paths leading to that read. We should be able to incorporate some inter-procedural information here, as we already compute it to check that @NonNull field are initialized somewhere.

I think the above should involve just some small enhancements to our existing dataflow analysis (basically, exporting facts from any program point, not just returns, plus sucking in the interprocedural stuff).

support models of generic types

As a baby step toward support of generics, we should support writing models of generic library types and checking uses of those types against the models. E.g., for a Pair<S, T> type, we should be able to write a model indicating the type is really Pair<@PolyNull S, @PolyNull T> and then allowing app code to write, e.g., Pair<@Nullable String, String>. We would not initially check that the implementation of the Pair class respects the model. Depending on implementation difficulty of figuring out how generic types are instantiated, we may require the models to be more or less explicit.

Support annotation of guard methods

When adding NullAway, I receive a false positive. The failing branch is only executed if the non-null and this check is delegated to another method.

error: [NullAway] dereferenced expression future is @Nullable
    return isReady(future) ? future.join() : null;
/** Returns if the future has successfully completed. */
static boolean isReady(@Nullable CompletableFuture<?> future) {
  return (future != null) && future.isDone()
      && !future.isCompletedExceptionally()
      && (future.join() != null);
}

/** Returns the current value or null if either not done or failed. */
static @Nullable <V> V getIfReady(@Nullable CompletableFuture<V> future) {
  return isReady(future) ? future.join() : null;
}

Check for read before init for a single `@Initializer` method

Follow-on to #57. When a class has a single @Initializer method, we know it runs after all the initializer blocks / constructors. So, we should be able to check that in the @Initializer no @NonNull fields are read unless they were already initialized locally or in some constructor / initializer block. With multiple @Initializer methods we don't know what order they run in, so less checking is possible.

better error message when an initializer sometimes writes a field

Consider:

Class Foo {
  Object f;
  @Initializer
  void init() {
    if (someCond()) {
      return;
    }
    f = new Object();
  }
}

For this code, we give an error message saying that init() does not initialize f, but it's a bit confusing since the method does write f. Ideally, we'd give a clearer message indicating that init() does not initialize f on all control-flow paths.

Handling single expression lambdas with `void` return type

It looks like even with a single-expression lambda has a void return type, we are still checking the nullability of the single expression as if it were getting returned. Don't have a small test case yet, will work on it. Just want to record here so we don't forget

Gradle error when adding NullAway 0.1.7 to Android projects

I'm getting the gradle build error when adding NullAway version 0.1.7 to different projects in Android Studio 3.0 and gradle plugin version 3.0.0.

Commenting out

annotationProcessor "com.uber.nullaway:nullaway:0.1.7"

leads to successful build.

Project level build.gradle:

buildscript {
...
    repositories {
        jcenter()
        google()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'
        classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.11"
    }
}
...

App level build.gradle:

apply plugin: 'com.android.application'
apply plugin: 'net.ltgt.errorprone'

project.ext {
    supportLibraryVersion = "25.4.0"
    daggerVersion = "2.11"
    butterKnifeVersion = "8.7.0"
    rxJavaVersion = "2.1.0"
    rxAndroidVersion = "2.0.1"
    timberVersion = "4.5.1"
    lifecycleVersion = "1.0.0-alpha4"
    priorityJobQueueVersion = "2.0.1"
    playServicesVersion = "11.4.2"
    retrofitVersion = "2.1.0"
    okHttpVersion = "3.4.1"
    rxRelayVersion = "2.0.0"
    rxLintVersion = "1.6"
}

android {
    compileSdkVersion 25
    defaultConfig {
        applicationId "com.example.offline"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    lintOptions {
        abortOnError false
    }
}

dependencies {
    implementation "com.android.support:appcompat-v7:$project.supportLibraryVersion"

    // Dagger core
    annotationProcessor "com.google.dagger:dagger-compiler:$project.daggerVersion"
    implementation "com.google.dagger:dagger:$project.daggerVersion"

    // Dagger Android
    annotationProcessor "com.google.dagger:dagger-android-processor:$project.daggerVersion"
    implementation "com.google.dagger:dagger-android-support:$project.daggerVersion"

    // ButterKnife
    implementation "com.jakewharton:butterknife:$project.butterKnifeVersion"
    annotationProcessor "com.jakewharton:butterknife-compiler:$project.butterKnifeVersion"

    // ReactiveX
    implementation "io.reactivex.rxjava2:rxjava:$project.rxJavaVersion"
    implementation "io.reactivex.rxjava2:rxandroid:$project.rxAndroidVersion"

    // Timber
    implementation "com.jakewharton.timber:timber:$project.timberVersion"

    // Priority Job Queue
    implementation "com.birbit:android-priority-jobqueue:$project.priorityJobQueueVersion"

    //GCM Network Manager
    implementation "com.google.android.gms:play-services-gcm:$project.playServicesVersion"

    // RecyclerView
    implementation "com.android.support:recyclerview-v7:$project.supportLibraryVersion"

    // Retrofit
    implementation "com.squareup.retrofit2:retrofit:$project.retrofitVersion"

    // GSON Converter
    implementation "com.squareup.retrofit2:converter-gson:$project.retrofitVersion"

    // OkHttp Logging Interceptor
    implementation "com.squareup.okhttp3:okhttp:$project.okHttpVersion"
    implementation "com.squareup.okhttp3:logging-interceptor:$project.okHttpVersion"

    // Room Database
    implementation "android.arch.persistence.room:runtime:$rootProject.roomVersion"
    implementation "android.arch.persistence.room:rxjava2:$rootProject.roomVersion"
    annotationProcessor "android.arch.persistence.room:compiler:$rootProject.roomVersion"

    // Lifecycle
    implementation "android.arch.lifecycle:runtime:$project.lifecycleVersion"
    implementation "android.arch.lifecycle:extensions:$project.lifecycleVersion"
    annotationProcessor "android.arch.lifecycle:compiler:$project.lifecycleVersion"

    // RxRelay
    implementation "com.jakewharton.rxrelay2:rxrelay:$project.rxRelayVersion"

    // RxLint
    implementation "nl.littlerobots.rxlint:rxlint:$project.rxLintVersion"

    //Nullaway
    annotationProcessor "com.uber.nullaway:nullaway:0.1.7"
    compileOnly "com.google.code.findbugs:jsr305:3.0.2"
    errorprone "com.google.errorprone:error_prone_core:2.1.2"

}

tasks.withType(JavaCompile) {
    if (!name.toLowerCase().contains("test")) {
        options.compilerArgs += ["-Xep:NullAway:ERROR", "-XepOpt:NullAway:AnnotatedPackages=com.example"]
    }
}

Error stacktrace

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:compileDebugJavaWithJavac'.
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
	at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
	at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
	at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
	at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
	at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
	at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
	at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
	at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
	at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: org.gradle.internal.UncheckedException: java.lang.reflect.InvocationTargetException
	at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:63)
	at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:40)
	at net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:75)
	at net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:24)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:99)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:52)
	at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
	at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35)
	at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalCompilationFinalizer.execute(IncrementalCompilationFinalizer.java:39)
	at org.gradle.api.internal.tasks.compile.incremental.IncrementalCompilationFinalizer.execute(IncrementalCompilationFinalizer.java:24)
	at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:204)
	at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:130)
	at com.android.build.gradle.tasks.factory.AndroidJavaCompile.compile(AndroidJavaCompile.java:95)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
	at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$IncrementalTaskAction.doExecute(DefaultTaskClassInfoStore.java:179)
	at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:135)
	at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:122)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:121)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
	at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:110)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
	... 28 more
Caused by: java.lang.reflect.InvocationTargetException
	at net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:63)
	... 50 more
Caused by: java.lang.RuntimeException: java.lang.NoClassDefFoundError: org/openjdk/source/tree/Tree
	at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:158)
	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 com.google.errorprone.ErrorProneCompiler.compile(ErrorProneCompiler.java:65)
	... 51 more
Caused by: java.lang.NoClassDefFoundError: org/openjdk/source/tree/Tree
	at com.google.googlejavaformat.java.filer.FormattingFiler.<init>(FormattingFiler.java:37)
	at com.google.googlejavaformat.java.filer.FormattingFiler.<init>(FormattingFiler.java:42)
	at dagger.internal.codegen.ComponentProcessor.initSteps(ComponentProcessor.java:66)
	at dagger.shaded.auto.common.BasicAnnotationProcessor.init(BasicAnnotationProcessor.java:119)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment$ProcessorState.<init>(JavacProcessingEnvironment.java:675)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator.next(JavacProcessingEnvironment.java:774)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:869)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$2200(JavacProcessingEnvironment.java:108)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1204)
	at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1313)
	at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1267)
	at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:943)
	at com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:100)
	at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:142)
	... 57 more
Caused by: java.lang.ClassNotFoundException: org.openjdk.source.tree.Tree
	... 71 more

UnannotatedSubPackages option doesn't work correctly.

Reddit user u/rakingleaves recommended that I raise this issue here.

I'm trying to get NullAway working in my existing, large Android app. I've already had ErrorProne working for some time.

My intended approach was to enable NullAway one package at a time so I can add the necessary Nullable annotations gradually (and convince the rest of my dev team of the benefit of doing so). So I was trying to exclude all sub packages at first, then remove one at a time from the UnannotatedSubPackages option as I fix them up. But I just cannot get the UnannotatedSubPackages config to work.

This is the relevant snippet from my build.gradle. The network.xmpp package gets excluded correctly but the service.contacts package still throws up warnings. I've tried putting other packages in the list. Some get filtered out, most don't.

afterEvaluate {
    android.applicationVariants.each {
        it.javaCompiler.toolChain ErrorProneToolChain.create(project)
        it.javaCompiler.options.compilerArgs.addAll()

        if (!name.toLowerCase().contains("test")) {
            it.javaCompiler.options.compilerArgs += [
                "-Xep:NullAway:WARN",
                "-XepOpt:NullAway:AnnotatedPackages=com.mydomain.myapp",
                "-XepOpt:NullAway:UnannotatedSubPackages=com.mydomain.myapp.network.xmpp,com.mydomain.myapp.service.contacts"
            ]
        }
    }

Versions:

errorProne : '2.1.1',
nullAway : '0.1.6',

@LazyInit not respected

If you use Error-Prone's @LazyInit annotation, nullaway still flags it as an error

warning: [NullAway] @NonNull field header not initialized
    @LazyInit private transient TeamHeader header;
                                           ^
    (see http://t.uber.com/nullaway )

IndexOutOfBoundsException on ForwardingCollection.java in guava.

IndexOutOfBoundsException on ForwardingCollection.java (https://github.com/google/guava/blob/master/guava/src/com/google/common/collect/ForwardingCollection.java#L120)

src/main/java/com/google/common/collect/ForwardingCollection.java:120: error: An unhandled exception was thrown by the Error Prone static analysis plugin.
return delegate().toArray();
^
Please report this at https://github.com/google/error-prone/issues/new and include the following:

 error-prone version: 2.1.1
 Stack Trace:
 java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at com.sun.tools.javac.util.List.get(List.java:490)
at com.uber.nullaway.NullAway.handleInvocation(NullAway.java:987)
at com.uber.nullaway.NullAway.matchMethodInvocation(NullAway.java:297)
at com.google.errorprone.scanner.ErrorProneScanner.visitMethodInvocation(ErrorProneScanner.java:907)
at com.google.errorprone.scanner.ErrorProneScanner.visitMethodInvocation(ErrorProneScanner.java:146)
at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1644)
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.visitReturn(TreeScanner.java:469)
at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:1021)
at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:146)
at com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1548)
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.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:145)
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:1384)
at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1523)
at com.sun.tools.javac.main.JavaCompiler.desugar(JavaCompiler.java:1439)
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 com.google.errorprone.ErrorProneCompiler.compile(ErrorProneCompiler.java:65)
at org.codehaus.plexus.compiler.javac.errorprone.JavacCompilerWithErrorProne$CompilerInvoker.compile(JavacCompilerWithErrorProne.java:219)
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:884)
at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:129)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
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.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)

getFunctionalInterfaceMethod() fails to recognize method override

On the latest master (f31a2f7). Here's a patch to produce a failing test:

diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java
index e318ff0..1863775 100644
--- a/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java
+++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java
@@ -139,4 +139,9 @@ public class NullAwayTest {
     public void functionalMethodSuperInterface() {
         compilationHelper.addSourceFile("NullAwaySuperFunctionalInterface.java").doTest();
     }
+
+    @Test
+    public void functionalMethodOverrideSuperInterface() {
+        compilationHelper.addSourceFile("NullAwayOverrideFunctionalInterfaces.java").doTest();
+    }
 }
diff --git a/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayOverrideFunctionalInterfaces.java b/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayOverrideFunctionalInterfaces.java
index e69de29..9383bef 100644
--- a/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayOverrideFunctionalInterfaces.java
+++ b/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwayOverrideFunctionalInterfaces.java
@@ -0,0 +1,27 @@
+package com.uber.nullaway.testdata;
+
+import java.util.function.ToIntFunction;
+
+public class NullAwayOverrideFunctionalInterfaces {
+
+    public void test() {
+        call(str -> 42);
+    }
+
+    private int call(ObjToInt<String> f) {
+        return f.call("The answer to life the universe and everything");
+    }
+
+    @FunctionalInterface
+    private static interface ObjToInt<T> extends ObjToIntE<T, RuntimeException>, ToIntFunction<T> {
+        @Override
+        default int applyAsInt(T t) {
+            return call(t);
+        }
+    } 
+
+    @FunctionalInterface
+    private static interface ObjToIntE<T, E extends Exception> {
+        int call(T t) throws E;
+    }
+}

Here's the relevant portion of the error stacktrace:

java.lang.AssertionError: An unhandled exception was thrown by the Error Prone static analysis plugin.
     Please report this at https://github.com/google/error-prone/issues/new and include the following:
  
     error-prone version: 2.1.1
     Stack Trace:
     java.lang.RuntimeException: already found an answer! call(T) applyAsInt(T) applyAsInt(T)
  	at com.uber.nullaway.NullabilityUtil.getFunctionalInterfaceMethod(NullabilityUtil.java:87)
  	at com.uber.nullaway.NullAway.matchLambdaExpression(NullAway.java:422)

Analysis failure on boxing of `UNARY_MINUS` expression

Consider the following code:

final class Container {
    private void sender() {
        int someValue = 0;
        receiver(-someValue);
    }

    private void receiver(Integer i) {
        /* NOP */
    }
}

Analyzing this code with NullAway 0.1.6 inside Error Prone 2.1.1 yields:

java.lang.RuntimeException: whoops, better handle UNARY_MINUS -someValue
 	at com.uber.nullaway.NullAway.mayBeNullExpr(NullAway.java:1075)
 	at com.uber.nullaway.NullAway.handleInvocation(NullAway.java:644)
 	at com.uber.nullaway.NullAway.matchMethodInvocation(NullAway.java:262)
 	at com.google.errorprone.scanner.ErrorProneScanner.visitMethodInvocation(ErrorProneScanner.java:907)
 	at com.google.errorprone.scanner.ErrorProneScanner.visitMethodInvocation(ErrorProneScanner.java:146)
 	at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1644)
 	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.visitExpressionStatement(TreeScanner.java:433)
 	at com.google.errorprone.scanner.ErrorProneScanner.visitExpressionStatement(ErrorProneScanner.java:713)
 	at com.google.errorprone.scanner.ErrorProneScanner.visitExpressionStatement(ErrorProneScanner.java:146)
 	at com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1454)
 	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:145)
 	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)

The issue is also triggered if someValue is replaced with another int or Integer-typed non-constant expression such as a method invocation. The issue is not triggered if receiver's signature is updated such that the method accepts a primitive int.

Unhelpful errors when running `./gradlew build` on broken code

Currently, running ./gradlew build when compilation is broken for any reason, results in a large and opaque error such as:

> Task :sample:compileJava
An exception has occurred in the compiler (1.8.0_131). 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.util.ServiceConfigurationError: com.google.errorprone.bugpatterns.BugChecker: Error reading configuration file
        at java.util.ServiceLoader.fail(ServiceLoader.java:232)
        at java.util.ServiceLoader.parse(ServiceLoader.java:309)
        at java.util.ServiceLoader.access$200(ServiceLoader.java:185)
        at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:357)
        at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:393)
        at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474)
        at com.google.common.collect.Iterables.isEmpty(Iterables.java:1056)
        at com.google.errorprone.ErrorPronePlugins.loadPlugins(ErrorPronePlugins.java:49)
        at com.google.errorprone.ErrorProneAnalyzer.lambda$scansPlugins$0(ErrorProneAnalyzer.java:73)
        at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers.java:160)
        at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:145)
        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 com.google.errorprone.ErrorProneCompiler.compile(ErrorProneCompiler.java:65)
        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 net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:63)
        at net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:24)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:99)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:52)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
        at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35)
        at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
        at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:198)
        at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:183)
        at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:120)
        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.reflect.JavaMethod.invoke(JavaMethod.java:73)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$IncrementalTaskAction.doExecute(DefaultTaskClassInfoStore.java:173)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:121)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:122)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:111)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:63)
        at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
        at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:124)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:80)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:105)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:99)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:99)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.FileNotFoundException: JAR entry META-INF/services/com.google.errorprone.bugpatterns.BugChecker not found in /Users/lazaro/NullAway/nullaway/build/libs/nullaway-0.1.3-SNAPSHOT.jar
        at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:142)
        at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:150)
        at java.net.URL.openStream(URL.java:1045)
        at java.util.ServiceLoader.parse(ServiceLoader.java:304)
        ... 80 more

Whereas doing:

cd nullaway
gradle build

Gives out proper error messages. Is there a way to surface those when building from the projects root?

Consider inheritance when checking models

We should be able to leverage inheritance when writing models for librarys. E.g., Collections.toArray(T[]) is specified to throw an NPE whenever the parameter is null. Right now, we need to add a model for Collections.toArray, ArrayDeque.toArray, LinkedList.toArray, etc. to get full safety. It'd be nice to just add a model for Collections.toArray and then catch this for any overriding method. Would need to be careful about performance when implementing this.

Create a script to benchmark NullAway

As suggested here we should create a script / harness to benchmark NullAway and detect performance regressions. We could use jmh and try to put something together that runs NullAway on some representative benchmark.

Check when unnecessarily suppressed

As project code evolves and as this checker's false positives are squashed, some suppressions will no longer be needed. That could then lead to new scenarios going uncaught because a stale suppression remains, but a new NPE is introduced. For code health, it would be good to be optionally stricter about suppressions.

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

NullAway does not recognize null-check methods properly

Code example:

public class Example {
    @Nullable
    private String text;

    @NonNull
    public String getText() {
        // NullAway raises error here
        return StringUtils.isEmptyOrNull(text) ? "Hello World!" : text;
    }
}

// isEmptyOrNull method
public static boolean isEmptyOrNull(@Nullable final CharSequence value) {
    return value == null || value.length() == 0;
}

Error message says

Error:(50, 13) error: [NullAway] returning @Nullable expression from method with @NonNull return type
(see http://t.uber.com/nullaway )

Error is gone when I inline isEmptyOrNull method call.

NullAway version is 0.1.7.

False positive when setting a variable within a condition

In this case the code is derived from j.u.c.atomic.Striped64 so the style is retained. If setting the variable is extracted to buffers = table prior to the condition, then this error does not appear.

error: [NullAway] dereferenced expression buffers is @Nullable
      if (((buffers = table) != null) && ((n = buffers.length) > 0)) {

Does not compile with Parceler lib - @Parcel implementation annotation

Hi,

I tried to use NullAway in a project with no success. My problem was related to the Parceler library.

  • If I remove NullAway, my project compiles and works fine.
  • If I remove the implementation = {MyClassRealmProxy.class} in the @Parcel declaration on my model, the project compiles and NullAway works.

I tried to use this configuration with no success to ignore generated classes ($$Parcelable) :

options.compilerArgs += [
            "-Xep:NullAway:ERROR",
            "-XepOpt:NullAway:AnnotatedPackages=com.test.nullaway",
            "-XepOpt:NullAway:ExcludedClassAnnotations=org.parceler.Generated"
]

The error

error: Parceler: Code generation did not complete successfully.
  org.parceler.transfuse.transaction.TransactionRuntimeException: Encountered ErrorType <error>, unable to recover

How to reproduce ?

I made a project to demonstrate the problem. You can clone it and try to build it : https://github.com/tspoke/nullaway-parceler

This demo project use Parceler and Realm.

Create a sample android app?

I believe the README is missing something for Android. I tried to follow the instructions and found the following crash.

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':demos:memory-leaks:compileDebugJavaWithJavac'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:98)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:68)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
        at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:236)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:228)
        at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:228)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:215)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:77)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:58)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:46)
Caused by: org.gradle.internal.UncheckedException: java.lang.reflect.InvocationTargetException
        at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:45)
        at net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:75)
        at net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:24)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:99)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:52)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:37)
        at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:35)
        at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
        at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:244)
        at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:229)
        at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:151)
        at com.android.build.gradle.tasks.factory.AndroidJavaCompile.compile(AndroidJavaCompile.java:49)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$IncrementalTaskAction.doExecute(DefaultTaskClassInfoStore.java:163)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
        at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:123)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.execute(ExecuteActionsTaskExecuter.java:115)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.execute(ExecuteActionsTaskExecuter.java:109)
        at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:109)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:90)
        ... 20 more
Caused by: java.lang.reflect.InvocationTargetException
        at net.ltgt.gradle.errorprone.ErrorProneCompiler.execute(ErrorProneCompiler.java:63)
        ... 41 more
Caused by: java.lang.RuntimeException: java.lang.NoClassDefFoundError: org/openjdk/source/tree/Tree
        at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:158)
        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 com.google.errorprone.ErrorProneCompiler.compile(ErrorProneCompiler.java:65)
        ... 42 more
Caused by: java.lang.NoClassDefFoundError: org/openjdk/source/tree/Tree
        at com.google.googlejavaformat.java.filer.FormattingFiler.<init>(FormattingFiler.java:37)
        at com.google.googlejavaformat.java.filer.FormattingFiler.<init>(FormattingFiler.java:42)
        at dagger.internal.codegen.ComponentProcessor.initSteps(ComponentProcessor.java:66)
        at dagger.shaded.auto.common.BasicAnnotationProcessor.init(BasicAnnotationProcessor.java:119)
        at com.sun.tools.javac.processing.JavacProcessingEnvironment$ProcessorState.<init>(JavacProcessingEnvironment.java:675)
        at com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator.next(JavacProcessingEnvironment.java:774)
        at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:869)
        at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$2200(JavacProcessingEnvironment.java:108)
        at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1204)
        at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1313)
        at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1267)
        at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:943)
        at com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:100)
        at com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:142)
        ... 48 more
Caused by: java.lang.ClassNotFoundException: org.openjdk.source.tree.Tree
        ... 62 more

Might be worthwhile to create an Android sample app that engineers can copy-and-paste.

Support @CheckForNull annotation

error: [NullAway] method returns @Nullable, but superclass method com.github.benmanes.caffeine.cache.AsyncLoadingCache.getIfPresent(java.lang.Object) returns @NonNull
  public @Nullable CompletableFuture<V> getIfPresent(@Nonnull Object key) {

However, this method is annotated with @CheckForNull which should implicitly mean @Nullable.

False positive on constructor that throws exception

If the construction fails with an exception then the object fields will not be set, as the object is never instantiated. However, the checker enforces that the fields are set regardless. While non-precondition exceptions from constructors are a bad idiom, sometimes oddities in 3rd party libraries have to be worked around.

Foo(...) {
  Bar = ...
  try {
    this.baz = bar.baz();
  finally {
    bar.close();
  }
}
error: [NullAway] initializer method does not guarantee @NonNull fields cache, policyStats are 
initialized along all control-flow paths (remember to check for exceptions or early returns).

support ParametersAreNonnullByDefault

We should look into supporting this annotation, which often appears at the package level. If calling a method in an unannotated package, we could check if a ParametersAreNonnullByDefault annotation is present, and if so do stronger checking on the parameter passing.

Create a sample library model

We should write a sample library model, to illustrate how others can add their own library models. The sample app can leverage this library model, to show how it should be used. (See #51)

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

Why not using kotlin so far ??

Thanks for using NullAway. Before you create an issue, please consider the following points:

  • If you think you found a bug, please include a code sample that reproduces the problem. A test case that reproduces the issue is preferred. A stack trace alone is ok but may not contain enough context for us to address the issue.

  • Please include the library version number, including the minor and patch version, in the issue text.

Analysis Fails On Conditional Initialization

void method(@Nullable Dep dep1, @Nullable Dep dep2) {
  Thing thing = null;
  if (dep1 == null || dep2 == null) {
    thing = new Thing();
  }
  if (dep1 == null) {
  // Passing thing as a parameter to a @NonNull API causes NullAway to report a nullability error 
  }
  if (dep2 == null) {
  // Passing thing as a parameter to a @NonNull API causes NullAway to report a nullability error 
  }
}

In the example above dep1 and dep2 are both nullable. If they're both present I want them to share the same thing. If neither are present I don't want to instantiate thing.

Create a snapshot version on mvn repository?

Do you plan to create a snapshot version on the maven repository?

I believe that there must some way to setup building guava with the trunk of NullAway. However, I know nothing about maven, and it seems using the snapshot version is the easiest way.

Thank you.

False positive with field nullability stored in local variable

In this case, a @Nullable field is stored to a local variable. When the field is used in a null condition an error occurs, but if the variable is used then it does not. It seems the data flow analysis does not realize they are the same.

error: [NullAway] returning @Nullable expression from method with @NonNull return type
    return (writer == null) ? CacheWriter.disabledWriter() : castedWriter;
    ^
<K1 extends K, V1 extends V> CacheWriter<K1, V1> getCacheWriter() {
  @SuppressWarnings("unchecked")
  CacheWriter<K1, V1> castedWriter = (CacheWriter<K1, V1>) writer;
  return (writer == null) ? CacheWriter.disabledWriter() : castedWriter;
}

false positive result on fields injected using Dagger

Version : 0.1.6

I've a lot of Android component classes where I use Dagger field injection. Getting error while running NullAway on them :

warning: [NullAway] @NonNull field <fieldName> not initialized.

Am I missing some parameter to pass to error prone?

NullAway can't tell when the same if test is used to protect access to a member variable

This is a simplified example because I can't share my code.

NullAway doesn't seem able to spot that this code is OK and reports

error: [NullAway] initializer method does not guarantee @nonnull fields mSomeString are initialized along all control-flow paths (remember to check for exceptions or early returns).

Obviously I could annotate mSomeString with @nullable but then I have to add a null check in someMethodUsedLater which I'd prefer to avoid. Maybe I just have to live with doing that?

This is an Android Activity.

private String mSomeString;

@Override
public void onCreate()
{
    super.onCreate();

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
    {
        mSomeString = "SOMETHING";
    }
}

private someMethodUsedLater
{       
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
    {
        int someValue = mSomeString.length();
    }
}

getFunctionalInterfaceMethod() doesn't check super-interfaces

On the latest master (5177099). Here's a patch to produce a failing test:

diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java
index 43419a6..e318ff0 100644
--- a/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java
+++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java
@@ -134,4 +134,9 @@ public class NullAwayTest {
     public void rxSupportNegativeCases() {
         compilationHelper.addSourceFile("NullAwayRxSupportNegativeCases.java").doTest();
     }
+
+    @Test
+    public void functionalMethodSuperInterface() {
+        compilationHelper.addSourceFile("NullAwaySuperFunctionalInterface.java").doTest();
+    }
 }
diff --git a/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwaySuperFunctionalInterface.java b/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwaySuperFunctionalInterface.java
index e69de29..5d69c07 100644
--- a/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwaySuperFunctionalInterface.java
+++ b/nullaway/src/test/resources/com/uber/nullaway/testdata/NullAwaySuperFunctionalInterface.java
@@ -0,0 +1,20 @@
+package com.uber.nullaway.testdata;
+
+public class NullAwaySuperFunctionalInterface {
+
+    public void foo() {
+        go(() -> {});
+    }
+
+    private void go(Foo foo) {
+        foo.call();
+    }
+
+    @FunctionalInterface
+    private static interface Foo extends Bar {} 
+
+    @FunctionalInterface
+    private static interface Bar {
+        void call();
+    }
+}

Here's the relevant portion of the error stacktrace:

java.lang.AssertionError: An unhandled exception was thrown by the Error Prone static analysis plugin.
     Please report this at https://github.com/google/error-prone/issues/new and include the following:
  
     error-prone version: 2.1.1
     Stack Trace:
     java.lang.RuntimeException: could not find functional interface method in 
  	at com.uber.nullaway.NullabilityUtil.getFunctionalInterfaceMethod(NullabilityUtil.java:87)
  	at com.uber.nullaway.NullAway.matchLambdaExpression(NullAway.java:422)
        ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.