|
1 | | -(** Analysis result output. *) |
| 1 | +(** Analysis results. *) |
2 | 2 |
|
3 | 3 | open GoblintCil |
4 | 4 | open Pretty |
|
32 | 32 | val result_name: string |
33 | 33 | end |
34 | 34 |
|
35 | | -module Result (Range: Printable.S) (C: ResultConf) = |
36 | | -struct |
37 | | - include BatHashtbl.Make (ResultNode) |
38 | | - type nonrec t = Range.t t (* specialize polymorphic type for Range values *) |
39 | | - |
40 | | - let pretty () mapping = |
41 | | - let f key st dok = |
42 | | - dok ++ dprintf "%a ->@? @[%a@]\n" ResultNode.pretty key Range.pretty st |
43 | | - in |
44 | | - let content () = fold f mapping nil in |
45 | | - let defline () = dprintf "OTHERS -> Not available\n" in |
46 | | - dprintf "@[Mapping {\n @[%t%t@]}@]" content defline |
47 | | - |
48 | | - let pretty_deterministic () mapping = |
49 | | - let bindings = |
50 | | - to_list mapping |
51 | | - |> List.sort [%ord: ResultNode.t * Range.t] |
52 | | - in |
53 | | - let f dok (key, st) = |
54 | | - dok ++ dprintf "%a ->@? @[%a@]\n" ResultNode.pretty key Range.pretty st |
55 | | - in |
56 | | - let content () = List.fold_left f nil bindings in |
57 | | - let defline () = dprintf "OTHERS -> Not available\n" in |
58 | | - dprintf "@[Mapping {\n @[%t%t@]}@]" content defline |
| 35 | +module type Result = |
| 36 | +sig |
| 37 | + include ResultConf |
| 38 | + module Range: Printable.S |
| 39 | + module H: BatHashtbl.S with type key := ResultNode.t |
| 40 | + include BatHashtbl.S with type 'a t := 'a H.t and type key := ResultNode.t |
| 41 | + type t = Range.t H.t |
| 42 | +end |
59 | 43 |
|
| 44 | +module Result (Range: Printable.S) (C: ResultConf): Result with module Range = Range = |
| 45 | +struct |
60 | 46 | include C |
61 | | - |
62 | | - let printXml f xs = |
63 | | - let print_one n v = |
64 | | - (* Not using Node.location here to have updated locations in incremental analysis. |
65 | | - See: https://github.com/goblint/analyzer/issues/290#issuecomment-881258091. *) |
66 | | - let loc = UpdateCil.getLoc n in |
67 | | - BatPrintf.fprintf f "<call id=\"%s\" file=\"%s\" line=\"%d\" order=\"%d\" column=\"%d\" endLine=\"%d\" endColumn=\"%d\" synthetic=\"%B\">\n" (Node.show_id n) loc.file loc.line loc.byte loc.column loc.endLine loc.endColumn loc.synthetic; |
68 | | - BatPrintf.fprintf f "%a</call>\n" Range.printXml v |
69 | | - in |
70 | | - iter print_one xs |
71 | | - |
72 | | - let printJson f xs = |
73 | | - let print_one n v = |
74 | | - (* Not using Node.location here to have updated locations in incremental analysis. |
75 | | - See: https://github.com/goblint/analyzer/issues/290#issuecomment-881258091. *) |
76 | | - let loc = UpdateCil.getLoc n in |
77 | | - BatPrintf.fprintf f "{\n\"id\": \"%s\", \"file\": \"%s\", \"line\": \"%d\", \"byte\": \"%d\", \"column\": \"%d\", \"states\": %s\n},\n" (Node.show_id n) loc.file loc.line loc.byte loc.column (Yojson.Safe.to_string (Range.to_yojson v)) |
78 | | - in |
79 | | - iter print_one xs |
80 | | - |
81 | | - let printXmlWarning f () = |
82 | | - let one_text f Messages.Piece.{loc; text = m; _} = |
83 | | - match loc with |
84 | | - | Some loc -> |
85 | | - let l = Messages.Location.to_cil loc in |
86 | | - BatPrintf.fprintf f "\n<text file=\"%s\" line=\"%d\" column=\"%d\">%s</text>" l.file l.line l.column (XmlUtil.escape m) |
87 | | - | None -> |
88 | | - () (* TODO: not outputting warning without location *) |
89 | | - in |
90 | | - let one_w f (m: Messages.Message.t) = match m.multipiece with |
91 | | - | Single piece -> one_text f piece |
92 | | - | Group {group_text = n; pieces = e; group_loc} -> |
93 | | - let group_loc_text = match group_loc with |
94 | | - | None -> "" |
95 | | - | Some group_loc -> GobPretty.sprintf " (%a)" CilType.Location.pretty (Messages.Location.to_cil group_loc) |
96 | | - in |
97 | | - BatPrintf.fprintf f "<group name=\"%s%s\">%a</group>\n" n group_loc_text (BatList.print ~first:"" ~last:"" ~sep:"" one_text) e |
98 | | - in |
99 | | - let one_w f x = BatPrintf.fprintf f "\n<warning>%a</warning>" one_w x in |
100 | | - List.iter (one_w f) !Messages.Table.messages_list |
101 | | - |
102 | | - let output table gtable gtfxml (file: file) = |
103 | | - let out = Messages.get_out result_name !Messages.out in |
104 | | - match get_string "result" with |
105 | | - | "pretty" -> ignore (fprintf out "%a\n" pretty (Lazy.force table)) |
106 | | - | "pretty-deterministic" -> ignore (fprintf out "%a\n" pretty_deterministic (Lazy.force table)) |
107 | | - | "fast_xml" -> |
108 | | - let module SH = BatHashtbl.Make (Basetype.RawStrings) in |
109 | | - let file2funs = SH.create 100 in |
110 | | - let funs2node = SH.create 100 in |
111 | | - iter (fun n _ -> SH.add funs2node (Node.find_fundec n).svar.vname n) (Lazy.force table); |
112 | | - iterGlobals file (function |
113 | | - | GFun (fd,loc) -> SH.add file2funs loc.file fd.svar.vname |
114 | | - | _ -> () |
115 | | - ); |
116 | | - let p_node f n = BatPrintf.fprintf f "%s" (Node.show_id n) in |
117 | | - let p_nodes f xs = |
118 | | - List.iter (BatPrintf.fprintf f "<node name=\"%a\"/>\n" p_node) xs |
119 | | - in |
120 | | - let p_funs f xs = |
121 | | - let one_fun n = |
122 | | - BatPrintf.fprintf f "<function name=\"%s\">\n%a</function>\n" n p_nodes (SH.find_all funs2node n) |
123 | | - in |
124 | | - List.iter one_fun xs |
125 | | - in |
126 | | - let write_file f fn = |
127 | | - Messages.xml_file_name := fn; |
128 | | - Logs.info "Writing xml to temp. file: %s" fn; |
129 | | - BatPrintf.fprintf f "<run>"; |
130 | | - BatPrintf.fprintf f "<parameters>%s</parameters>" GobSys.command_line; |
131 | | - BatPrintf.fprintf f "<statistics>"; |
132 | | - let timing_ppf = BatFormat.formatter_of_out_channel f in |
133 | | - Timing.Default.print timing_ppf; |
134 | | - Format.pp_print_flush timing_ppf (); |
135 | | - BatPrintf.fprintf f "</statistics>"; |
136 | | - BatPrintf.fprintf f "<result>\n"; |
137 | | - BatEnum.iter (fun b -> BatPrintf.fprintf f "<file name=\"%s\" path=\"%s\">\n%a</file>\n" (Filename.basename b) b p_funs (SH.find_all file2funs b)) (BatEnum.uniq @@ SH.keys file2funs); (* nosemgrep: batenum-module *) |
138 | | - BatPrintf.fprintf f "%a" printXml (Lazy.force table); |
139 | | - gtfxml f gtable; |
140 | | - printXmlWarning f (); |
141 | | - BatPrintf.fprintf f "</result></run>\n"; |
142 | | - BatPrintf.fprintf f "%!" |
143 | | - in |
144 | | - if get_bool "g2html" then |
145 | | - BatFile.with_temporary_out ~mode:[`create;`text;`delete_on_exit] write_file |
146 | | - else |
147 | | - let f = BatIO.output_channel out in |
148 | | - write_file f (get_string "outfile") |
149 | | - | "json" -> |
150 | | - let open BatPrintf in |
151 | | - let module SH = BatHashtbl.Make (Basetype.RawStrings) in |
152 | | - let file2funs = SH.create 100 in |
153 | | - let funs2node = SH.create 100 in |
154 | | - iter (fun n _ -> SH.add funs2node (Node.find_fundec n).svar.vname n) (Lazy.force table); |
155 | | - iterGlobals file (function |
156 | | - | GFun (fd,loc) -> SH.add file2funs loc.file fd.svar.vname |
157 | | - | _ -> () |
158 | | - ); |
159 | | - let p_enum p f xs = BatEnum.print ~first:"[\n " ~last:"\n]" ~sep:",\n " p f xs in (* nosemgrep: batenum-module *) |
160 | | - let p_list p f xs = BatList.print ~first:"[\n " ~last:"\n]" ~sep:",\n " p f xs in |
161 | | - (*let p_kv f (k,p,v) = fprintf f "\"%s\": %a" k p v in*) |
162 | | - (*let p_obj f xs = BatList.print ~first:"{\n " ~last:"\n}" ~sep:",\n " p_kv xs in*) |
163 | | - let p_node f n = BatPrintf.fprintf f "\"%s\"" (Node.show_id n) in |
164 | | - let p_fun f x = fprintf f "{\n \"name\": \"%s\",\n \"nodes\": %a\n}" x (p_list p_node) (SH.find_all funs2node x) in |
165 | | - (*let p_fun f x = p_obj f [ "name", BatString.print, x; "nodes", p_list p_node, SH.find_all funs2node x ] in*) |
166 | | - let p_file f x = fprintf f "{\n \"name\": \"%s\",\n \"path\": \"%s\",\n \"functions\": %a\n}" (Filename.basename x) x (p_list p_fun) (SH.find_all file2funs x) in |
167 | | - let write_file f fn = |
168 | | - Logs.info "Writing json to temp. file: %s" fn; |
169 | | - fprintf f "{\n \"parameters\": \"%s\",\n " GobSys.command_line; |
170 | | - fprintf f "\"files\": %a,\n " (p_enum p_file) (SH.keys file2funs); |
171 | | - fprintf f "\"results\": [\n %a\n]\n" printJson (Lazy.force table); |
172 | | - (*gtfxml f gtable;*) |
173 | | - (*printXmlWarning f ();*) |
174 | | - fprintf f "}\n"; |
175 | | - in |
176 | | - if get_bool "g2html" then |
177 | | - BatFile.with_temporary_out ~mode:[`create;`text;`delete_on_exit] write_file |
178 | | - else |
179 | | - let f = BatIO.output_channel out in |
180 | | - write_file f (get_string "outfile") |
181 | | - | "sarif" -> |
182 | | - Logs.result "Writing Sarif to file: %s" (get_string "outfile"); |
183 | | - Yojson.Safe.to_channel ~std:true out (Sarif.to_yojson (List.rev !Messages.Table.messages_list)); |
184 | | - | "json-messages" -> |
185 | | - let json = `Assoc [ |
186 | | - ("files", Preprocessor.dependencies_to_yojson ()); |
187 | | - ("messages", Messages.Table.to_yojson ()); |
188 | | - ] |
189 | | - in |
190 | | - Yojson.Safe.to_channel ~std:true out json |
191 | | - | "none" -> () |
192 | | - | s -> failwith @@ "Unsupported value for option `result`: "^s |
| 47 | + module Range = Range |
| 48 | + module H = BatHashtbl.Make (ResultNode) |
| 49 | + include H |
| 50 | + type t = Range.t H.t |
193 | 51 | end |
194 | 52 |
|
195 | 53 | module ResultType2 (S: Analyses.Spec) = |
|
0 commit comments