From bd83813b3e48fd80d40feaab4f32e564db9e0389 Mon Sep 17 00:00:00 2001 From: Mitya Lyubarskiy Date: Thu, 5 Mar 2020 07:41:56 -0800 Subject: [PATCH] [tech debt] Remove experimental nullability checkers Summary: These were not used (and were actually activated byt the same config param). They both are in experimental stage that never reached maturity. Since the team does not have immediate plans to work on ObjC nullability checker; and since "eradicate" (now known as nullsafe) is the main solution for Java, removing it is sensible. Reviewed By: jvillard Differential Revision: D20279866 fbshipit-source-id: 79e64992b --- Makefile | 3 - infer/man/man1/infer-analyze.txt | 4 +- infer/man/man1/infer-full.txt | 6 +- infer/man/man1/infer-report.txt | 2 - infer/man/man1/infer.txt | 6 +- infer/src/IR/AccessPath.ml | 28 -- infer/src/IR/AccessPath.mli | 11 - infer/src/IR/Fieldname.ml | 4 - infer/src/IR/Fieldname.mli | 3 - infer/src/IR/Localise.mli | 3 - infer/src/base/Config.ml | 19 +- infer/src/base/Config.mli | 2 - infer/src/base/IssueType.ml | 8 - infer/src/base/IssueType.mli | 4 - infer/src/checkers/registerCheckers.ml | 10 - infer/src/nullsafe/NullabilityCheck.ml | 339 ------------------ infer/src/nullsafe/NullabilityCheck.mli | 10 - infer/src/nullsafe/NullabilitySuggest.ml | 236 ------------ infer/src/nullsafe/NullabilitySuggest.mli | 11 - .../codetoanalyze/cpp/conflicts/Makefile | 2 +- .../codetoanalyze/cpp/conflicts/issues.exp | 1 - .../tests/codetoanalyze/cpp/nullable/Makefile | 17 - .../codetoanalyze/cpp/nullable/example.cpp | 62 ---- .../codetoanalyze/cpp/nullable/issues.exp | 53 --- .../codetoanalyze/cpp/nullable/method.cpp | 170 --------- .../codetoanalyze/java/checkers/Makefile | 2 +- .../codetoanalyze/java/checkers/issues.exp | 11 - .../codetoanalyze/objc/nullable/Examples.m | 290 --------------- .../codetoanalyze/objc/nullable/Library.h | 13 - .../codetoanalyze/objc/nullable/Makefile | 17 - .../codetoanalyze/objc/nullable/issues.exp | 26 -- .../codetoanalyze/objcpp/nullable/Examples.mm | 27 -- .../codetoanalyze/objcpp/nullable/Makefile | 17 - .../codetoanalyze/objcpp/nullable/issues.exp | 1 - 34 files changed, 18 insertions(+), 1400 deletions(-) delete mode 100644 infer/src/nullsafe/NullabilityCheck.ml delete mode 100644 infer/src/nullsafe/NullabilityCheck.mli delete mode 100644 infer/src/nullsafe/NullabilitySuggest.ml delete mode 100644 infer/src/nullsafe/NullabilitySuggest.mli delete mode 100644 infer/tests/codetoanalyze/cpp/nullable/Makefile delete mode 100644 infer/tests/codetoanalyze/cpp/nullable/example.cpp delete mode 100644 infer/tests/codetoanalyze/cpp/nullable/issues.exp delete mode 100644 infer/tests/codetoanalyze/cpp/nullable/method.cpp delete mode 100644 infer/tests/codetoanalyze/objc/nullable/Examples.m delete mode 100644 infer/tests/codetoanalyze/objc/nullable/Library.h delete mode 100644 infer/tests/codetoanalyze/objc/nullable/Makefile delete mode 100644 infer/tests/codetoanalyze/objc/nullable/issues.exp delete mode 100644 infer/tests/codetoanalyze/objcpp/nullable/Examples.mm delete mode 100644 infer/tests/codetoanalyze/objcpp/nullable/Makefile delete mode 100644 infer/tests/codetoanalyze/objcpp/nullable/issues.exp diff --git a/Makefile b/Makefile index 698d07f47..dbf28927e 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,6 @@ DIRECT_TESTS += \ cpp_linters \ cpp_linters-for-test-only \ cpp_liveness \ - cpp_nullable \ cpp_pulse \ cpp_quandary cpp_quandaryBO \ cpp_racerd \ @@ -115,7 +114,6 @@ DIRECT_TESTS += \ objc_linters-def-folder \ objc_linters-for-test-only \ objc_liveness \ - objc_nullable \ objc_performance \ objc_pulse \ objc_quandary \ @@ -126,7 +124,6 @@ DIRECT_TESTS += \ objcpp_linters \ objcpp_linters-for-test-only \ objcpp_liveness \ - objcpp_nullable \ objcpp_pulse \ objcpp_racerd \ objcpp_retain-cycles \ diff --git a/infer/man/man1/infer-analyze.txt b/infer/man/man1/infer-analyze.txt index 3037a73b3..97ca0d75e 100644 --- a/infer/man/man1/infer-analyze.txt +++ b/infer/man/man1/infer-analyze.txt @@ -201,8 +201,8 @@ OPTIONS (Conversely: --no-loop-hoisting-only) --nullsafe - Activates: [EXPERIMENTAL] Nullable type checker (incomplete: use - --eradicate for now) (Conversely: --no-nullsafe) + Activates: [RESERVED] Reserved for nullsafe typechecker, use + --eradicate for now (Conversely: --no-nullsafe) --nullsafe-only Activates: Enable --nullsafe and disable all other checkers diff --git a/infer/man/man1/infer-full.txt b/infer/man/man1/infer-full.txt index f11c29f4f..2f0577a39 100644 --- a/infer/man/man1/infer-full.txt +++ b/infer/man/man1/infer-full.txt @@ -470,8 +470,6 @@ OPTIONS MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default), Missing_fld (enabled by default), NULLPTR_DEREFERENCE (disabled by default), - NULLSAFE_FIELD_NOT_NULLABLE (enabled by default), - NULLSAFE_NULLABLE_DEREFERENCE (enabled by default), NULL_DEREFERENCE (enabled by default), NULL_TEST_AFTER_DEREFERENCE (disabled by default), PARAMETER_NOT_NULL_CHECKED (enabled by default), @@ -801,8 +799,8 @@ OPTIONS See also infer-analyze(1). --nullsafe - Activates: [EXPERIMENTAL] Nullable type checker (incomplete: use - --eradicate for now) (Conversely: --no-nullsafe) See also infer-analyze(1). + Activates: [RESERVED] Reserved for nullsafe typechecker, use + --eradicate for now (Conversely: --no-nullsafe) See also infer-analyze(1). --nullsafe-only Activates: Enable --nullsafe and disable all other checkers diff --git a/infer/man/man1/infer-report.txt b/infer/man/man1/infer-report.txt index 6075959e2..3fc369d9d 100644 --- a/infer/man/man1/infer-report.txt +++ b/infer/man/man1/infer-report.txt @@ -192,8 +192,6 @@ OPTIONS MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default), Missing_fld (enabled by default), NULLPTR_DEREFERENCE (disabled by default), - NULLSAFE_FIELD_NOT_NULLABLE (enabled by default), - NULLSAFE_NULLABLE_DEREFERENCE (enabled by default), NULL_DEREFERENCE (enabled by default), NULL_TEST_AFTER_DEREFERENCE (disabled by default), PARAMETER_NOT_NULL_CHECKED (enabled by default), diff --git a/infer/man/man1/infer.txt b/infer/man/man1/infer.txt index 0f31dc402..76848c533 100644 --- a/infer/man/man1/infer.txt +++ b/infer/man/man1/infer.txt @@ -470,8 +470,6 @@ OPTIONS MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default), Missing_fld (enabled by default), NULLPTR_DEREFERENCE (disabled by default), - NULLSAFE_FIELD_NOT_NULLABLE (enabled by default), - NULLSAFE_NULLABLE_DEREFERENCE (enabled by default), NULL_DEREFERENCE (enabled by default), NULL_TEST_AFTER_DEREFERENCE (disabled by default), PARAMETER_NOT_NULL_CHECKED (enabled by default), @@ -801,8 +799,8 @@ OPTIONS See also infer-analyze(1). --nullsafe - Activates: [EXPERIMENTAL] Nullable type checker (incomplete: use - --eradicate for now) (Conversely: --no-nullsafe) See also infer-analyze(1). + Activates: [RESERVED] Reserved for nullsafe typechecker, use + --eradicate for now (Conversely: --no-nullsafe) See also infer-analyze(1). --nullsafe-only Activates: Enable --nullsafe and disable all other checkers diff --git a/infer/src/IR/AccessPath.ml b/infer/src/IR/AccessPath.ml index a5b66d6fa..cdf273158 100644 --- a/infer/src/IR/AccessPath.ml +++ b/infer/src/IR/AccessPath.ml @@ -55,14 +55,6 @@ module Raw = struct let equal = [%compare.equal: t] - let truncate ((base, accesses) as t) = - match List.rev accesses with - | [] -> - (t, None) - | last_access :: accesses -> - ((base, List.rev accesses), Some last_access) - - let lookup_field_type_annot tenv base_typ field_name = let lookup = Tenv.lookup tenv in Struct.get_field_type_and_annotation ~lookup field_name base_typ @@ -76,16 +68,6 @@ module Raw = struct Some array_typ - (* For field access, get the field name and the annotation associated with it - * Return None if given an array access, or if the info cannot be obtained *) - let get_access_field_annot tenv base_typ = function - | FieldAccess field_name -> - Option.map (lookup_field_type_annot tenv base_typ field_name) ~f:(fun (_, annot) -> - (field_name, annot) ) - | ArrayAccess _ -> - None - - (* Extract the last access of the given access path together with its base type. * Here the base type is defined to be the declaring class of the last accessed field, * or the type of base if the access list is empty. @@ -109,16 +91,6 @@ module Raw = struct last_access_info_impl tenv base_typ accesses - let get_last_access (_, accesses) = List.last accesses - - let get_field_and_annotation ap tenv = - match last_access_info ap tenv with - | Some base_typ, Some access -> - get_access_field_annot tenv base_typ access - | _ -> - None - - let get_typ ap tenv = match last_access_info ap tenv with | (Some _ as typ), None -> diff --git a/infer/src/IR/AccessPath.mli b/infer/src/IR/AccessPath.mli index 7a49a3d1e..0116ebd9f 100644 --- a/infer/src/IR/AccessPath.mli +++ b/infer/src/IR/AccessPath.mli @@ -20,17 +20,6 @@ type access = as (x, [f; g]) *) and t = base * access list [@@deriving compare] -val truncate : t -> t * access option -(** remove and return the last access of the access path if the access list is non-empty. returns - the original access path * None if the access list is empty *) - -val get_last_access : t -> access option -(** get the last access in the list. returns None if the list is empty *) - -val get_field_and_annotation : t -> Tenv.t -> (Fieldname.t * Annot.Item.t) option -(** get the field name and the annotation of the last access in the list of accesses if the list is - non-empty and the last access is a field access *) - val get_typ : t -> Tenv.t -> Typ.t option (** get the typ of the last access in the list of accesses if the list is non-empty, or the base if the list is empty. that is, for x.f.g, return typ(g), and for x, return typ(x) *) diff --git a/infer/src/IR/Fieldname.ml b/infer/src/IR/Fieldname.ml index f795cb63d..d1d3c6595 100644 --- a/infer/src/IR/Fieldname.ml +++ b/infer/src/IR/Fieldname.ml @@ -51,10 +51,6 @@ let to_full_string fld = let pp f fld = F.pp_print_string f fld.field_name -let is_java_captured_parameter ({field_name} as field) = - is_java field && String.is_prefix ~prefix:"val$" field_name - - let is_java_outer_instance ({field_name} as field) = is_java field && diff --git a/infer/src/IR/Fieldname.mli b/infer/src/IR/Fieldname.mli index 6efc69457..830c36911 100644 --- a/infer/src/IR/Fieldname.mli +++ b/infer/src/IR/Fieldname.mli @@ -26,9 +26,6 @@ module Set : Caml.Set.S with type elt = t module Map : Caml.Map.S with type key = t (** Map for fieldnames *) -val is_java_captured_parameter : t -> bool -(** Check if field is a captured parameter *) - val is_java_outer_instance : t -> bool (** Check if the field is the synthetic this$n of a nested class, used to access the n-th outer instance. *) diff --git a/infer/src/IR/Localise.mli b/infer/src/IR/Localise.mli index 561883115..49aec5014 100644 --- a/infer/src/IR/Localise.mli +++ b/infer/src/IR/Localise.mli @@ -94,9 +94,6 @@ type access = | Initialized_automatically | Returned_from_call of int -val nullable_annotation_name : Procname.t -> string -(** Name of the nullable annotation *) - val dereference_string : Procname.t -> deref_str -> string -> access option -> Location.t -> error_desc diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index a2dbd4e25..cff58d479 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -32,7 +32,6 @@ type checkers = ; litho_required_props: bool ref ; liveness: bool ref ; loop_hoisting: bool ref - ; nullsafe: bool ref ; self_in_block: bool ref ; printf_args: bool ref ; pulse: bool ref @@ -631,7 +630,6 @@ and { annotation_reachability ; litho_required_props ; liveness ; loop_hoisting - ; nullsafe ; self_in_block ; printf_args ; pulse @@ -643,9 +641,11 @@ and { annotation_reachability ; siof ; starvation ; uninit } = - let mk_checker ?(default = false) ?(deprecated = []) ~long doc = + let mk_checker ?(default = false) ?(deprecated = []) ~long ?f doc = let var = - CLOpt.mk_bool ~long ~in_help:InferCommand.[(Analyze, manual_generic)] ~default ~deprecated doc + CLOpt.mk_bool ?f ~long + ~in_help:InferCommand.[(Analyze, manual_generic)] + ~default ~deprecated doc in all_checkers := (var, long, doc, default) :: !all_checkers ; var @@ -681,10 +681,14 @@ and { annotation_reachability and liveness = mk_checker ~long:"liveness" ~default:true "the detection of dead stores and unused variables" and loop_hoisting = mk_checker ~long:"loop-hoisting" ~default:false "checker for loop-hoisting" - and nullsafe = + and _nullsafe = + (* TODO make this to be activate nullsafe typechecker when old usages are gone *) mk_checker ~long:"nullsafe" + ~f:(fun b -> + CLOpt.warnf "nullsafe is is a reserved (no-op) checker; use --eradicate\n" ; + b ) ~deprecated:["-check-nullable"; "-suggest-nullable"] - "[EXPERIMENTAL] Nullable type checker (incomplete: use --eradicate for now)" + "[RESERVED] Reserved for nullsafe typechecker, use --eradicate for now" and printf_args = mk_checker ~long:"printf-args" ~default:false "the detection of mismatch between the Java printf format strings and the argument types \ @@ -758,7 +762,6 @@ and { annotation_reachability ; litho_required_props ; liveness ; loop_hoisting - ; nullsafe ; printf_args ; pulse ; purity @@ -2810,8 +2813,6 @@ and censor_report = and changed_files_index = !changed_files_index -and nullsafe = !nullsafe - and check_version = !check_version and clang_biniou_file = !clang_biniou_file diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index a60d40318..33f6a2285 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -489,8 +489,6 @@ val no_translate_libs : bool val nullable_annotation : string option -val nullsafe : bool - val nullsafe_disable_field_not_initialized_in_nonstrict_classes : bool val nullsafe_optimistic_third_party_params_in_non_strict : bool diff --git a/infer/src/base/IssueType.ml b/infer/src/base/IssueType.ml index 6728456d5..e31cb318d 100644 --- a/infer/src/base/IssueType.ml +++ b/infer/src/base/IssueType.ml @@ -378,14 +378,6 @@ let null_test_after_dereference = register_from_string ~enabled:false "NULL_TEST let nullptr_dereference = register_from_string ~enabled:false "NULLPTR_DEREFERENCE" -let nullsafe_field_not_nullable = - register_from_string "NULLSAFE_FIELD_NOT_NULLABLE" ~hum:"Field Not Nullable" - - -let nullsafe_nullable_dereference = - register_from_string "NULLSAFE_NULLABLE_DEREFERENCE" ~hum:"Nullable Dereference" - - let parameter_not_null_checked = register_from_string "PARAMETER_NOT_NULL_CHECKED" let pointer_size_mismatch = register_from_string "POINTER_SIZE_MISMATCH" diff --git a/infer/src/base/IssueType.mli b/infer/src/base/IssueType.mli index e68f6df04..7d001ae6c 100644 --- a/infer/src/base/IssueType.mli +++ b/infer/src/base/IssueType.mli @@ -250,10 +250,6 @@ val null_test_after_dereference : t val nullptr_dereference : t -val nullsafe_field_not_nullable : t - -val nullsafe_nullable_dereference : t - val parameter_not_null_checked : t val pointer_size_mismatch : t diff --git a/infer/src/checkers/registerCheckers.ml b/infer/src/checkers/registerCheckers.ml index bb19c3e48..6aa75ce8c 100644 --- a/infer/src/checkers/registerCheckers.ml +++ b/infer/src/checkers/registerCheckers.ml @@ -35,11 +35,6 @@ let all_checkers = ; callbacks= [ (Procedure AnnotationReachability.checker, Language.Java) ; (Procedure AnnotationReachability.checker, Language.Clang) ] } - ; { name= "nullable checks" - ; active= Config.nullsafe - ; callbacks= - [ (Procedure NullabilityCheck.checker, Language.Clang) - ; (Procedure NullabilityCheck.checker, Language.Java) ] } ; { name= "biabduction" ; active= Config.biabduction ; callbacks= @@ -76,11 +71,6 @@ let all_checkers = ; { name= "printf args" ; active= Config.printf_args ; callbacks= [(Procedure PrintfArgs.callback_printf_args, Language.Java)] } - ; { name= "nullable suggestion" - ; active= Config.nullsafe - ; callbacks= - [ (Procedure NullabilitySuggest.checker, Language.Java) - ; (Procedure NullabilitySuggest.checker, Language.Clang) ] } ; { name= "impurity" ; active= Config.impurity ; callbacks= diff --git a/infer/src/nullsafe/NullabilityCheck.ml b/infer/src/nullsafe/NullabilityCheck.ml deleted file mode 100644 index 4a7b1ac35..000000000 --- a/infer/src/nullsafe/NullabilityCheck.ml +++ /dev/null @@ -1,339 +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. - *) - -open! IStd -module F = Format -module L = Logging -module MF = MarkupFormatter -module CallSites = AbstractDomain.FiniteSet (CallSite) -module NullableAP = AbstractDomain.Map (AccessPath) (CallSites) -module NullCheckedPname = AbstractDomain.InvertedSet (Procname) -module Domain = AbstractDomain.Pair (NullableAP) (NullCheckedPname) - -module TransferFunctions (CFG : ProcCfg.S) = struct - module CFG = CFG - module Domain = Domain - - type extras = unit - - let rec is_pointer_subtype tenv typ1 typ2 = - match (typ1.Typ.desc, typ2.Typ.desc) with - | Typ.Tptr (t1, _), Typ.Tptr (t2, _) -> ( - match (t1.Typ.desc, t2.Typ.desc) with - | Typ.Tstruct n1, Typ.Tstruct n2 -> - Subtype.is_known_subtype tenv n1 n2 - | _ -> - Typ.equal t1 t2 || is_pointer_subtype tenv t1 t2 ) - | _ -> - false - - - let is_non_objc_instance_method callee_pname = - match callee_pname with - | Procname.Java java_pname -> - not (Procname.Java.is_static java_pname) - | _ -> - Option.exists - ~f:(fun attributes -> - ClangMethodKind.equal attributes.ProcAttributes.clang_method_kind - ClangMethodKind.CPP_INSTANCE ) - (Summary.OnDisk.proc_resolve_attributes callee_pname) - - - let is_objc_instance_method callee_pname = - Option.exists - ~f:(fun attributes -> - ClangMethodKind.equal attributes.ProcAttributes.clang_method_kind - ClangMethodKind.OBJC_INSTANCE ) - (Summary.OnDisk.proc_resolve_attributes callee_pname) - - - let is_blacklisted_method : Procname.t -> bool = - let blacklist = ["URLWithString:"; "objectForKeyedSubscript:"] in - fun proc_name -> - let simplified_callee_pname = Procname.to_simplified_string proc_name in - List.exists ~f:(String.equal simplified_callee_pname) blacklist - - - let container_method_regex = - Str.regexp @@ "^\\(NS.*::\\(arrayByAddingObject\\|arrayWithObjects\\|" - ^ "dictionaryWithObjects\\|dictionaryWithObjectsAndKeys\\|initWithObjectsAndKeys\\|" - ^ "addObject\\|insertObject\\|setObject\\|" - ^ "stringWithUTF8String\\|stringWithString\\|initWithFormat\\|stringByAppendingString\\):\\|" - ^ "std::basic_string\\).*" - - - let is_objc_container_add_method proc_name = - let callee_pname = Procname.to_string proc_name in - Str.string_match container_method_regex callee_pname 0 - - - let is_conflicting_report summary report_location = - (* FIXME(T54950303) replace use of filtering with deduplicate *) - if not Config.filtering then false - else - Errlog.fold - (fun {Errlog.err_name; err_desc} {Errlog.loc} found_confict -> - found_confict - || IssueType.equal err_name IssueType.null_dereference - && Location.equal loc report_location - && Localise.error_desc_is_reportable_bucket err_desc ) - (Summary.get_err_log summary) false - - - (* On Clang languages, the annotations like _Nullabe can be found on the declaration - or on the implementation without the two being necessarily consistent. - Here, we explicitely want to lookup the annotations locally: either form - the implementation when defined locally, or from the included headers *) - let lookup_local_attributes = function - | Procname.Java _ as pname -> - (* Looking up the attribute according to the classpath *) - Summary.OnDisk.proc_resolve_attributes pname - | pname -> - (* Looking up the attributes locally, i.e. either from the file of from the includes *) - Option.map ~f:Procdesc.get_attributes (Ondemand.get_proc_desc pname) - - - let report_nullable_dereference ap call_sites {ProcData.summary} loc = - if is_conflicting_report summary loc then () - else - let pname = Summary.get_proc_name summary in - let annotation = Localise.nullable_annotation_name pname in - let call_site = - try CallSites.min_elt call_sites - with Caml.Not_found -> - L.(die InternalError) - "Expecting a least one element in the set of call sites when analyzing %a" Procname.pp - pname - in - let simplified_pname = - Procname.to_simplified_string ~withclass:true (CallSite.pname call_site) - in - let is_direct_dereference = - match ap with - | (Var.LogicalVar _, _), _ -> - true - | (Var.ProgramVar pvar, _), _ -> - Pvar.is_frontend_tmp pvar - in - let message = - if is_direct_dereference then - (* direct dereference without intermediate variable *) - F.asprintf - "The return value of %s is annotated with %a and is dereferenced without being checked \ - for null at %a" - (MF.monospaced_to_string simplified_pname) - MF.pp_monospaced annotation Location.pp loc - else - (* dereference with intermediate variable *) - F.asprintf - "Variable %a is indirectly annotated with %a (source %a) and is dereferenced without \ - being checked for null at %a" - (MF.wrap_monospaced AccessPath.pp) - ap MF.pp_monospaced annotation (MF.wrap_monospaced CallSite.pp) call_site Location.pp - loc - in - let trace = - let with_origin_site = - let callee_pname = CallSite.pname call_site in - match lookup_local_attributes callee_pname with - | None -> - [] - | Some attributes -> - let description = F.asprintf "definition of %s" (Procname.get_method callee_pname) in - let trace_element = - Errlog.make_trace_element 1 attributes.ProcAttributes.loc description [] - in - [trace_element] - in - let with_assignment_site = - let call_site_loc = CallSite.loc call_site in - if Location.equal call_site_loc loc then with_origin_site - else - let trace_element = - Errlog.make_trace_element 0 call_site_loc "assignment of the nullable value" [] - in - trace_element :: with_origin_site - in - let dereference_site = - let description = - if is_direct_dereference then - F.asprintf "dereferencing the return of %s" simplified_pname - else F.asprintf "dereference of %a" AccessPath.pp ap - in - Errlog.make_trace_element 0 loc description [] - in - dereference_site :: with_assignment_site - in - Reporting.log_error summary ~loc ~ltr:trace IssueType.nullsafe_nullable_dereference message - - - let add_nullable_ap ap call_sites (aps, pnames) = (NullableAP.add ap call_sites aps, pnames) - - let remove_nullable_ap ap (aps, pnames) = (NullableAP.remove ap aps, pnames) - - let find_nullable_ap ap (aps, _) = NullableAP.find ap aps - - let assume_pnames_notnull ap (aps, checked_pnames) : Domain.t = - let remove_call_sites ap aps = - let add_diff (to_remove : CallSites.t) ap call_sites map = - let remaining_call_sites = CallSites.diff call_sites to_remove in - if CallSites.is_empty remaining_call_sites then map - else NullableAP.add ap remaining_call_sites map - in - match NullableAP.find_opt ap aps with - | None -> - aps - | Some call_sites -> - let updated_aps = NullableAP.fold (add_diff call_sites) aps NullableAP.empty in - updated_aps - in - let updated_pnames = - try - let call_sites = NullableAP.find ap aps in - CallSites.fold - (fun call_site s -> NullCheckedPname.add (CallSite.pname call_site) s) - call_sites checked_pnames - with Caml.Not_found -> checked_pnames - in - (remove_call_sites ap aps, updated_pnames) - - - let rec longest_nullable_prefix ap ((nullable_aps, _) as astate) = - try Some (ap, NullableAP.find ap nullable_aps) - with Caml.Not_found -> ( - match ap with - | _, [] -> - None - | p -> - longest_nullable_prefix (fst (AccessPath.truncate p)) astate ) - - - let check_ap proc_data loc ap astate = - match longest_nullable_prefix ap astate with - | None -> - astate - | Some (nullable_ap, call_sites) -> - report_nullable_dereference nullable_ap call_sites proc_data loc ; - assume_pnames_notnull ap astate - - - let rec check_nil_in_objc_container proc_data loc args astate = - match args with - | [] -> - astate - | [arg] when HilExp.is_null_literal arg -> - astate - | HilExp.AccessExpression access_expr :: other_args -> - let ap = HilExp.AccessExpression.to_access_path access_expr in - check_nil_in_objc_container proc_data loc other_args (check_ap proc_data loc ap astate) - | _ :: other_args -> - check_nil_in_objc_container proc_data loc other_args astate - - - let exec_instr ((_, checked_pnames) as astate) proc_data _ (instr : HilInstr.t) : Domain.t = - let is_pointer_assignment tenv lhs rhs = - (* the rhs has type int when assigning the lhs to null *) - if HilExp.is_null_literal rhs then true - (* the lhs and rhs have the same type in the case of pointer assignment - but the types are different when assigning the pointee *) - else - match (AccessPath.get_typ lhs tenv, HilExp.get_typ tenv rhs) with - (* defensive assumption when the types are not known *) - | None, _ | _, None -> - true - (* the rhs can be a subtype of the lhs *) - | Some lhs_typ, Some rhs_typ -> - is_pointer_subtype tenv rhs_typ lhs_typ - in - match instr with - | Call (ret_var, Direct callee_pname, _, _, _) - when NullCheckedPname.mem callee_pname checked_pnames -> - (* Do not report nullable when the method has already been checked for null *) - remove_nullable_ap (ret_var, []) astate - | Call (_, Direct callee_pname, HilExp.AccessExpression receiver :: _, _, _) - when Models.is_check_not_null callee_pname -> - assume_pnames_notnull (HilExp.AccessExpression.to_access_path receiver) astate - | Call (_, Direct callee_pname, _, _, _) when is_blacklisted_method callee_pname -> - astate - | Call (ret_var, Direct callee_pname, _, _, loc) - when Annotations.pname_has_return_annot callee_pname ~attrs_of_pname:lookup_local_attributes - Annotations.ia_is_nullable -> - let call_site = CallSite.make callee_pname loc in - add_nullable_ap (ret_var, []) (CallSites.singleton call_site) astate - | Call (_, Direct callee_pname, args, _, loc) when is_objc_container_add_method callee_pname -> - check_nil_in_objc_container proc_data loc args astate - | Call (_, Direct callee_pname, HilExp.AccessExpression receiver :: _, _, loc) - when is_non_objc_instance_method callee_pname -> - check_ap proc_data loc (HilExp.AccessExpression.to_access_path receiver) astate - | Call - (((_, ret_typ) as ret_var), Direct callee_pname, HilExp.AccessExpression receiver :: _, _, _) - when Typ.is_pointer ret_typ && is_objc_instance_method callee_pname -> ( - match longest_nullable_prefix (HilExp.AccessExpression.to_access_path receiver) astate with - | None -> - astate - | Some (_, call_sites) -> - (* Objective C method will return nil when called on a nil receiver *) - add_nullable_ap (ret_var, []) call_sites astate ) - | Call (ret_var, _, _, _, _) -> - remove_nullable_ap (ret_var, []) astate - | Assign (lhs_access_expr, rhs, loc) -> ( - let lhs = HilExp.AccessExpression.to_access_path lhs_access_expr in - Option.iter - ~f:(fun (nullable_ap, call_sites) -> - if not (is_pointer_assignment proc_data.ProcData.tenv nullable_ap rhs) then - (* TODO (T22426288): Undertand why the pointer derference and the pointer - assignment have the same HIL representation *) - report_nullable_dereference nullable_ap call_sites proc_data loc ) - (longest_nullable_prefix lhs astate) ; - match rhs with - | HilExp.AccessExpression access_expr -> ( - try - (* Add the lhs to the list of nullable values if the rhs is nullable *) - let ap = HilExp.AccessExpression.to_access_path access_expr in - add_nullable_ap lhs (find_nullable_ap ap astate) astate - with Caml.Not_found -> - (* Remove the lhs from the list of nullable values if the rhs is not nullable *) - remove_nullable_ap lhs astate ) - | _ -> - (* Remove the lhs from the list of nullable values if the rhs is not an access path *) - remove_nullable_ap lhs astate ) - | Assume (HilExp.AccessExpression access_expr, _, _, _) -> - assume_pnames_notnull (HilExp.AccessExpression.to_access_path access_expr) astate - | Assume - ( ( HilExp.BinaryOperator (Binop.Ne, HilExp.AccessExpression access_expr, exp) - | HilExp.BinaryOperator (Binop.Ne, exp, HilExp.AccessExpression access_expr) ) - , _ - , _ - , _ ) - | Assume - ( HilExp.UnaryOperator - ( Unop.LNot - , ( HilExp.BinaryOperator (Binop.Eq, HilExp.AccessExpression access_expr, exp) - | HilExp.BinaryOperator (Binop.Eq, exp, HilExp.AccessExpression access_expr) ) - , _ ) - , _ - , _ - , _ ) -> - if HilExp.is_null_literal exp then - assume_pnames_notnull (HilExp.AccessExpression.to_access_path access_expr) astate - else astate - | _ -> - astate - - - let pp_session_name _node fmt = F.pp_print_string fmt "nullability check" -end - -module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (ProcCfg.Exceptional)) - -let checker {Callbacks.summary; exe_env} = - let initial = (NullableAP.empty, NullCheckedPname.empty) in - let tenv = Exe_env.get_tenv exe_env (Summary.get_proc_name summary) in - let proc_data = ProcData.make summary tenv () in - ignore (Analyzer.compute_post proc_data ~initial) ; - summary diff --git a/infer/src/nullsafe/NullabilityCheck.mli b/infer/src/nullsafe/NullabilityCheck.mli deleted file mode 100644 index 489676eb8..000000000 --- a/infer/src/nullsafe/NullabilityCheck.mli +++ /dev/null @@ -1,10 +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. - *) - -open! IStd - -val checker : Callbacks.proc_callback_t diff --git a/infer/src/nullsafe/NullabilitySuggest.ml b/infer/src/nullsafe/NullabilitySuggest.ml deleted file mode 100644 index e2fb64a5b..000000000 --- a/infer/src/nullsafe/NullabilitySuggest.ml +++ /dev/null @@ -1,236 +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. - *) -open! IStd -module F = Format -module L = Logging -module MF = MarkupFormatter - -module UseDefChain = struct - type t = - | DependsOn of (Location.t * AccessPath.t) - | NullDefCompare of (Location.t * AccessPath.t) - | NullDefAssign of (Location.t * AccessPath.t) - [@@deriving compare] - - let leq ~lhs ~rhs = compare lhs rhs <= 0 - - (* Keep only one chain in join/widen as we are going to report only one - * trace to the user eventually. *) - let join lhs rhs = if leq ~lhs ~rhs then rhs else lhs - - let widen ~prev ~next ~num_iters:_ = join prev next - - let pp fmt = function - | NullDefAssign (loc, ap) -> - F.fprintf fmt "NullDefAssign(%a, %a)" Location.pp loc AccessPath.pp ap - | NullDefCompare (loc, ap) -> - F.fprintf fmt "NullDefCompare(%a, %a)" Location.pp loc AccessPath.pp ap - | DependsOn (loc, ap) -> - F.fprintf fmt "DependsOn(%a, %a)" Location.pp loc AccessPath.pp ap - - - module Set = Caml.Set.Make (struct - type nonrec t = t - - let compare = compare - end) -end - -module Domain = AbstractDomain.Map (AccessPath) (UseDefChain) - -type extras = ProcData.no_extras - -module TransferFunctions (CFG : ProcCfg.S) = struct - module CFG = CFG - module Domain = Domain - - type nonrec extras = extras - - let is_access_nullable ap proc_data = - match AccessPath.get_field_and_annotation ap proc_data.ProcData.tenv with - | Some (_, annot_item) -> - Annotations.ia_is_nullable annot_item - | _ -> - false - - - let rec nullable_usedef_chain_of exp lhs astate loc = - match exp with - | HilExp.Cast (_, e) -> - nullable_usedef_chain_of e lhs astate loc - | HilExp.Constant (Cint n) when IntLit.isnull n -> - Some (UseDefChain.NullDefAssign (loc, lhs)) - | HilExp.AccessExpression access_expr -> ( - try - let ap = HilExp.AccessExpression.to_access_path access_expr in - match Domain.find ap astate with - | UseDefChain.NullDefCompare _ -> - (* Stop NullDefCompare from propagating here because we want to prevent - * the checker from suggesting @Nullable on y in the following case: - * if (x == null) ... else { y = x; } *) - None - | _ -> - Some (UseDefChain.DependsOn (loc, ap)) - with Caml.Not_found -> None ) - | _ -> - None - - - let rec extract_null_compare_expr = function - | HilExp.Cast (_, e) -> - extract_null_compare_expr e - | HilExp.BinaryOperator ((Eq | Ne), HilExp.AccessExpression access_expr, exp) - | HilExp.BinaryOperator ((Eq | Ne), exp, HilExp.AccessExpression access_expr) -> - Option.some_if (HilExp.is_null_literal exp) - (HilExp.AccessExpression.to_access_path access_expr) - | _ -> - None - - - let exec_instr (astate : Domain.t) proc_data _ (instr : HilInstr.t) = - match instr with - | Assume (expr, _, _, loc) -> ( - match extract_null_compare_expr expr with - | Some ap when not (is_access_nullable ap proc_data) -> - let udchain = UseDefChain.NullDefCompare (loc, ap) in - Domain.add ap udchain astate - | _ -> - astate ) - | Call _ -> - (* For now we just assume the callee always return non-null *) - astate - | Assign (lhs_access_expr, rhs, loc) -> - let lhs = HilExp.AccessExpression.to_access_path lhs_access_expr in - if not (is_access_nullable lhs proc_data) then - match nullable_usedef_chain_of rhs lhs astate loc with - | Some udchain -> - Domain.add lhs udchain astate - | None -> - astate - else astate - | Metadata _ -> - astate - - - let pp_session_name _node fmt = F.pp_print_string fmt "nullability suggest" -end - -module Analyzer = LowerHil.MakeAbstractInterpreter (TransferFunctions (ProcCfg.Exceptional)) - -let make_error_trace astate ap ud = - let name_of ap = - match AccessPath.get_last_access ap with - | Some (AccessPath.FieldAccess field_name) -> - "Field " ^ Fieldname.get_field_name field_name - | Some (AccessPath.ArrayAccess _) -> - "Some array element" - | None -> - "Variable" - in - let open UseDefChain in - let rec error_trace_impl seen depth ap = function - | NullDefAssign (loc, src) -> - let msg = F.sprintf "%s is assigned null here" (name_of src) in - let ltr = [Errlog.make_trace_element depth loc msg []] in - Some (loc, ltr) - | NullDefCompare (loc, src) -> - let msg = F.sprintf "%s is compared to null here" (name_of src) in - let ltr = [Errlog.make_trace_element depth loc msg []] in - Some (loc, ltr) - | DependsOn (loc, dep) -> ( - match Domain.find dep astate with - | exception Caml.Not_found -> - None - | ud' when Set.mem ud' seen -> - None - | ud' -> - let msg = F.sprintf "%s could be assigned here" (name_of ap) in - let trace_elem = Errlog.make_trace_element depth loc msg [] in - let seen' = Set.add ud' seen in - Option.map - (error_trace_impl seen' (depth + 1) dep ud') - ~f:(fun (_, trace) -> (loc, trace_elem :: trace)) ) - in - error_trace_impl Set.empty 0 ap ud - - -let pretty_field_name proc_data field_name = - match Summary.get_proc_name proc_data.ProcData.summary with - | Procname.Java jproc_name -> - let proc_class_name = Procname.Java.get_class_name jproc_name in - let field_class_name = Fieldname.get_class_name field_name |> Typ.Name.name in - if String.equal proc_class_name field_class_name then Fieldname.get_field_name field_name - else Fieldname.to_simplified_string field_name - | _ -> - (* This format is subject to change once this checker gets to run on C/Cpp/ObjC *) - Fieldname.to_string field_name - - -(* Checks if a field name stems from a class outside the domain of what is analyzed by Infer *) -let is_outside_codebase proc_name field_name = - match proc_name with - | Procname.Java _ -> - Typ.Name.Java.is_external (Fieldname.get_class_name field_name) - | _ -> - false - - -let checker {Callbacks.summary; exe_env} = - let proc_desc = Summary.get_proc_desc summary in - let proc_name = Procdesc.get_proc_name proc_desc in - let tenv = Exe_env.get_tenv exe_env proc_name in - let annotation = Localise.nullable_annotation_name proc_name in - let report astate (proc_data : extras ProcData.t) = - let report_access_path ap udchain = - match AccessPath.get_field_and_annotation ap proc_data.tenv with - | Some (field_name, _) when is_outside_codebase proc_name field_name -> - (* Skip reporting when the field is outside the analyzed codebase. - Note that we do similar filtering on high level which is common - for all checkers. - But this one is different: here we look NOT at the function - to be reported (the one that is using the field), but the root - cause (the field with the wrong annotation itself). - NOTE: Ideally we'd like to support such filtering in the way that - is agnostic to particular checker, but it is not trivial to - do, so let's do it in ad hoc way. - *) - () - | Some (field_name, _) when Fieldname.is_java_captured_parameter field_name -> - (* Skip reporting when field comes from generated code *) - () - | Some (field_name, _) -> - let message = - F.asprintf "Field %a should be annotated with %a" MF.pp_monospaced - (pretty_field_name proc_data field_name) - MF.pp_monospaced annotation - in - let loc, ltr = - match make_error_trace astate ap udchain with - | Some (loc, ltr) -> - (loc, Some ltr) - | None -> - (Procdesc.get_loc proc_desc, None) - in - Reporting.log_warning summary ~loc ?ltr IssueType.nullsafe_field_not_nullable message - | _ -> - () - in - Domain.iter report_access_path astate - in - if AndroidFramework.is_destroy_method proc_name then - (* Skip the fields nullified in Fragment onDestroy and onDestroyView *) - summary - else - (* Assume all fields are not null in the beginning *) - let initial = Domain.empty in - let proc_data = ProcData.make_default summary tenv in - ( match Analyzer.compute_post proc_data ~initial with - | Some post -> - report post proc_data - | None -> - L.internal_error "Analyzer failed to compute post for %a@." Procname.pp proc_name ) ; - summary diff --git a/infer/src/nullsafe/NullabilitySuggest.mli b/infer/src/nullsafe/NullabilitySuggest.mli deleted file mode 100644 index e49449258..000000000 --- a/infer/src/nullsafe/NullabilitySuggest.mli +++ /dev/null @@ -1,11 +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. - *) -(* Module that suggest adding nullability annotations *) - -open! IStd - -val checker : Callbacks.proc_callback_t diff --git a/infer/tests/codetoanalyze/cpp/conflicts/Makefile b/infer/tests/codetoanalyze/cpp/conflicts/Makefile index 665dcbd58..3a9659583 100644 --- a/infer/tests/codetoanalyze/cpp/conflicts/Makefile +++ b/infer/tests/codetoanalyze/cpp/conflicts/Makefile @@ -7,7 +7,7 @@ TESTS_DIR = ../../.. CLANG_OPTIONS = -c -x c++ -std=c++14 -INFER_OPTIONS = --no-default-checkers --biabduction --nullsafe --project-root $(TESTS_DIR) +INFER_OPTIONS = --no-default-checkers --biabduction --project-root $(TESTS_DIR) INFERPRINT_OPTIONS = --issues-tests SOURCES = $(wildcard *.cpp) diff --git a/infer/tests/codetoanalyze/cpp/conflicts/issues.exp b/infer/tests/codetoanalyze/cpp/conflicts/issues.exp index 27b7536fa..f2a1c89f2 100644 --- a/infer/tests/codetoanalyze/cpp/conflicts/issues.exp +++ b/infer/tests/codetoanalyze/cpp/conflicts/issues.exp @@ -1,3 +1,2 @@ codetoanalyze/cpp/conflicts/test.cpp, test1_bad, 2, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure test1_bad(),Skipping nullableMethod(): method has no implementation] -codetoanalyze/cpp/conflicts/test.cpp, test2_bad, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of nullableMethod(),definition of nullableMethod] codetoanalyze/cpp/conflicts/test.cpp, test3_bad, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure test3_bad(),Skipping nullableMethod(): method has no implementation,Loop condition is true. Entering loop body,Skipping nullableMethod(): method has no implementation,Loop condition is false. Leaving loop] diff --git a/infer/tests/codetoanalyze/cpp/nullable/Makefile b/infer/tests/codetoanalyze/cpp/nullable/Makefile deleted file mode 100644 index 1cb682130..000000000 --- a/infer/tests/codetoanalyze/cpp/nullable/Makefile +++ /dev/null @@ -1,17 +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. - -TESTS_DIR = ../../.. - -# see explanations in cpp/errors/Makefile for the custom isystem -CLANG_OPTIONS = -x c++ -std=c++11 -nostdinc++ -isystem$(ROOT_DIR) -isystem$(CLANG_INCLUDES)/c++/v1/ -c -INFER_OPTIONS = --biabduction --nullsafe --debug-exceptions --project-root $(TESTS_DIR) -INFERPRINT_OPTIONS = --issues-tests - -SOURCES = $(wildcard *.cpp) - -include $(TESTS_DIR)/clang.make - -infer-out/report.json: $(MAKEFILE_LIST) diff --git a/infer/tests/codetoanalyze/cpp/nullable/example.cpp b/infer/tests/codetoanalyze/cpp/nullable/example.cpp deleted file mode 100644 index abf5457d5..000000000 --- a/infer/tests/codetoanalyze/cpp/nullable/example.cpp +++ /dev/null @@ -1,62 +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. - */ -class T { - private: - int* unnanotated_field; - int* _Nullable nullable_field; - int* _Nonnull nonnull_field; - - public: - void assign_nullable_field_to_null_okay() { nullable_field = nullptr; } - - public: - void assign_unnanotated_field_to_null_bad() { unnanotated_field = nullptr; } - - public: - void assign_nonnull_field_to_null_bad() { nonnull_field = nullptr; } - - public: - void test_nullable_field_for_null_okay() { - if (nullable_field == nullptr) { - } - } - - public: - void test_unnanotated_field_for_null_bad() { - if (unnanotated_field == nullptr) { - } - } - - public: - void test_nonnull_field_for_null_bad() { - if (nonnull_field == nullptr) { - } - } - - public: - void dereference_unnanotated_field_okay() { *unnanotated_field = 42; } - - public: - void dereference_nonnull_field_okay() { *nonnull_field = 42; } - - public: - void dereference_nullable_field_bad() { *nullable_field = 42; } - - public: - void dereference_unnanotated_field_after_test_for_null_bad() { - if (unnanotated_field == nullptr) { - *unnanotated_field = 42; - } - } - - public: - void FP_dereference_nonnull_field_after_test_for_null_okay() { - if (nonnull_field == nullptr) { - *nonnull_field = 42; - } - } -}; diff --git a/infer/tests/codetoanalyze/cpp/nullable/issues.exp b/infer/tests/codetoanalyze/cpp/nullable/issues.exp deleted file mode 100644 index 996383ee2..000000000 --- a/infer/tests/codetoanalyze/cpp/nullable/issues.exp +++ /dev/null @@ -1,53 +0,0 @@ -codetoanalyze/cpp/nullable/example.cpp, T::FP_dereference_nonnull_field_after_test_for_null_okay, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field nonnull_field is compared to null here] -codetoanalyze/cpp/nullable/example.cpp, T::FP_dereference_nonnull_field_after_test_for_null_okay, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure FP_dereference_nonnull_field_after_test_for_null_okay,Taking true branch] -codetoanalyze/cpp/nullable/example.cpp, T::assign_nonnull_field_to_null_bad, 0, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field nonnull_field is assigned null here] -codetoanalyze/cpp/nullable/example.cpp, T::assign_unnanotated_field_to_null_bad, 0, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field unnanotated_field is assigned null here] -codetoanalyze/cpp/nullable/example.cpp, T::dereference_nullable_field_bad, 0, NULL_DEREFERENCE, B1, ERROR, [start of procedure dereference_nullable_field_bad] -codetoanalyze/cpp/nullable/example.cpp, T::dereference_unnanotated_field_after_test_for_null_bad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field unnanotated_field is compared to null here] -codetoanalyze/cpp/nullable/example.cpp, T::dereference_unnanotated_field_after_test_for_null_bad, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure dereference_unnanotated_field_after_test_for_null_bad,Taking true branch] -codetoanalyze/cpp/nullable/example.cpp, T::test_nonnull_field_for_null_bad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field nonnull_field is compared to null here] -codetoanalyze/cpp/nullable/example.cpp, T::test_unnanotated_field_for_null_bad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field unnanotated_field is compared to null here] -codetoanalyze/cpp/nullable/method.cpp, assignNullableValueBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of p,assignment of the nullable value,definition of mayReturnNullPointer] -codetoanalyze/cpp/nullable/method.cpp, assignNullableValueBad, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure assignNullableValueBad(),start of procedure mayReturnNullPointer,Taking true branch,return from a call to T::mayReturnNullPointer] -codetoanalyze/cpp/nullable/method.cpp, avoidDoubleReportingBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of p,assignment of the nullable value,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, avoidDoubleReportingBad, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure avoidDoubleReportingBad(),start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, callMethodOnNullableObjectBad, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::mayReturnNullObject,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, callMethodOnNullableObjectBad, 1, NULL_DEREFERENCE, B5, ERROR, [start of procedure callMethodOnNullableObjectBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, callMethodOnNullableObjectOkay, 2, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure callMethodOnNullableObjectOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, dereferenceFieldOfNullableObjectBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of p,assignment of the nullable value,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, dereferenceFieldOfNullableObjectBad, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure dereferenceFieldOfNullableObjectBad(),start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, dereferenceOfAliasesCheckedForNullOkay, 3, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure dereferenceOfAliasesCheckedForNullOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, methodAlwaysCheckedForNullOkay, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure methodAlwaysCheckedForNullOkay(),Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, methodAlwaysCheckedForNullOkay, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure methodAlwaysCheckedForNullOkay(),Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, methodCallOnFieldOfNullableObjectBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of p,assignment of the nullable value,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, methodCallOnFieldOfNullableObjectBad, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure methodCallOnFieldOfNullableObjectBad(),start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, methodCheckedForNullAndReturnOkay, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure methodCheckedForNullAndReturnOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, methodCheckedForNullAndReturnOkay, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure methodCheckedForNullAndReturnOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, methodCheckedForNullOkay, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure methodCheckedForNullOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, methodCheckedForNullOkay, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure methodCheckedForNullOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, methodNotAlwaysCheckedForNullBad, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure methodNotAlwaysCheckedForNullBad(),Taking false branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, methodNotAlwaysCheckedForNullBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::mayReturnNullObject,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, methodNotAlwaysCheckedForNullBad, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure methodNotAlwaysCheckedForNullBad(),Taking false branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, methodTestedForNullOkay, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure methodTestedForNullOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, methodTestedForNullOkay, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure methodTestedForNullOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, nullableAssignmentInOneBranchBad, 7, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of p,assignment of the nullable value,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, nullableAssignmentInOneBranchBad, 7, NULL_DEREFERENCE, B2, ERROR, [start of procedure nullableAssignmentInOneBranchBad(),Taking true branch,start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, onlyReportOnceBad, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::mayReturnNullObject,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, onlyReportOnceBad, 1, NULL_DEREFERENCE, B5, ERROR, [start of procedure onlyReportOnceBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, onlyReportOnceBad, 3, NULL_DEREFERENCE, B5, ERROR, [start of procedure onlyReportOnceBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,start of procedure doSomething,return from a call to T::doSomething,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, pointerTestBad, 2, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure pointerTestBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, pointerTestBad, 5, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of p,assignment of the nullable value,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, pointerTestBad, 5, NULL_DEREFERENCE, B2, ERROR, [start of procedure pointerTestBad(),start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, pointerTestOkay, 2, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure pointerTestOkay(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, reassigningNullablePointerOkay, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value] -codetoanalyze/cpp/nullable/method.cpp, reassigningNullablePointerToNullOkay, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationInNotNullElseBranchBad, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure reportsViolationInNotNullElseBranchBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationInNotNullElseBranchBad, 3, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::mayReturnNullObject,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationInNotNullElseBranchBad, 3, NULL_DEREFERENCE, B5, ERROR, [start of procedure reportsViolationInNotNullElseBranchBad(),start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject,Taking false branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationInNullBranchBad, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure reportsViolationInNullBranchBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationInNullBranchBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::mayReturnNullObject,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationInNullBranchBad, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure reportsViolationInNullBranchBad(),start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject,Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationOutsideOfNullCheckBad, 1, NULL_TEST_AFTER_DEREFERENCE, no_bucket, WARNING, [start of procedure reportsViolationOutsideOfNullCheckBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking false branch] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationOutsideOfNullCheckBad, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure reportsViolationOutsideOfNullCheckBad(),start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject,Taking true branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationOutsideOfNullCheckBad, 4, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::mayReturnNullObject,definition of mayReturnNullObject] -codetoanalyze/cpp/nullable/method.cpp, reportsViolationOutsideOfNullCheckBad, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure reportsViolationOutsideOfNullCheckBad(),start of procedure mayReturnNullObject,Taking true branch,return from a call to T::mayReturnNullObject,Taking false branch,start of procedure mayReturnNullObject,Taking false branch,return from a call to T::mayReturnNullObject] diff --git a/infer/tests/codetoanalyze/cpp/nullable/method.cpp b/infer/tests/codetoanalyze/cpp/nullable/method.cpp deleted file mode 100644 index 9f794de3c..000000000 --- a/infer/tests/codetoanalyze/cpp/nullable/method.cpp +++ /dev/null @@ -1,170 +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. - */ -bool star(); - -class T { - public: - int x; - T* field; - - public: - int* _Nullable mayReturnNullPointer() { - if (star()) { - return nullptr; - } else { - return new int; - } - } - - public: - T* _Nullable mayReturnNullObject() { - if (star()) { - return nullptr; - } else { - return this; - } - } - - public: - T* doesNotReturnNullObject() { return new T(); } - - public: - void doSomething() {} -}; - -void assignNullableValueBad(T* t) { - int* p = t->mayReturnNullPointer(); - *p = 42; -} - -void reassigningNullablePointerOkay(T* t) { - int* p = t->mayReturnNullPointer(); - p = new int; // does not report here - *p = 42; // does not report here -} - -void reassigningNullablePointerToNullOkay(T* t) { - int* p = t->mayReturnNullPointer(); - p = nullptr; // does not report here -} - -void callMethodOnNullableObjectBad(T* t) { - t->mayReturnNullObject()->doSomething(); -} - -void callMethodOnNullableObjectOkay(T* t) { - T* p = t->mayReturnNullObject(); - if (p != nullptr) { - p->doSomething(); - } -} - -void dereferenceFieldOfNullableObjectBad(T* t) { - T* p = t->mayReturnNullObject(); - p->x = 42; -} - -void methodCallOnFieldOfNullableObjectBad(T* t) { - T* p = t->mayReturnNullObject(); - p->field->doSomething(); -} - -void avoidDoubleReportingBad(T* t) { - T* p = t->mayReturnNullObject(); - p->doSomething(); // reports here - p->doSomething(); // does not report here -} - -void nullableAssignmentInOneBranchBad(T* t) { - T* p; - if (star()) { - p = t->mayReturnNullObject(); - } else { - p = t->doesNotReturnNullObject(); - } - p->doSomething(); // reports here -} - -void methodCheckedForNullOkay(T* t) { - if (t->mayReturnNullObject() != nullptr) { - t->mayReturnNullObject()->doSomething(); // does not report here - } -} - -void methodCheckedForNullAndReturnOkay(T* t) { - if (t->mayReturnNullObject() == nullptr) { - return; - } - t->mayReturnNullObject()->doSomething(); // does not report here -} - -void reportsViolationOutsideOfNullCheckBad(T* t) { - if (t->mayReturnNullObject() != nullptr) { - t->mayReturnNullObject()->doSomething(); // does not report here - } - t->mayReturnNullObject()->doSomething(); // reports here -} - -void reportsViolationInNullBranchBad(T* t) { - if (t->mayReturnNullObject() == nullptr) { - t->mayReturnNullObject()->doSomething(); // reports here - } -} - -void reportsViolationInNotNullElseBranchBad(T* t) { - if (t->mayReturnNullObject() != nullptr) { - } else { - t->mayReturnNullObject()->doSomething(); // reports here - } -} - -void methodAlwaysCheckedForNullOkay(T* t) { - if (star() && t->mayReturnNullObject() != nullptr) { - t->mayReturnNullObject()->doSomething(); // does not report here - } -} - -void methodNotAlwaysCheckedForNullBad(T* t) { - if (star() || t->mayReturnNullObject() != nullptr) { - t->mayReturnNullObject()->doSomething(); // reports here - } -} - -void onlyReportOnceBad(T* t) { - t->mayReturnNullObject()->doSomething(); // reports here - // ... - t->mayReturnNullObject()->doSomething(); // does not report here -} - -void dereferenceOfAliasesCheckedForNullOkay(T* t) { - T* s = t->mayReturnNullObject(); - T* r = s; - if (r != nullptr) { - s->doSomething(); - } -} - -void pointerTestOkay(T* t) { - T* p = t->mayReturnNullObject(); - if (p) { - p->doSomething(); - } -} - -void pointerTestBad(T* t) { - T* p = t->mayReturnNullObject(); - if (p) { - // ... - } - p->doSomething(); -} - -void methodTestedForNullOkay(T* t) { - if (t->mayReturnNullObject()) { - t->mayReturnNullObject()->doSomething(); - } -} diff --git a/infer/tests/codetoanalyze/java/checkers/Makefile b/infer/tests/codetoanalyze/java/checkers/Makefile index 0ce68d834..43d7754b3 100644 --- a/infer/tests/codetoanalyze/java/checkers/Makefile +++ b/infer/tests/codetoanalyze/java/checkers/Makefile @@ -8,7 +8,7 @@ TESTS_DIR = ../../.. INFER_OPTIONS = \ --debug-exceptions --no-default-checkers \ --fragment-retains-view --immutable-cast --printf-args --quandary \ - --nullsafe --racerd \ + --racerd \ INFERPRINT_OPTIONS = --issues-tests SOURCES = $(wildcard *.java) $(wildcard $(TESTS_DIR)/external/library/*.java) diff --git a/infer/tests/codetoanalyze/java/checkers/issues.exp b/infer/tests/codetoanalyze/java/checkers/issues.exp index 3b47e747d..e82e114b0 100644 --- a/infer/tests/codetoanalyze/java/checkers/issues.exp +++ b/infer/tests/codetoanalyze/java/checkers/issues.exp @@ -3,17 +3,6 @@ codetoanalyze/java/checkers/FragmentRetainsViewExample.java, codetoanalyze.java. codetoanalyze/java/checkers/FragmentRetainsViewExample.java, codetoanalyze.java.checkers.FragmentRetainsViewExample.onDestroyView():void, 0, CHECKERS_FRAGMENT_RETAINS_VIEW, no_bucket, WARNING, [] codetoanalyze/java/checkers/ImmutableCast.java, codetoanalyze.java.checkers.ImmutableCast.badCast(com.google.common.collect.ImmutableList):java.util.List, 0, CHECKERS_IMMUTABLE_CAST, no_bucket, WARNING, [Method badCast(...) returns class com.google.common.collect.ImmutableList but the return type is class java.util.List. Make sure that users of this method do not try to modify the collection.] codetoanalyze/java/checkers/ImmutableCast.java, codetoanalyze.java.checkers.ImmutableCast.badCastFromField():java.util.List, 0, CHECKERS_IMMUTABLE_CAST, no_bucket, WARNING, [Method badCastFromField() returns class com.google.common.collect.ImmutableList but the return type is class java.util.List. Make sure that users of this method do not try to modify the collection.] -codetoanalyze/java/checkers/NullableSuggest.java, codetoanalyze.java.checkers.NullableSuggest.assignNullBad():void, 0, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field obj0 is assigned null here] -codetoanalyze/java/checkers/NullableSuggest.java, codetoanalyze.java.checkers.NullableSuggest.assignNullToFieldInOtherClassBad():void, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field obj2 is assigned null here] -codetoanalyze/java/checkers/NullableSuggest.java, codetoanalyze.java.checkers.NullableSuggest.assignNullToFieldTransitiveBad(boolean):void, 2, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field obj0 could be assigned here,Variable could be assigned here,Variable could be assigned here,Variable is assigned null here] -codetoanalyze/java/checkers/NullableSuggest.java, codetoanalyze.java.checkers.NullableSuggest.assignNullToFieldTransitiveLoopBad(int):void, 6, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field obj0 could be assigned here,Some array element could be assigned here,Variable is assigned null here] -codetoanalyze/java/checkers/NullableSuggest.java, codetoanalyze.java.checkers.NullableSuggest.compareNullToFieldBad():void, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field obj0 is compared to null here] -codetoanalyze/java/checkers/NullableSuggest.java, codetoanalyze.java.checkers.NullableSuggest.multipleChainsAlwaysSelectShortestBad(boolean):void, 5, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field obj0 could be assigned here,Variable is assigned null here] -codetoanalyze/java/checkers/NullableViolation.java, codetoanalyze.java.checkers.NullableViolation.dereferenceNullableMethodBad():void, 0, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of NullableViolation.returnsNullable(),definition of returnsNullable] -codetoanalyze/java/checkers/NullableViolation.java, codetoanalyze.java.checkers.NullableViolation.dereferenceNullableMethodInElseBranchBad():void, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of NullableViolation.returnsNullable(),definition of returnsNullable] -codetoanalyze/java/checkers/NullableViolation.java, codetoanalyze.java.checkers.NullableViolation.dereferenceNullableMethodIncorrectlyCheckedForNullBad():void, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of NullableViolation.returnsNullable(),definition of returnsNullable] -codetoanalyze/java/checkers/NullableViolation.java, codetoanalyze.java.checkers.NullableViolation.dereferenceNullableMethodNotAlwaysCheckedForNullBad():void, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of NullableViolation.returnsNullable(),definition of returnsNullable] -codetoanalyze/java/checkers/NullableViolation.java, codetoanalyze.java.checkers.NullableViolation.dereferenceNullableReturnValueBad():void, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of t,assignment of the nullable value,definition of returnsNullable] codetoanalyze/java/checkers/PrintfArgsChecker.java, codetoanalyze.java.checkers.PrintfArgsChecker.formatStringIsNotLiteral(java.io.PrintStream):void, 1, CHECKERS_PRINTF_ARGS, no_bucket, WARNING, [] codetoanalyze/java/checkers/PrintfArgsChecker.java, codetoanalyze.java.checkers.PrintfArgsChecker.stringInsteadOfInteger(java.io.PrintStream):void, 0, CHECKERS_PRINTF_ARGS, no_bucket, ERROR, [] codetoanalyze/java/checkers/PrintfArgsChecker.java, codetoanalyze.java.checkers.PrintfArgsChecker.wrongNumberOfArguments(java.io.PrintStream):void, 0, CHECKERS_PRINTF_ARGS, no_bucket, ERROR, [] diff --git a/infer/tests/codetoanalyze/objc/nullable/Examples.m b/infer/tests/codetoanalyze/objc/nullable/Examples.m deleted file mode 100644 index dcee1b3ee..000000000 --- a/infer/tests/codetoanalyze/objc/nullable/Examples.m +++ /dev/null @@ -1,290 +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. - */ -#import -#import "Library.h" - -int* __nullable returnsNull(); - -typedef struct s_ { - int x; -} S; - -@interface T : NSObject -- (NSObject* _Nullable)nullableMethod; -- (T* _Nullable)nullableT; -@property(nonatomic) S structProperty; -@property(nonatomic) S* pointerProperty; -@property(nonatomic, nullable) NSObject* nullableProperty; -@end - -@implementation T { - int* unnanotatedField; - int* __nullable nullableField; - int* nonnullField; -} - -- (void)assignNullableFieldToNullOkay { - nullableField = nil; -} - -- (void)assignUnnanotatedFieldToNullBad { - unnanotatedField = nil; -} - -- (void)assignNonnullFieldToNullBad { - nonnullField = nil; -} - -- (void)testNullableFieldForNullOkay { - if (nullableField == nil) { - } -} - -- (void)testUnnanotatedFieldForNullBad { - if (unnanotatedField == nil) { - } -} - -- (int)DeadStoreFP_testUnnanotatedFieldInClosureBad { - int (^testField)(int defaultValue); - testField = ^(int defaultValue) { - if (unnanotatedField != nil) { - return *unnanotatedField; - } else { - return defaultValue; - } - }; - return testField(42); -} - -- (void)testNonnullFieldForNullBad { - if (nonnullField == nil) { - } -} - -- (void)dereferenceUnnanotatedFieldOkay { - *unnanotatedField = 42; -} - -- (void)dereferenceNonnullFieldOkay { - *nonnullField = 42; -} - -- (void)dereferenceNullableFieldBad { - *nullableField = 42; -} - -- (void)dereferenceUnnanotatedFieldAfterTestForNullBad { - if (unnanotatedField == nil) { - *unnanotatedField = 42; - } -} - -- (void)FP_dereferenceNonnullFieldAfterTestForNullOkay { - if (nonnullField == nil) { - *nonnullField = 42; - } -} - -- (void)dereferenceNullableFunctionBad { - int* p = returnsNull(); - *p = 42; -} - -- (void)dereferenceNullableFunction1Ok { - int* p = returnsNull(); - if (p) { - *p = 42; - } -} - -- (void)dereferenceNullableFunction2Ok { - int* p = returnsNull(); - if (p != nil) { - *p = 42; - } -} - -- (NSObject* _Nullable)nullableMethod { - return nil; -} - -- (NSString*)dereferenceNullableMethodOkay { - NSObject* nullableObject = [self nullableMethod]; - return [nullableObject description]; // does not report here -} - -- (void)reassigningNullableObjectOkay { - NSObject* nullableObject = [self nullableMethod]; - nullableObject = nil; // does not report here -} - -- (NSArray*)nullableObjectInNSArrayBad { - NSObject* nullableObject = [self nullableMethod]; - NSArray* array = @[ nullableObject ]; // reports here - return array; -} - -- (NSArray*)nullablePropertyInNSArrayBad { - return @[ self.nullableMethod ]; // reports here -} - -- (NSArray*)nullableMethodCheckedForNullAndReturnOkay { - NSObject* nullableObject = [self nullableMethod]; - NSArray* array; - if (nullableObject == nil) { - return array; - } - array = @[ nullableObject ]; // does not report here - return array; -} - -- (NSArray*)secondElementNullableObjectInNSArrayBad { - NSObject* allocatedObject = [NSObject alloc]; - NSObject* nullableObject = [self nullableMethod]; - NSArray* array = @[ allocatedObject, nullableObject ]; // reports here - return array; -} - -- (NSArray*)nullableObjectInNSArrayOkay { - NSObject* nullableObject = [self nullableMethod]; - NSArray* array; - if (nullableObject) { - array = @[ nullableObject ]; // reports here - } else { - array = @[ @"String" ]; - } - return array; -} - -- (NSArray*)URLWithStringOkay { - NSURL* url = [NSURL URLWithString:@"some/url/string"]; - NSArray* array = @[ url ]; // reports here -} - -- (NSDictionary*)nullableValueInNSDictionaryBad { - NSObject* nullableValue = [self nullableMethod]; - NSMutableDictionary* dict = [NSMutableDictionary - dictionaryWithObjectsAndKeys:@"key", nullableValue, nil]; // reports here - return dict; -} - -- (NSDictionary*)nullableKeyInNSDictionaryBad { - NSObject* nullableKey = [self nullableMethod]; - NSMutableDictionary* dict = [NSMutableDictionary - dictionaryWithObjectsAndKeys:nullableKey, @"value", nil]; // reports here - return dict; -} - -- (NSDictionary*)nullableKeyInNSDictionaryInitBad { - NSObject* nullableKey = [self nullableMethod]; - NSDictionary* dict = [[NSDictionary alloc] - initWithObjectsAndKeys:nullableKey, @"value", nil]; // reports here - return dict; -} - -- (NSDictionary*)nullableValueInNSDictionaryInitBad { - NSObject* nullableValue = [self nullableMethod]; - NSDictionary* dict = [[NSDictionary alloc] - initWithObjectsAndKeys:@"key", nullableValue, nil]; // reports here - return dict; -} - -- (NSDictionary*)nullableKeyInNSDictionaryInitLiteralBad { - NSObject* nullableKey = [self nullableMethod]; - NSDictionary* dict = @{nullableKey : @"value"}; // reports here - return dict; -} - -- (NSDictionary*)nullableValueInNSDictionaryInitLiteralBad { - NSObject* nullableValue = [self nullableMethod]; - NSDictionary* dict = @{@"key" : nullableValue}; // reports here - return dict; -} - -- (NSDictionary*)indirectNullableKeyInNSDictionaryBad { - NSObject* nullableKey = [self nullableMethod]; - NSString* nullableKeyString = [nullableKey description]; - NSDictionary* dict = [[NSDictionary alloc] - initWithObjectsAndKeys:nullableKeyString, @"value", nil]; // reports here - return dict; -} - -- (NSArray*)createArrayByAddingNilBad { - NSArray* array = @[ [NSObject alloc] ]; - return [array arrayByAddingObject:[self nullableMethod]]; -} - -- (NSDictionary*)setNullableObjectInDictionaryBad { - NSMutableDictionary* mutableDict = [NSMutableDictionary dictionary]; - [mutableDict setObject:[self nullableMethod] forKey:@"key"]; // reports here - return mutableDict; -} - -- (NSArray*)addNullableObjectInMutableArrayBad { - NSMutableArray* mutableArray = [[NSMutableArray alloc] init]; - [mutableArray addObject:[self nullableMethod]]; // reports here - return mutableArray; -} - -- (NSArray*)insertNullableObjectInMutableArrayBad { - NSMutableArray* mutableArray = [[NSMutableArray alloc] init]; - [mutableArray insertObject:[self nullableMethod] atIndex:0]; // reports here - return mutableArray; -} - -- (NSArray*)propagateNullabilityOnMethodCallBad { - NSObject* nullableObject = [self nullableMethod]; - NSString* nullableString = - [nullableObject description]; // returns nil if nullableObject is nil - return @[ nullableString ]; // reports here -} - -- (S*)shouldPropagateNullabilityOnPointerTypeBad { - T* nullableT = [self nullableT]; - S* s = nullableT.pointerProperty; // returns nil when nullableT is nil - s->x = 42; // reports here - return s; -} - -- (S)shouldNotPropagateNullabilityOnNonPointerTypeGood { - T* nullableT = [self nullableT]; - S s = - nullableT.structProperty; // returns an empty struct when nullabeT is nil - s.x = 42; // does not report here - return s; -} - -- (NSArray*)pointerAssignmentWithSubtypeOkay:(NSString*)string { - NSObject* nullableObject = [self nullableMethod]; - nullableObject = string; - NSArray* array = @[ nullableObject ]; // does not report here - return array; -} - -- (NSArray*)dereferenceLibraryMethodOk:(L*)object { - NSObject* nullableObject = [object libraryMethod]; - NSArray* array = @[ nullableObject ]; // does not report here - return array; -} - -- (NSArray*)dereferenceNullableLibraryMethodBad:(L*)object { - NSObject* nullableObject = [object nullableLibraryMethod]; - NSArray* array = @[ nullableObject ]; // reports here - return array; -} - -@end - -@protocol P -- (NSObject* _Nullable)nullableMethod; -@end - -NSDictionary* callNullableMethodFromProtocolBad(id

pObject) { - NSObject* nullableObject = [pObject nullableMethod]; - return @{@"key" : nullableObject}; -} diff --git a/infer/tests/codetoanalyze/objc/nullable/Library.h b/infer/tests/codetoanalyze/objc/nullable/Library.h deleted file mode 100644 index 7f2c6a7ee..000000000 --- a/infer/tests/codetoanalyze/objc/nullable/Library.h +++ /dev/null @@ -1,13 +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. - */ - -#import - -@interface L : NSObject -- (NSObject*)libraryMethod; -- (NSObject* _Nullable)nullableLibraryMethod; -@end diff --git a/infer/tests/codetoanalyze/objc/nullable/Makefile b/infer/tests/codetoanalyze/objc/nullable/Makefile deleted file mode 100644 index e735f80af..000000000 --- a/infer/tests/codetoanalyze/objc/nullable/Makefile +++ /dev/null @@ -1,17 +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. - -TESTS_DIR = ../../.. - -CLANG_OPTIONS = -c $(OBJC_CLANG_OPTIONS) -INFER_OPTIONS = --debug-exceptions --no-default-checkers --nullsafe --project-root $(TESTS_DIR) -INFERPRINT_OPTIONS = --issues-tests - -SOURCES = $(wildcard *.m) - -include $(TESTS_DIR)/clang.make -include $(TESTS_DIR)/objc.make - -infer-out/report.json: $(MAKEFILE_LIST) diff --git a/infer/tests/codetoanalyze/objc/nullable/issues.exp b/infer/tests/codetoanalyze/objc/nullable/issues.exp deleted file mode 100644 index a59a7b62b..000000000 --- a/infer/tests/codetoanalyze/objc/nullable/issues.exp +++ /dev/null @@ -1,26 +0,0 @@ -codetoanalyze/objc/nullable/Examples.m, T::FP_dereferenceNonnullFieldAfterTestForNullOkay, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field nonnullField is compared to null here] -codetoanalyze/objc/nullable/Examples.m, T::addNullableObjectInMutableArrayBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::nullableMethod,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::assignNonnullFieldToNullBad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field nonnullField is assigned null here] -codetoanalyze/objc/nullable/Examples.m, T::assignUnnanotatedFieldToNullBad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field unnanotatedField is assigned null here] -codetoanalyze/objc/nullable/Examples.m, T::createArrayByAddingNilBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::nullableMethod,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::dereferenceNullableFunctionBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of p,assignment of the nullable value,definition of returnsNull] -codetoanalyze/objc/nullable/Examples.m, T::dereferenceNullableLibraryMethodBad:, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableObject,assignment of the nullable value,definition of nullableLibraryMethod] -codetoanalyze/objc/nullable/Examples.m, T::dereferenceUnnanotatedFieldAfterTestForNullBad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field unnanotatedField is compared to null here] -codetoanalyze/objc/nullable/Examples.m, T::indirectNullableKeyInNSDictionaryBad, 3, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableKeyString,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::insertNullableObjectInMutableArrayBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::nullableMethod,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullableKeyInNSDictionaryBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableKey,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullableKeyInNSDictionaryInitBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableKey,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullableKeyInNSDictionaryInitLiteralBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableKey,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullableObjectInNSArrayBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableObject,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullablePropertyInNSArrayBad, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::nullableMethod,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullableValueInNSDictionaryBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableValue,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullableValueInNSDictionaryInitBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableValue,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::nullableValueInNSDictionaryInitLiteralBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableValue,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::propagateNullabilityOnMethodCallBad, 4, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableString,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::secondElementNullableObjectInNSArrayBad, 3, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableObject,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::setNullableObjectInDictionaryBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of T::nullableMethod,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, T::shouldPropagateNullabilityOnPointerTypeBad, 3, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of s,assignment of the nullable value,definition of nullableT] -codetoanalyze/objc/nullable/Examples.m, T::testNonnullFieldForNullBad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field nonnullField is compared to null here] -codetoanalyze/objc/nullable/Examples.m, T::testUnnanotatedFieldForNullBad, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field unnanotatedField is compared to null here] -codetoanalyze/objc/nullable/Examples.m, callNullableMethodFromProtocolBad, 2, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereference of nullableObject,assignment of the nullable value,definition of nullableMethod] -codetoanalyze/objc/nullable/Examples.m, objc_blockT::DeadStoreFP_testUnnanotatedFieldInClosureBad_1, 1, NULLSAFE_FIELD_NOT_NULLABLE, no_bucket, WARNING, [Field unnanotatedField is compared to null here] diff --git a/infer/tests/codetoanalyze/objcpp/nullable/Examples.mm b/infer/tests/codetoanalyze/objcpp/nullable/Examples.mm deleted file mode 100644 index a2bf63f22..000000000 --- a/infer/tests/codetoanalyze/objcpp/nullable/Examples.mm +++ /dev/null @@ -1,27 +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. - */ -#import -#import - -@interface A : NSObject { -} -- (char _Nullable*)toString; -@end - -std::string stdStringOK(A* a) { - const char* s1 = [a toString]; - if (s1) { - std::string s2 = std::string(s1); - return s2; - } else - return ""; -} - -std::string stdStringBad(A* a) { - std::string s2 = std::string([a toString]); - return s2; -} diff --git a/infer/tests/codetoanalyze/objcpp/nullable/Makefile b/infer/tests/codetoanalyze/objcpp/nullable/Makefile deleted file mode 100644 index 62aceb639..000000000 --- a/infer/tests/codetoanalyze/objcpp/nullable/Makefile +++ /dev/null @@ -1,17 +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. - -TESTS_DIR = ../../.. - -CLANG_OPTIONS = -c $(OBJCPP_CLANG_OPTIONS) -INFER_OPTIONS = --debug-exceptions --no-default-checkers --nullsafe --project-root $(TESTS_DIR) -INFERPRINT_OPTIONS = --issues-tests - -SOURCES = $(wildcard *.mm) - -include $(TESTS_DIR)/clang.make -include $(TESTS_DIR)/objc.make - -infer-out/report.json: $(MAKEFILE_LIST) diff --git a/infer/tests/codetoanalyze/objcpp/nullable/issues.exp b/infer/tests/codetoanalyze/objcpp/nullable/issues.exp deleted file mode 100644 index 2a8aedb56..000000000 --- a/infer/tests/codetoanalyze/objcpp/nullable/issues.exp +++ /dev/null @@ -1 +0,0 @@ -codetoanalyze/objcpp/nullable/Examples.mm, stdStringBad, 1, NULLSAFE_NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of A::toString,assignment of the nullable value,definition of toString]