diff --git a/infer/lib/python/inferlib/analyze.py b/infer/lib/python/inferlib/analyze.py index 82faadbdf..edee91857 100644 --- a/infer/lib/python/inferlib/analyze.py +++ b/infer/lib/python/inferlib/analyze.py @@ -522,6 +522,8 @@ class Infer: if self.javac.annotations_out is not None: infer_print_options += [ '-local_config', self.javac.annotations_out] + if self.args.debug: + infer_print_options.append('-with_infer_src_loc') exit_status = subprocess.check_call( infer_print_cmd + infer_print_options ) diff --git a/infer/lib/python/inferlib/issues.py b/infer/lib/python/inferlib/issues.py index 94a4d610f..2662a5c58 100644 --- a/infer/lib/python/inferlib/issues.py +++ b/infer/lib/python/inferlib/issues.py @@ -93,6 +93,10 @@ JSON_INDEX_TRACE_DESCRIPTION = 'description' JSON_INDEX_TRACE_NODE_TAGS = 'node_tags' JSON_INDEX_TRACE_NODE_TAGS_TAG = 'tags' JSON_INDEX_TRACE_NODE_TAGS_VALUE = 'value' +JSON_INDEX_INFER_SOURCE_LOC = 'infer_source_loc' +JSON_INDEX_ISL_FILE = 'file' +JSON_INDEX_ISL_LINE = 'line' +JSON_INDEX_ISL_COLUMN = 'column' QUALIFIER_TAGS = 'qualifier_tags' BUCKET_TAGS = 'bucket' @@ -146,11 +150,20 @@ def text_of_report(report): line = report[JSON_INDEX_LINE] error_type = report[JSON_INDEX_TYPE] msg = report[JSON_INDEX_QUALIFIER] - return u'%s:%d: %s: %s\n %s' % ( + infer_loc = '' + if JSON_INDEX_INFER_SOURCE_LOC in report: + loc = report[JSON_INDEX_INFER_SOURCE_LOC] + infer_loc = u' (%s:%d:%d)' % ( + loc[JSON_INDEX_ISL_FILE], + loc[JSON_INDEX_ISL_LINE], + loc[JSON_INDEX_ISL_COLUMN], + ) + return u'%s:%d: %s: %s%s\n %s' % ( filename, line, kind.lower(), error_type, + infer_loc, msg, ) diff --git a/infer/src/backend/errlog.ml b/infer/src/backend/errlog.ml index 2cf9104de..1aba5770b 100644 --- a/infer/src/backend/errlog.ml +++ b/infer/src/backend/errlog.ml @@ -64,8 +64,16 @@ let empty () = ErrLogHash.create 13 (** type of the function to be passed to iter *) type iter_fun = - (int * int) -> Location.t -> Exceptions.err_kind -> bool -> Localise.t -> Localise.error_desc -> - string -> loc_trace -> Prop.normal Prop.t option -> Exceptions.err_class -> unit + (int * int) -> + Location.t -> + ml_location option -> + Exceptions.err_kind -> + bool -> + Localise.t -> Localise.error_desc -> string -> + loc_trace -> + Prop.normal Prop.t option -> + Exceptions.err_class -> + unit (** Apply f to nodes and error names *) let iter (f: iter_fun) (err_log: t) = @@ -73,7 +81,7 @@ let iter (f: iter_fun) (err_log: t) = ErrDataSet.iter (fun (node_id_key, section, loc, mloco, ltr, pre_opt, eclass) -> f - node_id_key loc ekind in_footprint err_name + node_id_key loc mloco ekind in_footprint err_name desc severity ltr pre_opt eclass) set) err_log diff --git a/infer/src/backend/errlog.mli b/infer/src/backend/errlog.mli index 27b21637c..02de59646 100644 --- a/infer/src/backend/errlog.mli +++ b/infer/src/backend/errlog.mli @@ -9,6 +9,8 @@ (** Module for error logs. *) +open Utils + (** Element of a loc trace *) type loc_trace_elem = { lt_level : int; (** nesting level of procedure calls *) @@ -28,8 +30,16 @@ val empty : unit -> t (** type of the function to be passed to iter *) type iter_fun = - (int * int) -> Location.t -> Exceptions.err_kind -> bool -> Localise.t -> Localise.error_desc -> - string -> loc_trace -> Prop.normal Prop.t option -> Exceptions.err_class -> unit + (int * int) -> + Location.t -> + ml_location option -> + Exceptions.err_kind -> + bool -> + Localise.t -> Localise.error_desc -> string -> + loc_trace -> + Prop.normal Prop.t option -> + Exceptions.err_class -> + unit (** Apply f to nodes and error names *) val iter : iter_fun -> t -> unit diff --git a/infer/src/backend/inferprint.ml b/infer/src/backend/inferprint.ml index 04f6cd9e1..666a4a15c 100644 --- a/infer/src/backend/inferprint.ml +++ b/infer/src/backend/inferprint.ml @@ -64,6 +64,9 @@ let precondition_stats = ref false (** name of the file to load analysis results from *) let load_analysis_results = ref None +(** If true then include Infer source code locations in json reports *) +let reports_include_ml_loc = ref false + (** name of the file to load save results to *) let save_analysis_results = ref None @@ -114,6 +117,8 @@ let arg_desc = "Path to the .inferconfig file"; "-local_config", Arg.String (fun s -> Inferconfig.local_config := Some s), Some "Path", "Path to local config file"; + "-with_infer_src_loc", Arg.Set reports_include_ml_loc, None, + "include the location (in the Infer source code) from where reports are generated"; ] in Arg.create_options_desc false "Options" desc in let reserved_arg = @@ -414,7 +419,7 @@ module BugsCsv = struct let pp_bugs error_filter fname fmt summary = let pp x = F.fprintf fmt x in let err_log = summary.Specs.attributes.ProcAttributes.err_log in - let pp_row (node_id, node_key) loc ekind in_footprint error_name error_desc severity ltr pre_opt eclass = + let pp_row (node_id, node_key) loc ml_loc_opt ekind in_footprint error_name error_desc severity ltr pre_opt eclass = if in_footprint && error_filter error_desc error_name then let err_desc_string = error_desc_to_csv_string error_desc in let err_advice_string = error_advice_to_csv_string error_desc in @@ -463,13 +468,17 @@ module BugsJson = struct let pp_bugs error_filter fname fmt summary = let pp x = F.fprintf fmt x in let err_log = summary.Specs.attributes.ProcAttributes.err_log in - let pp_row (node_id, node_key) loc ekind in_footprint error_name error_desc severity ltr pre_opt eclass = + let pp_row (node_id, node_key) loc ml_loc_opt ekind in_footprint error_name error_desc severity ltr pre_opt eclass = if in_footprint && error_filter error_desc error_name then let kind = Exceptions.err_kind_string ekind in let bug_type = Localise.to_string error_name in let procedure_id = Procname.to_filename (Specs.get_proc_name summary) in let file = DB.source_file_to_string summary.Specs.attributes.ProcAttributes.loc.Location.file in + let json_mloc = match ml_loc_opt with + | Some (file, line, column) when !reports_include_ml_loc -> + Some Jsonbug_j.{ file; line; column } + | _ -> None in let bug = { bug_class = Exceptions.err_class_string eclass; kind = kind; @@ -485,6 +494,7 @@ module BugsJson = struct qualifier_tags = error_desc_to_qualifier_tags_records error_desc; hash = get_bug_hash kind bug_type procedure_id file node_key error_desc; dotty = error_desc_to_dotty_string error_desc; + infer_source_loc = json_mloc; } in if not !is_first_item then pp "," else is_first_item := false; pp "%s@?" (string_of_jsonbug bug) in @@ -495,7 +505,7 @@ module BugsTxt = struct (** Write bug report in text format *) let pp_bugs error_filter fname fmt summary = let err_log = summary.Specs.attributes.ProcAttributes.err_log in - let pp_row (node_id, node_key) loc ekind in_footprint error_name error_desc severity ltr pre_opt eclass = + let pp_row (node_id, node_key) loc ml_loc_opt ekind in_footprint error_name error_desc severity ltr pre_opt eclass = if in_footprint && error_filter error_desc error_name then Exceptions.pp_err (node_id, node_key) loc ekind error_name error_desc None fmt () in Errlog.iter pp_row err_log @@ -535,7 +545,7 @@ module BugsXml = struct (** print bugs from summary in xml *) let pp_bugs error_filter linereader fmt summary = let err_log = summary.Specs.attributes.ProcAttributes.err_log in - let do_row (node_id, node_key) loc ekind in_footprint error_name error_desc severity ltr pre_opt eclass = + let do_row (node_id, node_key) loc ml_loc_opt ekind in_footprint error_name error_desc severity ltr pre_opt eclass = if in_footprint && error_filter error_desc error_name then let err_desc_string = error_desc_to_xml_string error_desc in let precondition_tree () = match pre_opt with @@ -729,7 +739,7 @@ module Stats = struct let process_err_log error_filter linereader err_log stats = let found_errors = ref false in - let process_row (node_id, node_key) loc ekind in_footprint error_name error_desc severity ltr pre_opt eclass = + let process_row (node_id, node_key) loc ml_loc_opt ekind in_footprint error_name error_desc severity ltr pre_opt eclass = let type_str = Localise.to_string error_name in if in_footprint && error_filter error_desc error_name then match ekind with diff --git a/infer/src/backend/jsonbug.atd b/infer/src/backend/jsonbug.atd index 09352672c..652eb8e73 100644 --- a/infer/src/backend/jsonbug.atd +++ b/infer/src/backend/jsonbug.atd @@ -1,33 +1,40 @@ type tag_value_record = { - tag : string; - value : string; + tag : string; + value : string; } type json_trace_item = { - level : int; - filename : string; - line_number : int; - description : string; - node_tags : tag_value_record list; + level : int; + filename : string; + line_number : int; + description : string; + node_tags : tag_value_record list; +} + +type loc = { + file: string; + line: int; + column: int; } type jsonbug = { - bug_class : string; - kind : string; - bug_type : string; - qualifier : string; - severity : string; - line: int; - procedure : string; - procedure_id : string; - file : string; - bug_trace : json_trace_item list; - key : int; - qualifier_tags : tag_value_record list; - hash : int; - dotty : string; + bug_class : string; + kind : string; + bug_type : string; + qualifier : string; + severity : string; + line: int; + procedure : string; + procedure_id : string; + file : string; + bug_trace : json_trace_item list; + key : int; + qualifier_tags : tag_value_record list; + hash : int; + dotty : string; + ?infer_source_loc: loc option; } type json_trace = { - trace : json_trace_item list; + trace : json_trace_item list; } diff --git a/infer/src/backend/printer.ml b/infer/src/backend/printer.ml index 8ca494405..b1d6e2c7d 100644 --- a/infer/src/backend/printer.ml +++ b/infer/src/backend/printer.ml @@ -290,9 +290,8 @@ let proc_write_log whole_seconds cfg pname = (** Creare a hash table mapping line numbers to the set of errors occurring on that line *) let create_errors_per_line err_log = let err_per_line = Hashtbl.create 17 in - let add_err node_id_key loc ekind in_footprint err_name desc severity ltr pre_opt eclass = + let add_err node_id_key loc ml_loc_opt ekind in_footprint err_name desc severity ltr pre_opt eclass = let err_str = Localise.to_string err_name ^ " " ^ (pp_to_string Localise.pp_error_desc desc) in - (* if in_footprint then *) try let set = Hashtbl.find err_per_line loc.Location.line in Hashtbl.replace err_per_line loc.Location.line (StringSet.add err_str set)