From f86d9193a900bb084ce461efe08cbc2c5e660dd7 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Tue, 5 May 2020 03:38:38 -0700 Subject: [PATCH] [nullsafe] stop using SummaryReporting Summary: This turned into a pretty big refactoring: the `IntraproceduralAnalysis.t` needs to be passed around through quite a few functions. These functions usually depended on tenv/proc_desc/proc_name that are already in the `analysis_data` so refactored that too (checking that these were indeed the same as in the `analysis_data` record (using my own eyeballs). Interestingly there is one place where we actually turn the analysis to other proc descs than the original one in eradicate.ml so I've added a small comment there. Reviewed By: mityal Differential Revision: D21351909 fbshipit-source-id: 6e6330e5b --- infer/src/backend/SummaryReporting.ml | 16 -- infer/src/backend/SummaryReporting.mli | 11 -- infer/src/nullsafe/eradicate.ml | 48 ++--- infer/src/nullsafe/eradicateCheckers.ml | 9 +- infer/src/nullsafe/eradicateCheckers.mli | 4 +- infer/src/nullsafe/eradicateChecks.ml | 181 ++++++++--------- infer/src/nullsafe/immutableChecker.ml | 12 +- infer/src/nullsafe/typeCheck.ml | 236 ++++++++++++----------- infer/src/nullsafe/typeCheck.mli | 6 +- infer/src/nullsafe/typeErr.ml | 29 +-- infer/src/nullsafe/typeErr.mli | 16 +- 11 files changed, 266 insertions(+), 302 deletions(-) diff --git a/infer/src/backend/SummaryReporting.ml b/infer/src/backend/SummaryReporting.ml index f7573afad..3d4e4a961 100644 --- a/infer/src/backend/SummaryReporting.ml +++ b/infer/src/backend/SummaryReporting.ml @@ -6,7 +6,6 @@ *) open! IStd -module L = Logging type log_t = Reporting.log_t @@ -25,18 +24,3 @@ let log_warning summary ~loc ?ltr ?extras issue_type error_message = let log_error_using_state summary exn = BiabductionReporting.log_error_using_state (Summary.get_proc_desc summary) (Summary.get_err_log summary) exn - - -let log_issue_deprecated_using_state severity proc_name ?node ?loc ?ltr exn = - if !BiabductionConfig.footprint then - match Summary.OnDisk.get proc_name with - | Some summary -> - let proc_attributes = Summary.get_attributes summary in - let err_log = Summary.get_err_log summary in - BiabductionReporting.log_issue_deprecated_using_state proc_attributes err_log severity ?node - ?loc ?ltr exn - | None -> - L.(die InternalError) - "Trying to report error on procedure %a, but cannot because no summary exists for this \ - procedure. Did you mean to log the error on the caller of %a instead?" - Procname.pp proc_name Procname.pp proc_name diff --git a/infer/src/backend/SummaryReporting.mli b/infer/src/backend/SummaryReporting.mli index 4f0d31898..ac96051e9 100644 --- a/infer/src/backend/SummaryReporting.mli +++ b/infer/src/backend/SummaryReporting.mli @@ -19,14 +19,3 @@ val log_warning : Summary.t -> loc:Location.t -> log_t val log_error_using_state : Summary.t -> exn -> unit (** Add an error to the given summary using biabduction state (DO NOT USE ELSEWHERE). *) - -val log_issue_deprecated_using_state : - Exceptions.severity - -> Procname.t - -> ?node:Procdesc.Node.t - -> ?loc:Location.t - -> ?ltr:Errlog.loc_trace - -> exn - -> unit -(** Report an issue in the given procedure using biabduction state. DEPRECATED as it can create race - conditions between checkers. Use log_error_using_state instead *) diff --git a/infer/src/nullsafe/eradicate.ml b/infer/src/nullsafe/eradicate.ml index b988e43b5..1b31b017b 100644 --- a/infer/src/nullsafe/eradicate.ml +++ b/infer/src/nullsafe/eradicate.ml @@ -10,8 +10,10 @@ module L = Logging module F = Format open Dataflow -let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname curr_pdesc - annotated_signature linereader proc_loc : bool * TypeState.t option = +let callback1 ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) + find_canonical_duplicate calls_this checks idenv annotated_signature linereader proc_loc : + bool * TypeState.t option = + let curr_pname = Procdesc.get_proc_name curr_pdesc in let add_formal typestate (param_signature : AnnotatedSignature.param_signature) = let pvar = Pvar.mk param_signature.mangled curr_pname in let formal_name = param_signature.mangled in @@ -37,7 +39,7 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c (* Check the nullable flag computed for the return value and report inconsistencies. *) let check_return find_canonical_duplicate exit_node final_typestate annotated_signature loc : unit = - let AnnotatedSignature.{ret_annotated_type} = annotated_signature.AnnotatedSignature.ret in + let {AnnotatedSignature.ret_annotated_type} = annotated_signature.AnnotatedSignature.ret in let ret_pvar = Procdesc.get_ret_var curr_pdesc in let ret_range = TypeState.lookup_pvar ret_pvar final_typestate in let typ_found_opt = @@ -50,10 +52,10 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c AnalysisState.set_node exit_node ; if not (List.is_empty checks.TypeCheck.check_ret_type) then List.iter - ~f:(fun f -> f curr_pname curr_pdesc ret_annotated_type.typ typ_found_opt loc) + ~f:(fun f -> f curr_pdesc ret_annotated_type.typ typ_found_opt loc) checks.TypeCheck.check_ret_type ; if checks.TypeCheck.eradicate then - EradicateChecks.check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range + EradicateChecks.check_return_annotation analysis_data find_canonical_duplicate ret_range annotated_signature ret_implicitly_nullable loc in let do_before_dataflow initial_typestate = @@ -73,13 +75,13 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c let pp_name fmt = F.pp_print_string fmt "eradicate" - let do_node tenv node typestate = + let do_node _tenv node typestate = NodePrinter.with_session ~pp_name node ~f:(fun () -> AnalysisState.set_node node ; if Config.write_html then L.d_printfln "before:@\n%a@\n" TypeState.pp typestate ; - let TypeCheck.{normal_flow_typestate; exception_flow_typestates} = - TypeCheck.typecheck_node tenv calls_this checks idenv curr_pname curr_pdesc - find_canonical_duplicate annotated_signature typestate node linereader + let {TypeCheck.normal_flow_typestate; exception_flow_typestates} = + TypeCheck.typecheck_node analysis_data calls_this checks idenv find_canonical_duplicate + annotated_signature typestate node linereader in let normal_flow_typestates = Option.value_map normal_flow_typestate ~f:(fun a -> [a]) ~default:[] @@ -100,14 +102,15 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c (!calls_this, None) -let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_signature linereader - proc_loc : unit = +let analyze_one_procedure ({IntraproceduralAnalysis.tenv; proc_desc; _} as analysis_data) calls_this + checks annotated_signature linereader proc_loc : unit = let idenv = Idenv.create proc_desc in let find_duplicate_nodes = State.mk_find_duplicate_nodes proc_desc in let find_canonical_duplicate node = let duplicate_nodes = find_duplicate_nodes node in try Procdesc.NodeSet.min_elt duplicate_nodes with Caml.Not_found -> node in + let proc_name = Procdesc.get_proc_name proc_desc in let caller_nullsafe_mode = NullsafeMode.of_procname tenv proc_name in let typecheck_proc do_checks pname pdesc proc_details_opt = let ann_sig, loc, idenv_pn = @@ -134,8 +137,10 @@ let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_s if do_checks then (checks, calls_this) else ({TypeCheck.eradicate= false; check_ret_type= []}, ref false) in - callback1 tenv find_canonical_duplicate calls_this' checks' idenv_pn pname pdesc ann_sig - linereader loc + (* NOTE: [analysis_data] has the new [pdesc] *) + callback1 + {analysis_data with proc_desc= pdesc} + find_canonical_duplicate calls_this' checks' idenv_pn ann_sig linereader loc in let do_final_typestate typestate_opt calls_this = let do_typestate typestate = @@ -151,8 +156,8 @@ let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_s let typestates_for_all_constructors_incl_current = Initializers.final_constructor_typestates_lazy tenv proc_name typecheck_proc in - EradicateChecks.check_constructor_initialization tenv find_canonical_duplicate proc_name - proc_desc start_node ~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode + EradicateChecks.check_constructor_initialization analysis_data find_canonical_duplicate + start_node ~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode ~typestates_for_curr_constructor_and_all_initializer_methods ~typestates_for_all_constructors_incl_current proc_loc ; if Config.eradicate_verbose then L.result "Final Typestate@\n%a@." TypeState.pp typestate ) @@ -164,7 +169,7 @@ let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_s in do_final_typestate final_typestate_opt calls_this ; if checks.TypeCheck.eradicate then - EradicateChecks.check_overridden_annotations find_canonical_duplicate tenv proc_name proc_desc + EradicateChecks.check_overridden_annotations analysis_data find_canonical_duplicate annotated_signature ; () @@ -188,7 +193,8 @@ let find_reason_to_skip_analysis proc_name proc_desc = (** Entry point for the nullsafe procedure-level analysis. *) -let analyze checks {IntraproceduralAnalysis.proc_desc; tenv} : NullsafeSummary.t option = +let analyze checks ({IntraproceduralAnalysis.proc_desc; tenv; _} as analysis_data) : + NullsafeSummary.t option = let proc_name = Procdesc.get_proc_name proc_desc in L.debug Analysis Medium "Analysis of %a@\n" Procname.pp proc_name ; match find_reason_to_skip_analysis proc_name proc_desc with @@ -210,14 +216,12 @@ let analyze checks {IntraproceduralAnalysis.proc_desc; tenv} : NullsafeSummary.t (* The main method - during this the actual analysis will happen and TypeErr will be populated with issues (and some of them - reported). *) - analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_signature - linereader loc ; + analyze_one_procedure analysis_data calls_this checks annotated_signature linereader loc ; (* Collect issues that were detected during analysis and put them in summary for further processing *) let issues = TypeErr.get_errors () |> List.map ~f:(fun (issues, _) -> issues) in (* Report errors of "farall" class - those could not be reported during analysis phase. *) - TypeErr.report_forall_issues_and_reset - (EradicateCheckers.report_error tenv) - ~nullsafe_mode:annotated_signature.nullsafe_mode proc_desc ; + TypeErr.report_forall_issues_and_reset analysis_data + ~nullsafe_mode:annotated_signature.nullsafe_mode ; Some {NullsafeSummary.issues} diff --git a/infer/src/nullsafe/eradicateCheckers.ml b/infer/src/nullsafe/eradicateCheckers.ml index 09e3c89c4..90714f875 100644 --- a/infer/src/nullsafe/eradicateCheckers.ml +++ b/infer/src/nullsafe/eradicateCheckers.ml @@ -9,7 +9,7 @@ open! IStd (** Module for Eradicate-based user-defined checkers. *) -let report_error tenv proc_name proc_desc kind loc ?(field_name = None) +let report_error {IntraproceduralAnalysis.proc_desc; tenv; err_log} kind loc ?(field_name = None) ?(exception_kind = fun k d -> Exceptions.Checkers (k, d)) ~severity description = let suppressed = Reporting.is_suppressed tenv proc_desc kind ~field_name in if suppressed then Logging.debug Analysis Medium "Reporting is suppressed!@\n" @@ -17,4 +17,9 @@ let report_error tenv proc_name proc_desc kind loc ?(field_name = None) let localized_description = Localise.verbatim_desc description in let exn = exception_kind kind localized_description in let trace = [Errlog.make_trace_element 0 loc description []] in - SummaryReporting.log_issue_deprecated_using_state severity proc_name ~loc ~ltr:trace exn + let attrs = Procdesc.get_attributes proc_desc in + let node = AnalysisState.get_node_exn () in + let session = AnalysisState.get_session () in + Reporting.log_issue_from_summary severity attrs err_log + ~node:(BackendNode {node}) + ~session ~loc ~ltr:trace exn diff --git a/infer/src/nullsafe/eradicateCheckers.mli b/infer/src/nullsafe/eradicateCheckers.mli index b16bbf893..ffa19169d 100644 --- a/infer/src/nullsafe/eradicateCheckers.mli +++ b/infer/src/nullsafe/eradicateCheckers.mli @@ -10,9 +10,7 @@ open! IStd (** Module for Eradicate-based user-defined checkers. *) val report_error : - Tenv.t - -> Procname.t - -> Procdesc.t + IntraproceduralAnalysis.t -> IssueType.t -> Location.t -> ?field_name:Fieldname.t option diff --git a/infer/src/nullsafe/eradicateChecks.ml b/infer/src/nullsafe/eradicateChecks.ml index e2c157604..60782b467 100644 --- a/infer/src/nullsafe/eradicateChecks.ml +++ b/infer/src/nullsafe/eradicateChecks.ml @@ -11,8 +11,6 @@ open! IStd module L = Logging -let register_error tenv = TypeErr.register_error (EradicateCheckers.report_error tenv) - let explain_expr tenv node e = match Errdesc.exp_rv_dexp tenv node e with | Some de -> @@ -28,8 +26,8 @@ let is_virtual = function false -let check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pname node instr_ref - object_exp dereference_type inferred_nullability loc = +let check_object_dereference ({IntraproceduralAnalysis.tenv; _} as analysis_data) ~nullsafe_mode + find_canonical_duplicate node instr_ref object_exp dereference_type inferred_nullability loc = Result.iter_error (DereferenceRule.check (InferredNullability.get_nullability inferred_nullability)) ~f:(fun dereference_violation -> @@ -43,15 +41,17 @@ let check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_p ; dereference_type ; nullable_object_origin } in - register_error tenv find_canonical_duplicate type_error (Some instr_ref) ~nullsafe_mode loc - curr_pname ) + TypeErr.register_error analysis_data find_canonical_duplicate type_error (Some instr_ref) + ~nullsafe_mode loc ) (** [expr] is an expression that was explicitly compared with `null`. At the same time, [expr] had [inferred_nullability] before the comparision. Check if the comparision is redundant and emit an issue, if this is the case. *) -let check_condition_for_redundancy tenv ~is_always_true find_canonical_duplicate curr_pdesc node - ~nullsafe_mode expr typ inferred_nullability idenv linereader loc instr_ref : unit = +let check_condition_for_redundancy + ({IntraproceduralAnalysis.tenv; proc_desc= curr_pdesc; _} as analysis_data) ~is_always_true + find_canonical_duplicate node ~nullsafe_mode expr typ inferred_nullability idenv linereader loc + instr_ref : unit = let contains_instanceof_throwable pdesc node = (* Check if the current procedure has a catch Throwable. *) (* That always happens in the bytecode generated by try-with-resources. *) @@ -111,21 +111,22 @@ let check_condition_for_redundancy tenv ~is_always_true find_canonical_duplicate *) let condition_descr = explain_expr tenv node expr in let nonnull_origin = InferredNullability.get_origin inferred_nullability in - register_error tenv find_canonical_duplicate + TypeErr.register_error analysis_data find_canonical_duplicate (TypeErr.Condition_redundant {is_always_true; condition_descr; nonnull_origin}) - (Some instr_ref) ~nullsafe_mode loc curr_pdesc + (Some instr_ref) ~nullsafe_mode loc (** Check an assignment to a field. *) -let check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node instr_ref - typestate ~expr_rhs ~field_type loc fname (annotated_field : AnnotatedField.t) typecheck_expr : - unit = +let check_field_assignment + ({IntraproceduralAnalysis.tenv; proc_desc= curr_pdesc; _} as analysis_data) ~nullsafe_mode + find_canonical_duplicate node instr_ref typestate ~expr_rhs ~field_type loc fname + (annotated_field : AnnotatedField.t) typecheck_expr : unit = L.d_with_indent ~name:"check_field_assignment" (fun () -> let curr_pname = Procdesc.get_proc_name curr_pdesc in let curr_pattrs = Procdesc.get_attributes curr_pdesc in let _, inferred_nullability_rhs = L.d_strln "Typechecking rhs" ; - typecheck_expr node instr_ref curr_pdesc typestate expr_rhs + typecheck_expr node instr_ref typestate expr_rhs (* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *) (field_type, InferredNullability.create TypeOrigin.OptimisticFallback) loc @@ -158,13 +159,13 @@ let check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate curr_pde in if should_report then let rhs_origin = InferredNullability.get_origin inferred_nullability_rhs in - register_error tenv find_canonical_duplicate + TypeErr.register_error analysis_data find_canonical_duplicate (TypeErr.Bad_assignment { assignment_violation ; assignment_location= loc ; rhs_origin ; assignment_type= AssignmentRule.ReportableViolation.AssigningToField fname }) - (Some instr_ref) ~nullsafe_mode loc curr_pdesc ) ) + (Some instr_ref) ~nullsafe_mode loc ) ) (* Check if the field declared as not nullable (implicitly or explicitly). If the field is @@ -228,12 +229,13 @@ let is_generated_field field_name = (** Check field initialization for a given constructor *) -let check_constructor_initialization tenv find_canonical_duplicate curr_constructor_pname - curr_constructor_pdesc start_node ~nullsafe_mode +let check_constructor_initialization + ({IntraproceduralAnalysis.tenv; proc_desc= curr_constructor_pdesc; _} as analysis_data) + find_canonical_duplicate start_node ~nullsafe_mode ~typestates_for_curr_constructor_and_all_initializer_methods ~typestates_for_all_constructors_incl_current loc : unit = AnalysisState.set_node start_node ; - if Procname.is_constructor curr_constructor_pname then + if Procname.is_constructor (Procdesc.get_proc_name curr_constructor_pdesc) then match PatternMatch.get_this_type_nonstatic_methods_only (Procdesc.get_attributes curr_constructor_pdesc) @@ -305,9 +307,9 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc *) () else - register_error tenv find_canonical_duplicate + TypeErr.register_error analysis_data find_canonical_duplicate (TypeErr.Field_not_initialized {field_name}) - None ~nullsafe_mode loc curr_constructor_pdesc ; + None ~nullsafe_mode loc ; (* Check if field is over-annotated. *) match annotated_field with | None -> @@ -321,11 +323,11 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc let by_rhs_upper_bound = field_nullability_upper_bound_over_all_typestates () in Result.iter_error (OverAnnotatedRule.check ~what ~by_rhs_upper_bound) ~f:(fun over_annotated_violation -> - register_error tenv find_canonical_duplicate + TypeErr.register_error analysis_data find_canonical_duplicate (TypeErr.Over_annotation { over_annotated_violation ; violation_type= OverAnnotatedRule.FieldOverAnnoted field_name }) - ~nullsafe_mode None loc curr_constructor_pdesc ) ) + ~nullsafe_mode None loc ) ) in List.iter ~f:do_field fields | None -> @@ -334,24 +336,27 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc () -let check_return_not_nullable ~nullsafe_mode tenv find_canonical_duplicate loc curr_pname curr_pdesc - (ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability = +let check_return_not_nullable ({IntraproceduralAnalysis.proc_desc= curr_pdesc; _} as analysis_data) + ~nullsafe_mode find_canonical_duplicate loc (ret_signature : AnnotatedSignature.ret_signature) + ret_inferred_nullability = (* Returning from a function is essentially an assignment the actual return value to the formal `return` *) let lhs = AnnotatedNullability.get_nullability ret_signature.ret_annotated_type.nullability in let rhs = InferredNullability.get_nullability ret_inferred_nullability in Result.iter_error (AssignmentRule.check ~lhs ~rhs) ~f:(fun assignment_violation -> let rhs_origin = InferredNullability.get_origin ret_inferred_nullability in - register_error tenv find_canonical_duplicate - (TypeErr.Bad_assignment + let curr_pname = Procdesc.get_proc_name curr_pdesc in + TypeErr.register_error analysis_data find_canonical_duplicate + (Bad_assignment { assignment_violation ; assignment_location= loc ; rhs_origin - ; assignment_type= AssignmentRule.ReportableViolation.ReturningFromFunction curr_pname }) - None ~nullsafe_mode loc curr_pdesc ) + ; assignment_type= ReturningFromFunction curr_pname }) + None ~nullsafe_mode loc ) -let check_return_overrannotated tenv find_canonical_duplicate loc curr_pname curr_pdesc - ~nullsafe_mode (ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability = +let check_return_overrannotated + ({IntraproceduralAnalysis.proc_desc= curr_pdesc; _} as analysis_data) find_canonical_duplicate + loc ~nullsafe_mode (ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability = (* Returning from a function is essentially an assignment the actual return value to the formal `return` *) let what = AnnotatedNullability.get_nullability ret_signature.ret_annotated_type.nullability in (* In our CFG implementation, there is only one place where we return from a function @@ -361,34 +366,29 @@ let check_return_overrannotated tenv find_canonical_duplicate loc curr_pname cur let by_rhs_upper_bound = InferredNullability.get_nullability ret_inferred_nullability in Result.iter_error (OverAnnotatedRule.check ~what ~by_rhs_upper_bound) ~f:(fun over_annotated_violation -> - register_error tenv find_canonical_duplicate - (TypeErr.Over_annotation - { over_annotated_violation - ; violation_type= OverAnnotatedRule.ReturnOverAnnotated curr_pname }) - None ~nullsafe_mode loc curr_pdesc ) + let curr_pname = Procdesc.get_proc_name curr_pdesc in + TypeErr.register_error analysis_data find_canonical_duplicate + (Over_annotation {over_annotated_violation; violation_type= ReturnOverAnnotated curr_pname}) + None ~nullsafe_mode loc ) (** Check the annotations when returning from a method. *) -let check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range - (annotated_signature : AnnotatedSignature.t) ret_implicitly_nullable loc : unit = +let check_return_annotation ({IntraproceduralAnalysis.proc_desc= curr_pdesc; _} as analysis_data) + find_canonical_duplicate ret_range (annotated_signature : AnnotatedSignature.t) + ret_implicitly_nullable loc : unit = let curr_pname = Procdesc.get_proc_name curr_pdesc in match ret_range with (* Disables the warnings since it is not clear how to annotate the return value of lambdas *) | Some _ - when match curr_pname with - | Procname.Java java_pname -> - Procname.Java.is_lambda java_pname - | _ -> - false -> + when match curr_pname with Java java_pname -> Procname.Java.is_lambda java_pname | _ -> false -> () | Some (_, ret_inferred_nullability) -> (* TODO(T54308240) Model ret_implicitly_nullable in AnnotatedNullability *) if not ret_implicitly_nullable then - check_return_not_nullable ~nullsafe_mode:annotated_signature.nullsafe_mode tenv - find_canonical_duplicate loc curr_pname curr_pdesc annotated_signature.ret - ret_inferred_nullability ; + check_return_not_nullable analysis_data ~nullsafe_mode:annotated_signature.nullsafe_mode + find_canonical_duplicate loc annotated_signature.ret ret_inferred_nullability ; if Config.eradicate_return_over_annotated then - check_return_overrannotated tenv find_canonical_duplicate loc curr_pname curr_pdesc + check_return_overrannotated analysis_data find_canonical_duplicate loc annotated_signature.ret ~nullsafe_mode:annotated_signature.nullsafe_mode ret_inferred_nullability | None -> @@ -396,18 +396,18 @@ let check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range (** Check the receiver of a virtual call. *) -let check_call_receiver ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node typestate +let check_call_receiver analysis_data ~nullsafe_mode find_canonical_duplicate node typestate call_params callee_pname (instr_ref : TypeErr.InstrRef.t) loc typecheck_expr : unit = match call_params with | ((original_this_e, this_e), typ) :: _ -> let _, this_inferred_nullability = - typecheck_expr tenv node instr_ref curr_pdesc typestate this_e + typecheck_expr node instr_ref typestate this_e (* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *) (typ, InferredNullability.create TypeOrigin.OptimisticFallback) loc in - check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node - instr_ref original_this_e (DereferenceRule.ReportableViolation.MethodCall callee_pname) + check_object_dereference analysis_data ~nullsafe_mode find_canonical_duplicate node instr_ref + original_this_e (DereferenceRule.ReportableViolation.MethodCall callee_pname) this_inferred_nullability loc | [] -> () @@ -420,8 +420,9 @@ type resolved_param = ; is_formal_propagates_nullable: bool } (** Check the parameters of a call. *) -let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_canonical_duplicate - curr_pdesc node callee_attributes resolved_params loc instr_ref : unit = +let check_call_parameters ({IntraproceduralAnalysis.tenv; _} as analysis_data) ~nullsafe_mode + ~callee_annotated_signature find_canonical_duplicate node callee_attributes resolved_params loc + instr_ref : unit = let callee_pname = callee_attributes.ProcAttributes.proc_name in let check {num= param_position; formal; actual= orig_e2, nullability_actual} = let report ~nullsafe_mode assignment_violation = @@ -433,19 +434,19 @@ let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_c "formal parameter " ^ Mangled.to_string formal.mangled in let rhs_origin = InferredNullability.get_origin nullability_actual in - register_error tenv find_canonical_duplicate - (TypeErr.Bad_assignment + TypeErr.register_error analysis_data find_canonical_duplicate + (Bad_assignment { assignment_violation ; assignment_location= loc ; rhs_origin ; assignment_type= - AssignmentRule.ReportableViolation.PassingParamToFunction + PassingParamToFunction { param_signature= formal ; model_source= callee_annotated_signature.AnnotatedSignature.model_source ; actual_param_expression ; param_position ; function_procname= callee_pname } }) - (Some instr_ref) ~nullsafe_mode loc curr_pdesc + (Some instr_ref) ~nullsafe_mode loc in if PatternMatch.type_is_class formal.param_annotated_type.typ then (* Passing a param to a function is essentially an assignment the actual param value @@ -457,41 +458,42 @@ let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_c List.iter ~f:check resolved_params -let check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~nullsafe_mode - ~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_nullability +let check_inheritance_rule_for_return + ({IntraproceduralAnalysis.proc_desc= overridden_proc_desc; _} as analysis_data) + find_canonical_duplicate loc ~nullsafe_mode ~base_proc_name ~base_nullability ~overridden_nullability = Result.iter_error (InheritanceRule.check InheritanceRule.Ret ~base:base_nullability ~overridden:overridden_nullability) ~f:(fun inheritance_violation -> - register_error tenv find_canonical_duplicate - (TypeErr.Inconsistent_subclass + TypeErr.register_error analysis_data find_canonical_duplicate + (Inconsistent_subclass { inheritance_violation - ; violation_type= InheritanceRule.ReportableViolation.InconsistentReturn - ; overridden_proc_name + ; violation_type= InconsistentReturn + ; overridden_proc_name= Procdesc.get_proc_name overridden_proc_desc ; base_proc_name }) - None ~nullsafe_mode loc overridden_proc_desc ) + None ~nullsafe_mode loc ) -let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe_mode - ~overridden_param_name ~base_proc_name ~overridden_proc_name ~overridden_proc_desc +let check_inheritance_rule_for_param + ({IntraproceduralAnalysis.proc_desc= overridden_proc_desc; _} as analysis_data) + find_canonical_duplicate loc ~nullsafe_mode ~overridden_param_name ~base_proc_name ~param_position ~base_nullability ~overridden_nullability = Result.iter_error (InheritanceRule.check InheritanceRule.Param ~base:base_nullability ~overridden:overridden_nullability) ~f:(fun inheritance_violation -> - register_error tenv find_canonical_duplicate - (TypeErr.Inconsistent_subclass + TypeErr.register_error analysis_data find_canonical_duplicate + (Inconsistent_subclass { inheritance_violation ; violation_type= - InheritanceRule.ReportableViolation.InconsistentParam + InconsistentParam {param_position; param_description= Mangled.to_string overridden_param_name} ; base_proc_name - ; overridden_proc_name }) - None ~nullsafe_mode loc overridden_proc_desc ) + ; overridden_proc_name= Procdesc.get_proc_name overridden_proc_desc }) + None ~nullsafe_mode loc ) -let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsafe_mode - ~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_signature - ~overridden_signature = +let check_inheritance_rule_for_params analysis_data find_canonical_duplicate loc ~nullsafe_mode + ~base_proc_name ~base_signature ~overridden_signature = let base_params = base_signature.AnnotatedSignature.params in let overridden_params = overridden_signature.AnnotatedSignature.params in let zipped_params = List.zip base_params overridden_params in @@ -506,8 +508,8 @@ let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsaf { mangled= overridden_param_name ; param_annotated_type= {nullability= annotated_nullability_overridden} } ) -> - check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe_mode - ~overridden_param_name ~base_proc_name ~overridden_proc_name ~overridden_proc_desc + check_inheritance_rule_for_param analysis_data find_canonical_duplicate loc ~nullsafe_mode + ~overridden_param_name ~base_proc_name ~param_position:(if should_index_from_zero then index else index + 1) ~base_nullability:(AnnotatedNullability.get_nullability annotated_nullability_base) ~overridden_nullability: @@ -518,13 +520,12 @@ let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsaf () -(* Check both params and return values for complying for co- and contravariance *) -let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~nullsafe_mode - ~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_signature - ~overridden_signature = +(** Check both params and return values for complying for co- and contravariance *) +let check_inheritance_rule_for_signature analysis_data find_canonical_duplicate loc ~nullsafe_mode + ~base_proc_name ~base_signature ~overridden_signature = (* Check params *) - check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsafe_mode ~base_proc_name - ~overridden_proc_name ~overridden_proc_desc ~base_signature ~overridden_signature ; + check_inheritance_rule_for_params analysis_data find_canonical_duplicate loc ~nullsafe_mode + ~base_proc_name ~base_signature ~overridden_signature ; (* Check return value *) match base_proc_name with (* TODO model this as unknown nullability and get rid of that check *) @@ -538,9 +539,8 @@ let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~null AnnotatedNullability.get_nullability overridden_signature.AnnotatedSignature.ret.ret_annotated_type.nullability in - check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~nullsafe_mode - ~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_nullability - ~overridden_nullability + check_inheritance_rule_for_return analysis_data find_canonical_duplicate loc ~nullsafe_mode + ~base_proc_name ~base_nullability ~overridden_nullability | _ -> (* the analysis should not report return type inconsistencies with external code *) () @@ -548,8 +548,8 @@ let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~null (** Checks if the annotations are consistent with the derived classes and with the implemented interfaces *) -let check_overridden_annotations find_canonical_duplicate tenv proc_name proc_desc - annotated_signature = +let check_overridden_annotations ({IntraproceduralAnalysis.tenv; proc_desc; _} as analysis_data) + find_canonical_duplicate annotated_signature = let start_node = Procdesc.get_start_node proc_desc in let loc = Procdesc.Node.get_loc start_node in let check_if_base_signature_matches_current base_proc_name = @@ -561,15 +561,16 @@ let check_overridden_annotations find_canonical_duplicate tenv proc_name proc_de Models.get_modelled_annotated_signature ~is_callee_in_trust_list:false tenv base_attributes in - check_inheritance_rule_for_signature + check_inheritance_rule_for_signature analysis_data ~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode - find_canonical_duplicate tenv loc ~base_proc_name ~overridden_proc_name:proc_name - ~overridden_proc_desc:proc_desc ~base_signature ~overridden_signature:annotated_signature + find_canonical_duplicate loc ~base_proc_name ~base_signature + ~overridden_signature:annotated_signature | None -> (* Could not find the attributes - optimistically skipping the check *) (* TODO(T54687014) ensure this is not an issue in practice *) () in + let proc_name = Procdesc.get_proc_name proc_desc in (* Iterate over all methods the current method overrides and see the current method is compatible with all of them *) PatternMatch.override_iter check_if_base_signature_matches_current tenv proc_name diff --git a/infer/src/nullsafe/immutableChecker.ml b/infer/src/nullsafe/immutableChecker.ml index 53b4e0c44..2974a988b 100644 --- a/infer/src/nullsafe/immutableChecker.ml +++ b/infer/src/nullsafe/immutableChecker.ml @@ -9,7 +9,7 @@ open! IStd (** Check an implicit cast when returning an immutable collection from a method whose type is mutable. *) -let check_immutable_cast tenv curr_pname curr_pdesc typ_expected typ_found_opt loc : unit = +let check_immutable_cast analysis_data proc_desc typ_expected typ_found_opt loc : unit = match typ_found_opt with | Some typ_found -> ( let casts = @@ -32,16 +32,16 @@ let check_immutable_cast tenv curr_pname curr_pdesc typ_expected typ_found_opt l Format.asprintf "Method %s returns %a but the return type is %a. Make sure that users of this \ method do not try to modify the collection." - (Procname.to_simplified_string curr_pname) + (Procname.to_simplified_string (Procdesc.get_proc_name proc_desc)) Typ.Name.pp name_given Typ.Name.pp name_expected in - EradicateCheckers.report_error tenv curr_pname curr_pdesc - IssueType.checkers_immutable_cast loc description ~severity:Exceptions.Warning + EradicateCheckers.report_error analysis_data IssueType.checkers_immutable_cast loc + description ~severity:Exceptions.Warning | _ -> () ) | None -> () -let analyze ({IntraproceduralAnalysis.tenv} as analysis_data) = - Eradicate.analyze_for_immutable_cast_checker (check_immutable_cast tenv) analysis_data +let analyze analysis_data = + Eradicate.analyze_for_immutable_cast_checker (check_immutable_cast analysis_data) analysis_data diff --git a/infer/src/nullsafe/typeCheck.ml b/infer/src/nullsafe/typeCheck.ml index 585c1d37b..656c021f3 100644 --- a/infer/src/nullsafe/typeCheck.ml +++ b/infer/src/nullsafe/typeCheck.ml @@ -104,15 +104,16 @@ end (* ComplexExpressions *) -type check_return_type = Procname.t -> Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit +type check_return_type = Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit type find_canonical_duplicate = Procdesc.Node.t -> Procdesc.Node.t type checks = {eradicate: bool; check_ret_type: check_return_type list} (** Typecheck an expression. *) -let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref - (curr_pdesc : Procdesc.t) typestate e tr_default loc : TypeState.range = +let rec typecheck_expr ({IntraproceduralAnalysis.tenv; _} as analysis_data) ~nullsafe_mode + find_canonical_duplicate visited checks node instr_ref typestate e tr_default loc : + TypeState.range = L.d_with_indent ~name:"typecheck_expr" ~pp_result:TypeState.pp_range (fun () -> L.d_printfln "Expr: %a" Exp.pp e ; match e with @@ -142,13 +143,13 @@ let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks te L.d_strln "WARNING: could not lookup Id in typestate: fallback to default" ; tr_default ) | Exp.Exn e1 -> - typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref - curr_pdesc typestate e1 tr_default loc + typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate visited checks node + instr_ref typestate e1 tr_default loc | Exp.Lfield (exp, field_name, typ) -> let _, _ = tr_default in let _, inferred_nullability = - typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node - instr_ref curr_pdesc typestate exp + typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate visited checks node + instr_ref typestate exp (* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *) (typ, InferredNullability.create TypeOrigin.OptimisticFallback) loc @@ -165,23 +166,22 @@ let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks te tr_default in if checks.eradicate then - EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate - curr_pdesc node instr_ref exp - (DereferenceRule.ReportableViolation.AccessToField field_name) inferred_nullability - loc ; + EradicateChecks.check_object_dereference analysis_data ~nullsafe_mode + find_canonical_duplicate node instr_ref exp (AccessToField field_name) + inferred_nullability loc ; tr_new | Exp.Lindex (array_exp, index_exp) -> let _, inferred_nullability = - typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node - instr_ref curr_pdesc typestate array_exp tr_default loc + typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate visited checks node + instr_ref typestate array_exp tr_default loc in let index_desc = match EradicateChecks.explain_expr tenv node index_exp with Some s -> s | None -> "?" in if checks.eradicate then - EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate - curr_pdesc node instr_ref array_exp - (DereferenceRule.ReportableViolation.AccessByIndex {index_desc}) + EradicateChecks.check_object_dereference analysis_data ~nullsafe_mode + find_canonical_duplicate node instr_ref array_exp + (AccessByIndex {index_desc}) inferred_nullability loc ; let typ, _ = tr_default in (typ, InferredNullability.create TypeOrigin.ArrayAccess) @@ -460,19 +460,19 @@ let pvar_apply instr_ref idenv tenv curr_pname curr_annotated_signature loc hand (* typecheck_expr with fewer parameters, using a common template for typestate range *) -let typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks tenv +let typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node instr_ref typestate1 exp1 typ1 origin1 loc1 = - typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref - curr_pdesc typestate1 exp1 + typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node + instr_ref typestate1 exp1 (typ1, InferredNullability.create origin1) loc1 (* check if there are errors in exp1 *) -let typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks - tenv node instr_ref typestate1 exp1 loc1 : unit = +let typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate1 exp1 loc1 : unit = ignore - (typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks tenv + (typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node instr_ref typestate1 exp1 Typ.void TypeOrigin.OptimisticFallback loc1) @@ -498,9 +498,10 @@ let java_get_vararg_values node pvar idenv = (* Handle Preconditions.checkNotNull. *) -let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc curr_pdesc - curr_pname curr_annotated_signature checks call_params idenv parameter_num ~is_vararg typestate' - = +let do_preconditions_check_not_null + ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) instr_ref + find_canonical_duplicate node loc curr_annotated_signature checks call_params idenv + parameter_num ~is_vararg typestate' = (* clear the nullable flag of the first parameter of the procedure *) let clear_nullable_flag ~nullsafe_mode typestate'' pvar = (* remove the nullable flag for the given pvar *) @@ -514,12 +515,12 @@ let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node in ( if checks.eradicate && should_report then let cond = Exp.BinOp (Binop.Ne, Exp.Lvar pvar, Exp.null) in - EradicateChecks.register_error tenv find_canonical_duplicate - (TypeErr.Condition_redundant + TypeErr.register_error analysis_data find_canonical_duplicate + (Condition_redundant { is_always_true= true ; condition_descr= EradicateChecks.explain_expr tenv node cond ; nonnull_origin= InferredNullability.get_origin nullability }) - (Some instr_ref) ~nullsafe_mode loc curr_pdesc ) ; + (Some instr_ref) ~nullsafe_mode loc ) ; let previous_origin = InferredNullability.get_origin nullability in let new_origin = TypeOrigin.InferredNonnull {previous_origin} in TypeState.add pvar @@ -539,6 +540,7 @@ let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node in match find_parameter parameter_num call_params with | Some (pvar, _) -> + let curr_pname = Procdesc.get_proc_name curr_pdesc in if is_vararg then let do_vararg_value e ts = match Idenv.expand_expr idenv e with @@ -626,8 +628,9 @@ let do_preconditions_check_state instr_ref idenv tenv curr_pname curr_annotated_ (* Handle m.put(k,v) as assignment pvar = v for the pvar associated to m.get(k) *) -let do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc calls_this checks - instr_ref ~nullsafe_mode find_canonical_duplicate typestate' = +let do_map_put ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) + call_params callee_pname loc node calls_this checks instr_ref ~nullsafe_mode + find_canonical_duplicate typestate' = (* Get the proc name for map.get() from map.put() *) let pname_get_from_pname_put pname_put = let object_t = JavaSplitName.java_lang_object in @@ -656,11 +659,12 @@ let do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc call ComplexExpressions.exp_to_string_map_dexp tenv convert_dexp_key_to_dexp_get node exp_key with | Some map_get_str -> + let curr_pname = Procdesc.get_proc_name curr_pdesc in let pvar_map_get = Pvar.mk (Mangled.from_string map_get_str) curr_pname in TypeState.add pvar_map_get - (typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this - checks tenv node instr_ref typestate' exp_value typ_value - TypeOrigin.OptimisticFallback loc) + (typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate' exp_value typ_value TypeOrigin.OptimisticFallback + loc) typestate' ~descr:"do_map_put" | None -> typestate' ) @@ -719,9 +723,11 @@ let normalize_cond_for_sil_prune idenv ~node cond = normalize_cond_for_sil_prune_rec idenv ~node ~original_node:node cond -let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname - curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref - ~nullsafe_mode ~original_node ~node c : TypeState.t = +let rec check_condition_for_sil_prune + ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) idenv calls_this + find_canonical_duplicate loc curr_annotated_signature linereader typestate checks true_branch + instr_ref ~nullsafe_mode ~original_node ~node c : TypeState.t = + let curr_pname = Procdesc.get_proc_name curr_pdesc in (* check if the expression is coming from a call, and return the arguments *) let extract_arguments_from_call filter_callee expr = match expr with @@ -829,14 +835,14 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli This means the corresponding condition (initiated this PRUNE branch) was redudant. *) let typ, inferred_nullability = - typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks - tenv original_node instr_ref typestate pvar_expr Typ.void TypeOrigin.OptimisticFallback + typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks original_node instr_ref typestate pvar_expr Typ.void TypeOrigin.OptimisticFallback loc in if checks.eradicate then - EradicateChecks.check_condition_for_redundancy ~is_always_true:true_branch tenv - find_canonical_duplicate curr_pdesc original_node pvar_expr typ inferred_nullability - ~nullsafe_mode idenv linereader loc instr_ref ) ; + EradicateChecks.check_condition_for_redundancy analysis_data ~is_always_true:true_branch + find_canonical_duplicate original_node pvar_expr typ inferred_nullability ~nullsafe_mode + idenv linereader loc instr_ref ) ; set_nonnull pvar_expr typestate ~descr in (* Assuming [expr] is a boolean, this is the branch where, according to PRUNE semantics, @@ -910,14 +916,14 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli *) typestate |> handle_boolean_equal_true expr |> handle_object_not_equal_null expr | Exp.UnOp (Unop.LNot, Exp.BinOp (Binop.Eq, e1, e2), _) -> - check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname - curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref - ~nullsafe_mode ~original_node ~node + check_condition_for_sil_prune analysis_data idenv calls_this find_canonical_duplicate loc + curr_annotated_signature linereader typestate checks true_branch instr_ref ~nullsafe_mode + ~original_node ~node (Exp.BinOp (Binop.Ne, e1, e2)) | Exp.UnOp (Unop.LNot, Exp.BinOp (Binop.Ne, e1, e2), _) -> - check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname - curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref - ~nullsafe_mode ~original_node ~node + check_condition_for_sil_prune analysis_data idenv calls_this find_canonical_duplicate loc + curr_annotated_signature linereader typestate checks true_branch instr_ref ~nullsafe_mode + ~original_node ~node (Exp.BinOp (Binop.Eq, e1, e2)) | _ -> (* TODO(T54687014): silenced warning may be an unsoundeness issue; investigate *) @@ -949,15 +955,17 @@ let clarify_ret_by_propagates_nullable ret (resolved_params : EradicateChecks.re (upper_bound_nullability, ret_typ) -let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv idenv instr_ref - signature_params cflags call_params ~is_anonymous_inner_class_constructor - ~callee_annotated_signature ~callee_attributes ~callee_pname ~callee_pname_java ~curr_pname - ~curr_pdesc ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 loc node = +let calc_typestate_after_call + ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) + find_canonical_duplicate calls_this checks idenv instr_ref signature_params cflags call_params + ~is_anonymous_inner_class_constructor ~callee_annotated_signature ~callee_attributes + ~callee_pname ~callee_pname_java ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 + loc node = let resolve_param i (formal_param, actual_param) = let (orig_e2, e2), t2 = actual_param in let _, inferred_nullability_actual = - typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref - curr_pdesc typestate e2 + typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node + instr_ref typestate e2 (* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *) (t2, InferredNullability.create TypeOrigin.OptimisticFallback) loc @@ -1011,34 +1019,35 @@ let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv id let typestate_after_call = if not is_anonymous_inner_class_constructor then ( if cflags.CallFlags.cf_virtual && checks.eradicate then - EradicateChecks.check_call_receiver ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc + EradicateChecks.check_call_receiver analysis_data ~nullsafe_mode find_canonical_duplicate node typestate1 call_params callee_pname instr_ref loc - (typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks) ; + (typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks) ; if checks.eradicate then - EradicateChecks.check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv - find_canonical_duplicate curr_pdesc node callee_attributes resolved_params loc instr_ref ; + EradicateChecks.check_call_parameters analysis_data ~nullsafe_mode + ~callee_annotated_signature find_canonical_duplicate node callee_attributes + resolved_params loc instr_ref ; if Models.is_check_not_null callee_pname then match Models.get_check_not_null_parameter callee_pname with | Some index -> - do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc - curr_pdesc curr_pname curr_annotated_signature checks call_params idenv index - ~is_vararg:false typestate1 + do_preconditions_check_not_null analysis_data instr_ref find_canonical_duplicate node + loc curr_annotated_signature checks call_params idenv index ~is_vararg:false + typestate1 | None when Procname.Java.is_vararg callee_pname_java -> let last_parameter = List.length call_params in - do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc - curr_pdesc curr_pname curr_annotated_signature checks call_params idenv last_parameter - ~is_vararg:true typestate1 + do_preconditions_check_not_null analysis_data instr_ref find_canonical_duplicate node + loc curr_annotated_signature checks call_params idenv last_parameter ~is_vararg:true + typestate1 | None -> (* assume the first parameter is checked for null *) - do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc - curr_pdesc curr_pname curr_annotated_signature checks call_params idenv 1 - ~is_vararg:false typestate1 + do_preconditions_check_not_null analysis_data instr_ref find_canonical_duplicate node + loc curr_annotated_signature checks call_params idenv 1 ~is_vararg:false typestate1 else if Models.is_check_state callee_pname || Models.is_check_argument callee_pname then + let curr_pname = Procdesc.get_proc_name curr_pdesc in do_preconditions_check_state instr_ref idenv tenv curr_pname curr_annotated_signature call_params loc node typestate1 else if Models.is_mapPut callee_pname then - do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc calls_this checks - instr_ref ~nullsafe_mode find_canonical_duplicate typestate1 + do_map_put analysis_data call_params callee_pname loc node calls_this checks instr_ref + ~nullsafe_mode find_canonical_duplicate typestate1 else typestate1 ) else typestate1 in @@ -1046,9 +1055,10 @@ let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv id (* SIL instruction in form of [ret = fun(args);] where fun is a non-builtin Java function *) -let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref typestate idenv - ~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~nullsafe_mode - ret_id_typ etl_ loc callee_pname_java cflags node = +let typecheck_sil_call_function + ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) + find_canonical_duplicate checks instr_ref typestate idenv ~callee_pname curr_annotated_signature + calls_this ~nullsafe_mode ret_id_typ etl_ loc callee_pname_java cflags node = L.d_with_indent ~name:"typecheck_sil_call_function" (fun () -> let callee_attributes = match PatternMatch.lookup_attributes tenv callee_pname with @@ -1074,11 +1084,12 @@ let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref t in proc_attributes in + let curr_pname = Procdesc.get_proc_name curr_pdesc in let etl = drop_unchecked_params calls_this curr_pname callee_attributes etl_ in let call_params, typestate1 = let handle_et (e1, t1) (etl1, typestate1) = - typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this - checks tenv node instr_ref typestate e1 loc ; + typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate e1 loc ; let e2 = convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~is_assignment:false ~node ~original_node:node e1 typestate1 loc @@ -1124,19 +1135,19 @@ let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref t TypeState.add_id id (mk_return_range ()) typestate' ~descr:"typecheck_sil_call_function" in let typestate_after_call, finally_resolved_ret = - calc_typestate_after_call find_canonical_duplicate calls_this checks tenv idenv instr_ref - signature_params cflags call_params ~is_anonymous_inner_class_constructor + calc_typestate_after_call analysis_data find_canonical_duplicate calls_this checks idenv + instr_ref signature_params cflags call_params ~is_anonymous_inner_class_constructor ~callee_annotated_signature ~callee_attributes ~callee_pname ~callee_pname_java - ~curr_pname ~curr_pdesc ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 - loc node + ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 loc node in do_return finally_resolved_ret typestate_after_call ) (** Typecheck an instruction. *) -let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_pname curr_pdesc - find_canonical_duplicate (curr_annotated_signature : AnnotatedSignature.t) instr_ref linereader - typestate instr = +let typecheck_instr ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) + calls_this checks (node : Procdesc.Node.t) idenv find_canonical_duplicate + (curr_annotated_signature : AnnotatedSignature.t) instr_ref linereader typestate instr = + let curr_pname = Procdesc.get_proc_name curr_pdesc in let is_return pvar = let ret_pvar = Procdesc.get_ret_var curr_pdesc in Pvar.equal pvar ret_pvar @@ -1153,22 +1164,22 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p | Sil.Metadata (Abstract _ | Nullify _ | Skip | VariableLifetimeBegins _) -> typestate | Sil.Load {id; e; typ; loc} -> - typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks - tenv node instr_ref typestate e loc ; + typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate e loc ; let e', typestate' = convert_complex_exp_to_pvar_and_register_field_in_typestate tenv idenv curr_pname curr_annotated_signature ~node ~original_node:node ~is_assignment:false e typestate loc in TypeState.add_id id - (typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks - tenv node instr_ref typestate' e' typ TypeOrigin.OptimisticFallback loc) + (typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate' e' typ TypeOrigin.OptimisticFallback loc) ~descr:"Sil.Load" typestate' | Sil.Store {e1= Exp.Lvar pvar; e2= Exp.Exn _} when is_return pvar -> (* skip assignment to return variable where it is an artifact of a throw instruction *) typestate | Sil.Store {e1; typ; e2; loc} -> - typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks - tenv node instr_ref typestate e1 loc ; + typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate e1 loc ; let e1' = convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~node ~original_node:node ~is_assignment:true e1 typestate loc @@ -1179,10 +1190,11 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p match AnnotatedField.get tenv field_name field_class_type with | Some annotated_field -> if checks.eradicate then - EradicateChecks.check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate - curr_pdesc node instr_ref typestate ~expr_rhs:e2 ~field_type:typ loc field_name - annotated_field - (typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv) + EradicateChecks.check_field_assignment analysis_data ~nullsafe_mode + find_canonical_duplicate node instr_ref typestate ~expr_rhs:e2 ~field_type:typ loc + field_name annotated_field + (typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks) | None -> L.d_strln "WARNING: could not fetch field declaration; skipping assignment check" ) | _ -> @@ -1192,8 +1204,9 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p match e1' with | Exp.Lvar pvar -> TypeState.add pvar - (typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this - checks tenv node instr_ref typestate e2 typ TypeOrigin.OptimisticFallback loc) + (typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate + calls_this checks node instr_ref typestate e2 typ TypeOrigin.OptimisticFallback + loc) typestate ~descr:"Sil.Store: Exp.Lvar case" | Exp.Lfield _ -> typestate @@ -1211,31 +1224,31 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p (* Type cast *) | Sil.Call ((id, _), Exp.Const (Const.Cfun pn), (e, typ) :: _, loc, _) when Procname.equal pn BuiltinDecl.__cast -> - typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks - tenv node instr_ref typestate e loc ; + typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate e loc ; let e' = convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~is_assignment:false ~node ~original_node:node e typestate loc in (* cast copies the type of the first argument *) TypeState.add_id id - (typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks - tenv node instr_ref typestate e' typ TypeOrigin.OptimisticFallback loc) + (typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this + checks node instr_ref typestate e' typ TypeOrigin.OptimisticFallback loc) typestate ~descr:"type cast" (* myarray.length *) | Sil.Call ((id, _), Exp.Const (Const.Cfun pn), [(array_exp, t)], loc, _) when Procname.equal pn BuiltinDecl.__get_array_length -> let _, ta = - typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref - curr_pdesc typestate array_exp + typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node + instr_ref typestate array_exp (* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *) (t, InferredNullability.create TypeOrigin.OptimisticFallback) loc in if checks.eradicate then - EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate - curr_pdesc node instr_ref array_exp DereferenceRule.ReportableViolation.ArrayLengthAccess - ta loc ; + EradicateChecks.check_object_dereference analysis_data ~nullsafe_mode + find_canonical_duplicate node instr_ref array_exp + DereferenceRule.ReportableViolation.ArrayLengthAccess ta loc ; TypeState.add_id id (Typ.mk (Tint Typ.IInt), InferredNullability.create TypeOrigin.ArrayLengthResult) typestate ~descr:"array.length" @@ -1249,9 +1262,9 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p , etl_ , loc , cflags ) -> - typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref typestate idenv - ~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~nullsafe_mode - ret_id_typ etl_ loc callee_pname_java cflags node + typecheck_sil_call_function analysis_data find_canonical_duplicate checks instr_ref typestate + idenv ~callee_pname curr_annotated_signature calls_this ~nullsafe_mode ret_id_typ etl_ loc + callee_pname_java cflags node (* Calls instruction that is not a function call *) | Sil.Call _ -> (* This is something weird, we don't normally expect this type of instruction @@ -1261,9 +1274,9 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p typestate | Sil.Prune (cond, loc, true_branch, _) -> let node', normalized_cond = normalize_cond_for_sil_prune idenv ~node cond in - check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname - curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref - ~nullsafe_mode ~node:node' ~original_node:node normalized_cond + check_condition_for_sil_prune analysis_data idenv calls_this find_canonical_duplicate loc + curr_annotated_signature linereader typestate checks true_branch instr_ref ~nullsafe_mode + ~node:node' ~original_node:node normalized_cond let can_instrunction_throw tenv node instr = @@ -1298,8 +1311,8 @@ let is_noreturn_instruction = function (** Typecheck the instructions in a cfg node. *) -let typecheck_node tenv calls_this checks idenv curr_pname curr_pdesc find_canonical_duplicate - annotated_signature typestate node linereader = +let typecheck_node ({IntraproceduralAnalysis.tenv; _} as analysis_data) calls_this checks idenv + find_canonical_duplicate annotated_signature typestate node linereader = if Procdesc.Node.equal_nodekind (Procdesc.Node.get_kind node) Procdesc.Node.exn_sink_kind then {normal_flow_typestate= None; exception_flow_typestates= []} else @@ -1324,9 +1337,8 @@ let typecheck_node tenv calls_this checks idenv curr_pname curr_pdesc find_canon TypeErr.InstrRef.gen instr_ref_gen in let normal_flow_typestate = - typecheck_instr tenv calls_this checks node idenv curr_pname curr_pdesc - find_canonical_duplicate annotated_signature instr_ref linereader - normal_flow_typestate_prev instr + typecheck_instr analysis_data calls_this checks node idenv find_canonical_duplicate + annotated_signature instr_ref linereader normal_flow_typestate_prev instr in if Config.write_html then L.d_printfln "New state: @\n%a@\n" TypeState.pp normal_flow_typestate ; diff --git a/infer/src/nullsafe/typeCheck.mli b/infer/src/nullsafe/typeCheck.mli index d2d41fa45..a4e865206 100644 --- a/infer/src/nullsafe/typeCheck.mli +++ b/infer/src/nullsafe/typeCheck.mli @@ -9,7 +9,7 @@ open! IStd (** Module type for the type checking functions. *) -type check_return_type = Procname.t -> Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit +type check_return_type = Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit type find_canonical_duplicate = Procdesc.Node.t -> Procdesc.Node.t @@ -26,12 +26,10 @@ type typecheck_result = together) will be passed to all "exception output" nodes of the current node. *) } val typecheck_node : - Tenv.t + IntraproceduralAnalysis.t -> bool ref -> checks -> Idenv.t - -> Procname.t - -> Procdesc.t -> find_canonical_duplicate -> AnnotatedSignature.t -> TypeState.t diff --git a/infer/src/nullsafe/typeErr.ml b/infer/src/nullsafe/typeErr.ml index 6e6556903..bf958514b 100644 --- a/infer/src/nullsafe/typeErr.ml +++ b/infer/src/nullsafe/typeErr.ml @@ -169,17 +169,6 @@ let add_err find_canonical_duplicate err_instance instr_ref_opt loc = not is_forall -type st_report_error = - Procname.t - -> Procdesc.t - -> IssueType.t - -> Location.t - -> ?field_name:Fieldname.t option - -> ?exception_kind:(IssueType.t -> Localise.error_desc -> exn) - -> severity:Exceptions.severity - -> string - -> unit - (* If an error is related to a particular field, we support suppressing the error via a supress annotation placed near the field declaration *) let get_field_name_for_error_suppressing = function @@ -338,37 +327,33 @@ let is_reportable ~nullsafe_mode err_instance = get_error_info_fetcher_if_reportable ~nullsafe_mode err_instance |> Option.is_some -let report_now_if_reportable (st_report_error : st_report_error) err_instance ~nullsafe_mode loc - pdesc = - let pname = Procdesc.get_proc_name pdesc in +let report_now_if_reportable analysis_data err_instance ~nullsafe_mode loc = get_error_info_if_reportable ~nullsafe_mode err_instance |> Option.iter ~f:(fun (err_description, infer_issue_type, updated_location, severity) -> Logging.debug Analysis Medium "About to report: %s" err_description ; let field_name = get_field_name_for_error_suppressing err_instance in let error_location = Option.value updated_location ~default:loc in - st_report_error pname pdesc infer_issue_type error_location ~field_name + EradicateCheckers.report_error analysis_data infer_issue_type error_location ~field_name ~exception_kind:(fun k d -> Exceptions.Eradicate (k, d)) ~severity err_description ) (** Register issue (unless exactly the same issue was already registered). If needed, report this error immediately. *) -let register_error (st_report_error : st_report_error) find_canonical_duplicate err_instance - ~nullsafe_mode instr_ref_opt loc pdesc = +let register_error analysis_data find_canonical_duplicate err_instance ~nullsafe_mode instr_ref_opt + loc = let should_report_now = add_err find_canonical_duplicate err_instance instr_ref_opt loc in - if should_report_now then - report_now_if_reportable st_report_error err_instance ~nullsafe_mode loc pdesc + if should_report_now then report_now_if_reportable analysis_data err_instance ~nullsafe_mode loc -let report_forall_issues_and_reset st_report_error ~nullsafe_mode proc_desc = +let report_forall_issues_and_reset analysis_data ~nullsafe_mode = let iter (err_instance, instr_ref_opt) err_state = match (instr_ref_opt, get_forall err_instance) with | Some instr_ref, is_forall -> let node = InstrRef.get_node instr_ref in AnalysisState.set_node node ; if is_forall && err_state.always then - report_now_if_reportable st_report_error err_instance err_state.loc ~nullsafe_mode - proc_desc + report_now_if_reportable analysis_data err_instance err_state.loc ~nullsafe_mode | None, _ -> () in diff --git a/infer/src/nullsafe/typeErr.mli b/infer/src/nullsafe/typeErr.mli index 6c3f1b6bd..e83a876ff 100644 --- a/infer/src/nullsafe/typeErr.mli +++ b/infer/src/nullsafe/typeErr.mli @@ -62,31 +62,19 @@ val pp_err_instance : Format.formatter -> err_instance -> unit val node_reset_forall : Procdesc.Node.t -> unit -type st_report_error = - Procname.t - -> Procdesc.t - -> IssueType.t - -> Location.t - -> ?field_name:Fieldname.t option - -> ?exception_kind:(IssueType.t -> Localise.error_desc -> exn) - -> severity:Exceptions.severity - -> string - -> unit - val register_error : - st_report_error + IntraproceduralAnalysis.t -> (Procdesc.Node.t -> Procdesc.Node.t) -> err_instance -> nullsafe_mode:NullsafeMode.t -> InstrRef.t option -> Location.t - -> Procdesc.t -> unit (** Register the fact that issue happened. Depending on the error and mode, this error might or might not be reported to the user. *) val report_forall_issues_and_reset : - st_report_error -> nullsafe_mode:NullsafeMode.t -> Procdesc.t -> unit + IntraproceduralAnalysis.t -> nullsafe_mode:NullsafeMode.t -> unit (** Report registered "forall" issues (if needed), and reset the error table *) val is_reportable : nullsafe_mode:NullsafeMode.t -> err_instance -> bool