Add @Cleanup annotation

Reviewed By: jeremydubreil

Differential Revision: D15318692

fbshipit-source-id: fd6debace
master
Andrew Adams-Moran 6 years ago committed by Facebook Github Bot
parent 0a5810c579
commit 0ad15356c2

@ -0,0 +1,22 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.infer.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A method annotated with @Cleanup should always be permitted to nullify fields, even if they are
* not nullable. Combined with the @Initializer annotation, this allows devs to specify
* acquire/release methods.
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface Cleanup {}

@ -27,6 +27,8 @@ let bind_string = "BindString"
let camel_nonnull = "NonNull"
let cleanup = "Cleanup"
let expensive = "Expensive"
let false_on_null = "FalseOnNull"
@ -181,6 +183,8 @@ let ia_is_nonblocking ia = ia_ends_with ia nonblocking
let ia_is_initializer ia = ia_ends_with ia initializer_
let ia_is_cleanup ia = ia_ends_with ia cleanup
let ia_is_volatile ia = ia_contains ia volatile
let field_injector_readwrite_list =

@ -65,6 +65,8 @@ val ia_is_false_on_null : Annot.Item.t -> bool
val ia_is_initializer : Annot.Item.t -> bool
val ia_is_cleanup : Annot.Item.t -> bool
val ia_is_field_injector_readonly : Annot.Item.t -> bool
(** Annotations for readonly injectors.
The injector framework initializes the field but does not write null into it. *)

@ -33,6 +33,7 @@ let explain_expr tenv node e =
| None ->
None
let is_virtual = function (p, _, _) :: _ when Mangled.is_this p -> true | _ -> false
(** Check an access (read or write) to a field. *)
@ -143,6 +144,7 @@ let check_nonzero tenv find_canonical_duplicate =
let check_field_assignment tenv find_canonical_duplicate curr_pdesc node instr_ref typestate
exp_lhs exp_rhs typ loc fname t_ia_opt typecheck_expr : unit =
let curr_pname = Procdesc.get_proc_name curr_pdesc in
let curr_pattrs = Procdesc.get_attributes curr_pdesc in
let t_lhs, ta_lhs, _ =
typecheck_expr node instr_ref curr_pdesc typestate exp_lhs
(typ, TypeAnnotation.const AnnotatedSignature.Nullable false TypeOrigin.ONone, [loc])
@ -153,20 +155,25 @@ let check_field_assignment tenv find_canonical_duplicate curr_pdesc node instr_r
(typ, TypeAnnotation.const AnnotatedSignature.Nullable false TypeOrigin.ONone, [loc])
loc
in
let field_is_injector_readwrite () =
match t_ia_opt with
| Some (_, ia) ->
Annotations.ia_is_field_injector_readwrite ia
| _ ->
false
in
let field_is_in_cleanup_context () =
let ia, _ = (Models.get_modelled_annotated_signature curr_pattrs).AnnotatedSignature.ret in
Annotations.ia_is_cleanup ia
in
let should_report_nullable =
let field_is_field_injector_readwrite () =
match t_ia_opt with
| Some (_, ia) ->
Annotations.ia_is_field_injector_readwrite ia
| _ ->
false
in
(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))
&& not (field_is_field_injector_readwrite ())
&& (not (field_is_injector_readwrite ()))
&& not (field_is_in_cleanup_context ())
in
let should_report_absent =
Config.eradicate_optional_present

@ -12,6 +12,7 @@ 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.Cleanup;
import com.facebook.infer.annotation.Initializer;
import javax.annotation.Nullable;
@ -120,6 +121,13 @@ class TestInitializerBuilder {
return new TestInitializer(this);
}
@Cleanup
void testCleanup() {
this.required1 = null;
this.required2 = null;
this.optional = null;
}
}
class TestInitializer {

@ -16,18 +16,18 @@ codetoanalyze/java/eradicate/FieldNotInitialized.java, codetoanalyze.java.eradic
codetoanalyze/java/eradicate/FieldNotInitialized.java, codetoanalyze.java.eradicate.FieldNotInitialized$Swap.<init>(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.<init>(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.<init>(), 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.<init>(java.lang.Integer), -25, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 43)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.<init>(java.lang.String), -2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 43)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.setYNull():void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: null constant at line 61)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.<init>(java.lang.Integer), -25, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 44)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.<init>(java.lang.String), -2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.static_s` can be null but is not declared `@Nullable`. (Origin: null constant at line 44)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.FieldNotNullable.setYNull():void, 1, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `FieldNotNullable.y` can be null but is not declared `@Nullable`. (Origin: null constant at line 62)]
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.FragmentExample.<init>(), 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, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 250)]
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, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 256)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD1():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 274)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD2():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 280)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD3():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 286)]
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, [`Map.put(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 324)]
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, [Field `NestedFieldAccess$TestPut.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: null constant at line 324)]
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, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 258)]
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, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 264)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD1():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 282)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD2():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 288)]
codetoanalyze/java/eradicate/FieldNotNullable.java, codetoanalyze.java.eradicate.NestedFieldAccess$TestFunctionsIdempotent.NestedBAD3():void, 2, ERADICATE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field `NestedFieldAccess$TestFunctionsIdempotent.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: call to getS(...) at line 294)]
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, [`Map.put(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 332)]
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, [Field `NestedFieldAccess$TestPut.dontAssignNull` can be null but is not declared `@Nullable`. (Origin: null constant at line 332)]
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(...)`.]

Loading…
Cancel
Save