From fbeb58c0f286489f01bcffe41780b1aab564b920 Mon Sep 17 00:00:00 2001 From: Mitya Lyubarskiy Date: Tue, 10 Sep 2019 09:52:40 -0700 Subject: [PATCH] [nullafe] Consolidate different ways to suppress field not initialized Summary: See title Reviewed By: artempyanykh Differential Revision: D17281701 fbshipit-source-id: 5a2775f3e --- .../nullsafe-default/FieldNotInitialized.java | 47 +++++++++++++------ .../SuppressedFieldNotInitializedExample.java | 28 ----------- .../java/nullsafe-default/issues.exp | 17 ++++--- 3 files changed, 42 insertions(+), 50 deletions(-) delete mode 100644 infer/tests/codetoanalyze/java/nullsafe-default/SuppressedFieldNotInitializedExample.java diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotInitialized.java b/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotInitialized.java index 640022cfb..97586b388 100644 --- a/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotInitialized.java +++ b/infer/tests/codetoanalyze/java/nullsafe-default/FieldNotInitialized.java @@ -7,11 +7,13 @@ package codetoanalyze.java.nullsafe_default; +import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.support.annotation.NonNull; import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Initializer; +import com.facebook.infer.annotation.SuppressFieldNotInitialized; import com.facebook.infer.annotation.SuppressViewNullability; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -22,29 +24,44 @@ import javax.inject.Inject; public class FieldNotInitialized { - String notNullIsBAD; // BAD: need to initialize it + // different ways to suppress the error + class Suppression { + String notNullIsBAD; // BAD: need to initialize it - @Nonnull String nonnullIsBAD; // BAD: explicit annotation does not make it better + @Nonnull String nonnullIsBAD; // BAD: explicit annotation does not make it better - @NonNull String nonNullIsBAD; // BAD: explicit annotation does not make it better + @NonNull String nonNullIsBAD; // BAD: explicit annotation does not make it better - @Nullable String nullableIsOK; // OK: will be init with null + @Nullable String nullableIsOK; // OK: will be init with null - @Inject String injectIsOK; // Means: assume it will be initialized via dependency injection + @SuppressFieldNotInitialized String suppressAnnotationIsOK; // OK: explicitly suppressed - @Bind String bindIsOK; // Means: assume it will be initialized, and ignore null assignment + @SuppressLint("eradicate-field-not-initialized") + String suppressLintIsOK; // OK: explicitly suppressed on lint level - // Means: assume it will be initialized, and ignore null assignment - @SuppressViewNullability String suppressViewNullabilityIsOK; + @SuppressLint("some-irrelevant-linter") + String suppressWrongLintIsBAD; // BAD: this suppression is irrelevant - FieldNotInitialized() {} + @Inject String injectIsOK; // Means: assume it will be initialized via dependency injection - void testNullifyFields() { - bindIsOK = null; // OK: the framework could write null into the field - suppressViewNullabilityIsOK = null; // OK: the framework could write null into the field - nonnullIsBAD = null; // BAD: explicit annotation does not allow nullifying - nonNullIsBAD = null; // BAD: explicit annotation does not allow nullifying - injectIsOK = null; // BAD: can not nullify this + @Bind String bindIsOK; // Means: assume it will be initialized, and ignore null assignment + + // Means: assume it will be initialized, and ignore null assignment + @SuppressViewNullability String suppressViewNullabilityIsOK; + + Suppression() {} + + // Ensure that some suppressions suppress only field not initialized + // and nothing else, but some suppress setting to null as well. + void testNullifyFields() { + bindIsOK = null; // OK: the framework could write null into the field + suppressViewNullabilityIsOK = null; // OK: the framework could write null into the field + nonnullIsBAD = null; // BAD: explicit nonnull annotation does not allow nullifying + nonNullIsBAD = null; // BAD: explicit nonnull annotation does not allow nullifying + injectIsOK = null; // BAD: inject suppressed only initialization issues + suppressAnnotationIsOK = null; // BAD: only initialization issue was suppressed + suppressLintIsOK = null; // BAD: only initialization issue was suppressed + } } class OnlyRead { diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/SuppressedFieldNotInitializedExample.java b/infer/tests/codetoanalyze/java/nullsafe-default/SuppressedFieldNotInitializedExample.java deleted file mode 100644 index 4335c84af..000000000 --- a/infer/tests/codetoanalyze/java/nullsafe-default/SuppressedFieldNotInitializedExample.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package codetoanalyze.java.nullsafe_default; - -import android.annotation.SuppressLint; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) -@interface SuppressFieldNotInitialized {} - -public class SuppressedFieldNotInitializedExample { - - @SuppressLint("eradicate-field-not-initialized") - String iKnowBetter; - - @SuppressFieldNotInitialized String annotationSuppressed; - - SuppressedFieldNotInitializedExample() {} -} diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp b/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp index 2d6939229..45a155909 100644 --- a/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp +++ b/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp @@ -17,7 +17,7 @@ codetoanalyze/java/nullsafe-default/CustomAnnotations.java, codetoanalyze.java.n codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitCircular.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$InitCircular.bad` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitCircular.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$InitCircular.stillBad` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitIfNull.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$InitIfNull.shouldBeGood_FIXME` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitWithOtherClass.(codetoanalyze.java.nullsafe_default.FieldNotInitialized,codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitWithOtherClass$OtherClass), 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized$InitWithOtherClass.bad` can be null but is not declared `@Nullable`. (Origin: field FieldNotInitialized$InitWithOtherClass$OtherClass.nullable at line 165)] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitWithOtherClass.(codetoanalyze.java.nullsafe_default.FieldNotInitialized,codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitWithOtherClass$OtherClass), 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized$InitWithOtherClass.bad` can be null but is not declared `@Nullable`. (Origin: field FieldNotInitialized$InitWithOtherClass$OtherClass.nullable at line 182)] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitWithTheSameClass.(codetoanalyze.java.nullsafe_default.FieldNotInitialized,codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitWithTheSameClass), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$InitWithTheSameClass.bad` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$InitializationOrder.(codetoanalyze.java.nullsafe_default.FieldNotInitialized,int), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$InitializationOrder.o1` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$OnlyRead.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$OnlyRead.o` is not initialized in the constructor and is not declared `@Nullable`] @@ -25,13 +25,16 @@ codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$ShouldInitializeInAllBranches.(codetoanalyze.java.nullsafe_default.FieldNotInitialized,int), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$ShouldInitializeInAllBranches.f3` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$ShouldInitializeInAllBranches.(codetoanalyze.java.nullsafe_default.FieldNotInitialized,int), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$ShouldInitializeInAllBranches.f5` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$ShouldInitializeInAllBranches.(codetoanalyze.java.nullsafe_default.FieldNotInitialized,int), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$ShouldInitializeInAllBranches.f2` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.nonnullIsBAD` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.notNullIsBAD` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.suppressWrongLintIsBAD` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.nonNullIsBAD` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.testNullifyFields():void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.nonnullIsBAD` can be null but is not declared `@Nullable`. (Origin: null constant at line 59)] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.testNullifyFields():void, 4, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.nonNullIsBAD` can be null but is not declared `@Nullable`. (Origin: null constant at line 60)] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.testNullifyFields():void, 5, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.injectIsOK` can be null but is not declared `@Nullable`. (Origin: null constant at line 61)] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.testNullifyFields():void, 6, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.suppressAnnotationIsOK` can be null but is not declared `@Nullable`. (Origin: null constant at line 62)] +codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$Suppression.testNullifyFields():void, 7, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized$Suppression.suppressLintIsOK` can be null but is not declared `@Nullable`. (Origin: null constant at line 63)] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized$WriteItselfIsBAD.(codetoanalyze.java.nullsafe_default.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$WriteItselfIsBAD.bad` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized.notNullIsBAD` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized.nonNullIsBAD` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized.nonnullIsBAD` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized.testNullifyFields():void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized.nonnullIsBAD` can be null but is not declared `@Nullable`. (Origin: null constant at line 45)] -codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized.testNullifyFields():void, 4, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized.nonNullIsBAD` can be null but is not declared `@Nullable`. (Origin: null constant at line 46)] -codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.FieldNotInitialized.testNullifyFields():void, 5, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotInitialized.injectIsOK` can be null but is not declared `@Nullable`. (Origin: null constant at line 47)] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.TestInitializerAnnotation.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `TestInitializerAnnotation.dontInitAtAllIsBAD` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.TestInitializerAnnotation.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `TestInitializerAnnotation.initInAnyOtherMethodIsBAD` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/nullsafe-default/FieldNotInitialized.java, codetoanalyze.java.nullsafe_default.TestInitializerAnnotation.build():java.lang.Object, 5, ERADICATE_CONDITION_REDUNDANT, no_bucket, WARNING, [The condition TestInitializerAnnotation.initInInitilizerMethod2IsOK is always true according to the existing annotations.]