From 878add3fad089b4b1abacbdd82c9db81f92c78ac Mon Sep 17 00:00:00 2001 From: Jeremy Dubreil Date: Tue, 25 Sep 2018 08:56:26 -0700 Subject: [PATCH] [eradicate] no longer report Field Not Nullable warnings on the Fragment onDestroy method Summary: It is common on Android code to recycle the `View` object by nullifying them in the `onDestroy()` or `onDestroyView()` methods. In this case, the outer `Fragment` object structure is preserve while the inner `View` object are set to null for the garbage collect to release the memory. However, if the fields are only set to `null` in the `onDestroy*()` methods, those fields cannot be `null` during the active lifecycle of the `Fragment`, so it is not necessary to annotate those fields with `Nullable`. Reviewed By: mbouaziz Differential Revision: D10024458 fbshipit-source-id: b05e538d9 --- infer/src/eradicate/eradicateChecks.ml | 3 ++- .../java/eradicate/FieldNotNullable.java | 18 +++++++++++++--- .../codetoanalyze/java/eradicate/issues.exp | 21 ++++++++++--------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/infer/src/eradicate/eradicateChecks.ml b/infer/src/eradicate/eradicateChecks.ml index 78fedfec8..f1156494b 100644 --- a/infer/src/eradicate/eradicateChecks.ml +++ b/infer/src/eradicate/eradicateChecks.ml @@ -184,7 +184,8 @@ let check_field_assignment tenv find_canonical_duplicate curr_pdesc node instr_r | _ -> false in - (not (TypeAnnotation.get_value AnnotatedSignature.Nullable ta_lhs)) + (not (AndroidFramework.is_destroy_method curr_pname)) + && (not (TypeAnnotation.get_value AnnotatedSignature.Nullable ta_lhs)) && TypeAnnotation.get_value AnnotatedSignature.Nullable ta_rhs && PatternMatch.type_is_class t_lhs && (not (Typ.Fieldname.Java.is_outer_instance fname)) diff --git a/infer/tests/codetoanalyze/java/eradicate/FieldNotNullable.java b/infer/tests/codetoanalyze/java/eradicate/FieldNotNullable.java index d9410e32c..d568284b1 100644 --- a/infer/tests/codetoanalyze/java/eradicate/FieldNotNullable.java +++ b/infer/tests/codetoanalyze/java/eradicate/FieldNotNullable.java @@ -7,15 +7,17 @@ package codetoanalyze.java.eradicate; +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.View; + import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Initializer; import com.facebook.infer.annotation.SuppressFieldNotInitialized; import javax.annotation.Nullable; -import android.app.Activity; -import android.os.Bundle; - abstract class A { final String fld; @@ -27,6 +29,16 @@ abstract class A { // for butterknife @interface InjectView {} +class FragmentExample extends Fragment { + + View view; + + @Override + public void onDestroyView() { + view = null; + } +} + public class FieldNotNullable extends A { @Nullable String x; diff --git a/infer/tests/codetoanalyze/java/eradicate/issues.exp b/infer/tests/codetoanalyze/java/eradicate/issues.exp index 24978132f..1887b33be 100644 --- a/infer/tests/codetoanalyze/java/eradicate/issues.exp +++ b/infer/tests/codetoanalyze/java/eradicate/issues.exp @@ -16,17 +16,18 @@ codetoanalyze/java/eradicate/FieldNotInitialized.java, codetoanalyze.java.eradic codetoanalyze/java/eradicate/FieldNotInitialized.java, codetoanalyze.java.eradicate.FieldNotInitialized$Swap.(codetoanalyze.java.eradicate.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$Swap.o1` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/eradicate/FieldNotInitialized.java, codetoanalyze.java.eradicate.FieldNotInitialized$WriteItself.(codetoanalyze.java.eradicate.FieldNotInitialized), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized$WriteItself.o` is not initialized in the constructor and is not declared `@Nullable`] codetoanalyze/java/eradicate/FieldNotInitialized.java, codetoanalyze.java.eradicate.FieldNotInitialized.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FieldNotInitialized.a` is not initialized in the constructor and is not declared `@Nullable`] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.(java.lang.Integer), -25, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 35)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.(java.lang.String), -2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 35)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.setYNull():void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: null constant at line 53)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.(java.lang.Integer), -25, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 47)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.(java.lang.String), -2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 47)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.setYNull():void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: null constant at line 65)] codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.setYNullable(java.lang.String):void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: method parameter s)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.FlatBAD1(codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 249)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.FlatBAD2(codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 255)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD1():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 273)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD2():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 279)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD3():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 285)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestPut.putNull(java.util.Map,java.lang.String):void, 2, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [origin,`Map.put(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 323)] -codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestPut.putNull(java.util.Map,java.lang.String):void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestPut.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: null constant at line 323)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FragmentExample.(), 0, ERADICATE_FIELD_NOT_INITIALIZED, no_bucket, WARNING, [Field `FragmentExample.view` is not initialized in the constructor and is not declared `@Nullable`] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.FlatBAD1(codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 261)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.FlatBAD2(codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent):void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 267)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD1():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 285)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD2():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 291)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD3():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 297)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestPut.putNull(java.util.Map,java.lang.String):void, 2, ERADICATE_PARAMETER_NOT_NULLABLE, no_bucket, WARNING, [origin,`Map.put(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 335)] +codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestPut.putNull(java.util.Map,java.lang.String):void, 3, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [origin,Field `NestedFieldAccess$TestPut.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: null constant at line 335)] codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.TestInitializerBuilder.build():codetoanalyze.java.eradicate.TestInitializer, 2, ERADICATE_CONDITION_REDUNDANT, no_bucket, WARNING, [The condition TestInitializerBuilder.required1 is always true according to the existing annotations.] codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.TestInitializerBuilder.build():codetoanalyze.java.eradicate.TestInitializer, 2, ERADICATE_CONDITION_REDUNDANT, no_bucket, WARNING, [The condition TestInitializerBuilder.required2 is always true according to the existing annotations.] codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, codetoanalyze.java.eradicate.ExtendsExternalLibrary.externalMethod2(java.lang.Object):void, 0, ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION, no_bucket, WARNING, [First parameter `object` of method `ExtendsExternalLibrary.externalMethod2(...)` is not `@Nullable` but is declared `@Nullable`in the parent class method `SomeExternalClass.externalMethod2(...)`.]