ada: Fix wrong resolution for hidden discriminant in predicate
[official-gcc.git] / gcc / diagnostic-format-sarif.cc
blob5e483988027b78e9bbb27747ae791dbb37c17071
1 /* SARIF output for diagnostics
2 Copyright (C) 2018-2023 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "diagnostic.h"
27 #include "diagnostic-metadata.h"
28 #include "diagnostic-path.h"
29 #include "json.h"
30 #include "cpplib.h"
31 #include "logical-location.h"
32 #include "diagnostic-client-data-hooks.h"
33 #include "diagnostic-diagram.h"
34 #include "text-art/canvas.h"
36 class sarif_builder;
38 /* Subclass of json::object for SARIF invocation objects
39 (SARIF v2.1.0 section 3.20). */
41 class sarif_invocation : public json::object
43 public:
44 sarif_invocation ()
45 : m_notifications_arr (new json::array ()),
46 m_success (true)
49 void add_notification_for_ice (diagnostic_context *context,
50 diagnostic_info *diagnostic,
51 sarif_builder *builder);
52 void prepare_to_flush ();
54 private:
55 json::array *m_notifications_arr;
56 bool m_success;
59 /* Subclass of json::object for SARIF result objects
60 (SARIF v2.1.0 section 3.27). */
62 class sarif_result : public json::object
64 public:
65 sarif_result () : m_related_locations_arr (NULL) {}
67 void
68 on_nested_diagnostic (diagnostic_context *context,
69 diagnostic_info *diagnostic,
70 diagnostic_t orig_diag_kind,
71 sarif_builder *builder);
72 void on_diagram (diagnostic_context *context,
73 const diagnostic_diagram &diagram,
74 sarif_builder *builder);
76 private:
77 void add_related_location (json::object *location_obj);
79 json::array *m_related_locations_arr;
82 /* Subclass of json::object for SARIF notification objects
83 (SARIF v2.1.0 section 3.58).
85 This subclass is specifically for notifying when an
86 internal compiler error occurs. */
88 class sarif_ice_notification : public json::object
90 public:
91 sarif_ice_notification (diagnostic_context *context,
92 diagnostic_info *diagnostic,
93 sarif_builder *builder);
96 /* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
97 and -fdiagnostics-format=sarif-file).
99 As diagnostics occur, we build "result" JSON objects, and
100 accumulate state:
101 - which source files are referenced
102 - which warnings are emitted
103 - which CWEs are used
105 At the end of the compile, we use the above to build the full SARIF
106 object tree, adding the result objects to the correct place, and
107 creating objects for the various source files, warnings and CWEs
108 referenced.
110 Implemented:
111 - fix-it hints
112 - CWE metadata
113 - diagnostic groups (see limitations below)
114 - logical locations (e.g. cfun)
116 Known limitations:
117 - GCC supports one-deep nesting of diagnostics (via auto_diagnostic_group),
118 but we only capture location and message information from such nested
119 diagnostics (e.g. we ignore fix-it hints on them)
120 - doesn't yet capture command-line arguments: would be run.invocations
121 property (SARIF v2.1.0 section 3.14.11), as invocation objects
122 (SARIF v2.1.0 section 3.20), but we'd want to capture the arguments to
123 toplev::main, and the response files.
124 - doesn't capture escape_on_output_p
125 - doesn't capture secondary locations within a rich_location
126 (perhaps we should use the "relatedLocations" property: SARIF v2.1.0
127 section 3.27.22)
128 - doesn't capture "artifact.encoding" property
129 (SARIF v2.1.0 section 3.24.9).
130 - doesn't capture hashes of the source files
131 ("artifact.hashes" property (SARIF v2.1.0 section 3.24.11).
132 - doesn't capture the "analysisTarget" property
133 (SARIF v2.1.0 section 3.27.13).
134 - doesn't capture labelled ranges
135 - doesn't capture -Werror cleanly
136 - doesn't capture inlining information (can SARIF handle this?)
137 - doesn't capture macro expansion information (can SARIF handle this?). */
139 class sarif_builder
141 public:
142 sarif_builder (diagnostic_context *context);
144 void end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic,
145 diagnostic_t orig_diag_kind);
146 void emit_diagram (diagnostic_context *context,
147 const diagnostic_diagram &diagram);
148 void end_group ();
150 void flush_to_file (FILE *outf);
152 json::array *make_locations_arr (diagnostic_info *diagnostic);
153 json::object *make_location_object (const rich_location &rich_loc,
154 const logical_location *logical_loc);
155 json::object *make_message_object (const char *msg) const;
156 json::object *
157 make_message_object_for_diagram (diagnostic_context *context,
158 const diagnostic_diagram &diagram);
160 private:
161 sarif_result *make_result_object (diagnostic_context *context,
162 diagnostic_info *diagnostic,
163 diagnostic_t orig_diag_kind);
164 void set_any_logical_locs_arr (json::object *location_obj,
165 const logical_location *logical_loc);
166 json::object *make_location_object (const diagnostic_event &event);
167 json::object *
168 make_logical_location_object (const logical_location &logical_loc) const;
169 json::object *make_code_flow_object (const diagnostic_path &path);
170 json::object *make_thread_flow_object (const diagnostic_path &path);
171 json::object *
172 make_thread_flow_location_object (const diagnostic_event &event);
173 json::array *maybe_make_kinds_array (diagnostic_event::meaning m) const;
174 json::object *maybe_make_physical_location_object (location_t loc);
175 json::object *make_artifact_location_object (location_t loc);
176 json::object *make_artifact_location_object (const char *filename);
177 json::object *make_artifact_location_object_for_pwd () const;
178 json::object *maybe_make_region_object (location_t loc) const;
179 json::object *maybe_make_region_object_for_context (location_t loc) const;
180 json::object *make_region_object_for_hint (const fixit_hint &hint) const;
181 json::object *make_multiformat_message_string (const char *msg) const;
182 json::object *make_top_level_object (sarif_invocation *invocation_obj,
183 json::array *results);
184 json::object *make_run_object (sarif_invocation *invocation_obj,
185 json::array *results);
186 json::object *make_tool_object () const;
187 json::object *make_driver_tool_component_object () const;
188 json::array *maybe_make_taxonomies_array () const;
189 json::object *maybe_make_cwe_taxonomy_object () const;
190 json::object *make_tool_component_reference_object_for_cwe () const;
191 json::object *
192 make_reporting_descriptor_object_for_warning (diagnostic_context *context,
193 diagnostic_info *diagnostic,
194 diagnostic_t orig_diag_kind,
195 const char *option_text);
196 json::object *make_reporting_descriptor_object_for_cwe_id (int cwe_id) const;
197 json::object *
198 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id);
199 json::object *make_artifact_object (const char *filename);
200 json::object *maybe_make_artifact_content_object (const char *filename) const;
201 json::object *maybe_make_artifact_content_object (const char *filename,
202 int start_line,
203 int end_line) const;
204 json::object *make_fix_object (const rich_location &rich_loc);
205 json::object *make_artifact_change_object (const rich_location &richloc);
206 json::object *make_replacement_object (const fixit_hint &hint) const;
207 json::object *make_artifact_content_object (const char *text) const;
208 int get_sarif_column (expanded_location exploc) const;
210 diagnostic_context *m_context;
212 /* The JSON object for the invocation object. */
213 sarif_invocation *m_invocation_obj;
215 /* The JSON array of pending diagnostics. */
216 json::array *m_results_array;
218 /* The JSON object for the result object (if any) in the current
219 diagnostic group. */
220 sarif_result *m_cur_group_result;
222 hash_set <const char *> m_filenames;
223 bool m_seen_any_relative_paths;
224 hash_set <free_string_hash> m_rule_id_set;
225 json::array *m_rules_arr;
227 /* The set of all CWE IDs we've seen, if any. */
228 hash_set <int_hash <int, 0, 1> > m_cwe_id_set;
230 int m_tabstop;
233 static sarif_builder *the_builder;
235 /* class sarif_invocation : public json::object. */
237 /* Handle an internal compiler error DIAGNOSTIC occurring on CONTEXT.
238 Add an object representing the ICE to the notifications array. */
240 void
241 sarif_invocation::add_notification_for_ice (diagnostic_context *context,
242 diagnostic_info *diagnostic,
243 sarif_builder *builder)
245 m_success = false;
247 sarif_ice_notification *notification_obj
248 = new sarif_ice_notification (context, diagnostic, builder);
249 m_notifications_arr->append (notification_obj);
252 void
253 sarif_invocation::prepare_to_flush ()
255 /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */
256 set ("executionSuccessful", new json::literal (m_success));
258 /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */
259 set ("toolExecutionNotifications", m_notifications_arr);
262 /* class sarif_result : public json::object. */
264 /* Handle secondary diagnostics that occur within a diagnostic group.
265 The closest SARIF seems to have to nested diagnostics is the
266 "relatedLocations" property of result objects (SARIF v2.1.0 section 3.27.22),
267 so we lazily set this property and populate the array if and when
268 secondary diagnostics occur (such as notes to a warning). */
270 void
271 sarif_result::on_nested_diagnostic (diagnostic_context *context,
272 diagnostic_info *diagnostic,
273 diagnostic_t /*orig_diag_kind*/,
274 sarif_builder *builder)
276 /* We don't yet generate meaningful logical locations for notes;
277 sometimes these will related to current_function_decl, but
278 often they won't. */
279 json::object *location_obj
280 = builder->make_location_object (*diagnostic->richloc, NULL);
281 json::object *message_obj
282 = builder->make_message_object (pp_formatted_text (context->printer));
283 pp_clear_output_area (context->printer);
284 location_obj->set ("message", message_obj);
286 add_related_location (location_obj);
289 /* Handle diagrams that occur within a diagnostic group.
290 The closest thing in SARIF seems to be to add a location to the
291 "releatedLocations" property (SARIF v2.1.0 section 3.27.22),
292 and to put the diagram into the "message" property of that location
293 (SARIF v2.1.0 section 3.28.5). */
295 void
296 sarif_result::on_diagram (diagnostic_context *context,
297 const diagnostic_diagram &diagram,
298 sarif_builder *builder)
300 json::object *location_obj = new json::object ();
301 json::object *message_obj
302 = builder->make_message_object_for_diagram (context, diagram);
303 location_obj->set ("message", message_obj);
305 add_related_location (location_obj);
308 /* Add LOCATION_OBJ to this result's "relatedLocations" array,
309 creating it if it doesn't yet exist. */
311 void
312 sarif_result::add_related_location (json::object *location_obj)
314 if (!m_related_locations_arr)
316 m_related_locations_arr = new json::array ();
317 set ("relatedLocations", m_related_locations_arr);
319 m_related_locations_arr->append (location_obj);
322 /* class sarif_ice_notification : public json::object. */
324 /* sarif_ice_notification's ctor.
325 DIAGNOSTIC is an internal compiler error. */
327 sarif_ice_notification::sarif_ice_notification (diagnostic_context *context,
328 diagnostic_info *diagnostic,
329 sarif_builder *builder)
331 /* "locations" property (SARIF v2.1.0 section 3.58.4). */
332 json::array *locations_arr = builder->make_locations_arr (diagnostic);
333 set ("locations", locations_arr);
335 /* "message" property (SARIF v2.1.0 section 3.85.5). */
336 json::object *message_obj
337 = builder->make_message_object (pp_formatted_text (context->printer));
338 pp_clear_output_area (context->printer);
339 set ("message", message_obj);
341 /* "level" property (SARIF v2.1.0 section 3.58.6). */
342 set ("level", new json::string ("error"));
345 /* class sarif_builder. */
347 /* sarif_builder's ctor. */
349 sarif_builder::sarif_builder (diagnostic_context *context)
350 : m_context (context),
351 m_invocation_obj (new sarif_invocation ()),
352 m_results_array (new json::array ()),
353 m_cur_group_result (NULL),
354 m_seen_any_relative_paths (false),
355 m_rule_id_set (),
356 m_rules_arr (new json::array ()),
357 m_tabstop (context->tabstop)
361 /* Implementation of "end_diagnostic" for SARIF output. */
363 void
364 sarif_builder::end_diagnostic (diagnostic_context *context,
365 diagnostic_info *diagnostic,
366 diagnostic_t orig_diag_kind)
368 if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
370 m_invocation_obj->add_notification_for_ice (context, diagnostic, this);
371 return;
374 if (m_cur_group_result)
375 /* Nested diagnostic. */
376 m_cur_group_result->on_nested_diagnostic (context,
377 diagnostic,
378 orig_diag_kind,
379 this);
380 else
382 /* Top-level diagnostic. */
383 sarif_result *result_obj
384 = make_result_object (context, diagnostic, orig_diag_kind);
385 m_results_array->append (result_obj);
386 m_cur_group_result = result_obj;
390 /* Implementation of diagnostic_context::m_diagrams.m_emission_cb
391 for SARIF output. */
393 void
394 sarif_builder::emit_diagram (diagnostic_context *context,
395 const diagnostic_diagram &diagram)
397 /* We must be within the emission of a top-level diagnostic. */
398 gcc_assert (m_cur_group_result);
399 m_cur_group_result->on_diagram (context, diagram, this);
402 /* Implementation of "end_group_cb" for SARIF output. */
404 void
405 sarif_builder::end_group ()
407 m_cur_group_result = NULL;
410 /* Create a top-level object, and add it to all the results
411 (and other entities) we've seen so far.
413 Flush it all to OUTF. */
415 void
416 sarif_builder::flush_to_file (FILE *outf)
418 m_invocation_obj->prepare_to_flush ();
419 json::object *top = make_top_level_object (m_invocation_obj, m_results_array);
420 top->dump (outf);
421 m_invocation_obj = NULL;
422 m_results_array = NULL;
423 fprintf (outf, "\n");
424 delete top;
427 /* Attempt to convert DIAG_KIND to a suitable value for the "level"
428 property (SARIF v2.1.0 section 3.27.10).
430 Return NULL if there isn't one. */
432 static const char *
433 maybe_get_sarif_level (diagnostic_t diag_kind)
435 switch (diag_kind)
437 case DK_WARNING:
438 return "warning";
439 case DK_ERROR:
440 return "error";
441 case DK_NOTE:
442 case DK_ANACHRONISM:
443 return "note";
444 default:
445 return NULL;
449 /* Make a string for DIAG_KIND suitable for use a ruleId
450 (SARIF v2.1.0 section 3.27.5) as a fallback for when we don't
451 have anything better to use. */
453 static char *
454 make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind)
456 static const char *const diagnostic_kind_text[] = {
457 #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
458 #include "diagnostic.def"
459 #undef DEFINE_DIAGNOSTIC_KIND
460 "must-not-happen"
462 /* Lose the trailing ": ". */
463 const char *kind_text = diagnostic_kind_text[diag_kind];
464 size_t len = strlen (kind_text);
465 gcc_assert (len > 2);
466 gcc_assert (kind_text[len - 2] == ':');
467 gcc_assert (kind_text[len - 1] == ' ');
468 char *rstrip = xstrdup (kind_text);
469 rstrip[len - 2] = '\0';
470 return rstrip;
473 /* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */
475 sarif_result *
476 sarif_builder::make_result_object (diagnostic_context *context,
477 diagnostic_info *diagnostic,
478 diagnostic_t orig_diag_kind)
480 sarif_result *result_obj = new sarif_result ();
482 /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
483 /* Ideally we'd have an option_name for these. */
484 if (char *option_text
485 = context->option_name (context, diagnostic->option_index,
486 orig_diag_kind, diagnostic->kind))
488 /* Lazily create reportingDescriptor objects for and add to m_rules_arr.
489 Set ruleId referencing them. */
490 result_obj->set ("ruleId", new json::string (option_text));
491 if (m_rule_id_set.contains (option_text))
492 free (option_text);
493 else
495 /* This is the first time we've seen this ruleId. */
496 /* Add to set, taking ownership. */
497 m_rule_id_set.add (option_text);
499 json::object *reporting_desc_obj
500 = make_reporting_descriptor_object_for_warning (context,
501 diagnostic,
502 orig_diag_kind,
503 option_text);
504 m_rules_arr->append (reporting_desc_obj);
507 else
509 /* Otherwise, we have an "error" or a stray "note"; use the
510 diagnostic kind as the ruleId, so that the result object at least
511 has a ruleId.
512 We don't bother creating reportingDescriptor objects for these. */
513 char *rule_id = make_rule_id_for_diagnostic_kind (orig_diag_kind);
514 result_obj->set ("ruleId", new json::string (rule_id));
515 free (rule_id);
518 /* "taxa" property (SARIF v2.1.0 section 3.27.8). */
519 if (diagnostic->metadata)
520 if (int cwe_id = diagnostic->metadata->get_cwe ())
522 json::array *taxa_arr = new json::array ();
523 json::object *cwe_id_obj
524 = make_reporting_descriptor_reference_object_for_cwe_id (cwe_id);
525 taxa_arr->append (cwe_id_obj);
526 result_obj->set ("taxa", taxa_arr);
529 /* "level" property (SARIF v2.1.0 section 3.27.10). */
530 if (const char *sarif_level = maybe_get_sarif_level (diagnostic->kind))
531 result_obj->set ("level", new json::string (sarif_level));
533 /* "message" property (SARIF v2.1.0 section 3.27.11). */
534 json::object *message_obj
535 = make_message_object (pp_formatted_text (context->printer));
536 pp_clear_output_area (context->printer);
537 result_obj->set ("message", message_obj);
539 /* "locations" property (SARIF v2.1.0 section 3.27.12). */
540 json::array *locations_arr = make_locations_arr (diagnostic);
541 result_obj->set ("locations", locations_arr);
543 /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
544 if (const diagnostic_path *path = diagnostic->richloc->get_path ())
546 json::array *code_flows_arr = new json::array ();
547 json::object *code_flow_obj = make_code_flow_object (*path);
548 code_flows_arr->append (code_flow_obj);
549 result_obj->set ("codeFlows", code_flows_arr);
552 /* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is
553 set up later, if any nested diagnostics occur within this diagnostic
554 group. */
556 /* "fixes" property (SARIF v2.1.0 section 3.27.30). */
557 const rich_location *richloc = diagnostic->richloc;
558 if (richloc->get_num_fixit_hints ())
560 json::array *fix_arr = new json::array ();
561 json::object *fix_obj = make_fix_object (*richloc);
562 fix_arr->append (fix_obj);
563 result_obj->set ("fixes", fix_arr);
566 return result_obj;
569 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
570 for a GCC warning. */
572 json::object *
573 sarif_builder::
574 make_reporting_descriptor_object_for_warning (diagnostic_context *context,
575 diagnostic_info *diagnostic,
576 diagnostic_t /*orig_diag_kind*/,
577 const char *option_text)
579 json::object *reporting_desc = new json::object ();
581 /* "id" property (SARIF v2.1.0 section 3.49.3). */
582 reporting_desc->set ("id", new json::string (option_text));
584 /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since
585 it seems redundant compared to "id". */
587 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
588 if (context->get_option_url)
590 char *option_url
591 = context->get_option_url (context, diagnostic->option_index);
592 if (option_url)
594 reporting_desc->set ("helpUri", new json::string (option_url));
595 free (option_url);
599 return reporting_desc;
602 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
603 for CWE_ID, for use within the CWE taxa array. */
605 json::object *
606 sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id) const
608 json::object *reporting_desc = new json::object ();
610 /* "id" property (SARIF v2.1.0 section 3.49.3). */
612 pretty_printer pp;
613 pp_printf (&pp, "%i", cwe_id);
614 reporting_desc->set ("id", new json::string (pp_formatted_text (&pp)));
617 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
619 char *url = get_cwe_url (cwe_id);
620 reporting_desc->set ("helpUri", new json::string (url));
621 free (url);
624 return reporting_desc;
627 /* Make a reportingDescriptorReference object (SARIF v2.1.0 section 3.52)
628 referencing CWE_ID, for use within a result object.
629 Also, add CWE_ID to m_cwe_id_set. */
631 json::object *
632 sarif_builder::
633 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id)
635 json::object *desc_ref_obj = new json::object ();
637 /* "id" property (SARIF v2.1.0 section 3.52.4). */
639 pretty_printer pp;
640 pp_printf (&pp, "%i", cwe_id);
641 desc_ref_obj->set ("id", new json::string (pp_formatted_text (&pp)));
644 /* "toolComponent" property (SARIF v2.1.0 section 3.52.7). */
645 json::object *comp_ref_obj = make_tool_component_reference_object_for_cwe ();
646 desc_ref_obj->set ("toolComponent", comp_ref_obj);
648 /* Add CWE_ID to our set. */
649 gcc_assert (cwe_id > 0);
650 m_cwe_id_set.add (cwe_id);
652 return desc_ref_obj;
655 /* Make a toolComponentReference object (SARIF v2.1.0 section 3.54) that
656 references the CWE taxonomy. */
658 json::object *
659 sarif_builder::
660 make_tool_component_reference_object_for_cwe () const
662 json::object *comp_ref_obj = new json::object ();
664 /* "name" property (SARIF v2.1.0 section 3.54.3). */
665 comp_ref_obj->set ("name", new json::string ("cwe"));
667 return comp_ref_obj;
670 /* Make an array suitable for use as the "locations" property of:
671 - a "result" object (SARIF v2.1.0 section 3.27.12), or
672 - a "notification" object (SARIF v2.1.0 section 3.58.4). */
674 json::array *
675 sarif_builder::make_locations_arr (diagnostic_info *diagnostic)
677 json::array *locations_arr = new json::array ();
678 const logical_location *logical_loc = NULL;
679 if (m_context->m_client_data_hooks)
680 logical_loc
681 = m_context->m_client_data_hooks->get_current_logical_location ();
683 json::object *location_obj
684 = make_location_object (*diagnostic->richloc, logical_loc);
685 locations_arr->append (location_obj);
686 return locations_arr;
689 /* If LOGICAL_LOC is non-NULL, use it to create a "logicalLocations" property
690 within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */
692 void
693 sarif_builder::
694 set_any_logical_locs_arr (json::object *location_obj,
695 const logical_location *logical_loc)
697 if (!logical_loc)
698 return;
699 json::object *logical_loc_obj = make_logical_location_object (*logical_loc);
700 json::array *location_locs_arr = new json::array ();
701 location_locs_arr->append (logical_loc_obj);
702 location_obj->set ("logicalLocations", location_locs_arr);
705 /* Make a location object (SARIF v2.1.0 section 3.28) for RICH_LOC
706 and LOGICAL_LOC. */
708 json::object *
709 sarif_builder::make_location_object (const rich_location &rich_loc,
710 const logical_location *logical_loc)
712 json::object *location_obj = new json::object ();
714 /* Get primary loc from RICH_LOC. */
715 location_t loc = rich_loc.get_loc ();
717 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
718 if (json::object *phs_loc_obj = maybe_make_physical_location_object (loc))
719 location_obj->set ("physicalLocation", phs_loc_obj);
721 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
722 set_any_logical_locs_arr (location_obj, logical_loc);
724 return location_obj;
727 /* Make a location object (SARIF v2.1.0 section 3.28) for EVENT
728 within a diagnostic_path. */
730 json::object *
731 sarif_builder::make_location_object (const diagnostic_event &event)
733 json::object *location_obj = new json::object ();
735 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
736 location_t loc = event.get_location ();
737 if (json::object *phs_loc_obj = maybe_make_physical_location_object (loc))
738 location_obj->set ("physicalLocation", phs_loc_obj);
740 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
741 const logical_location *logical_loc = event.get_logical_location ();
742 set_any_logical_locs_arr (location_obj, logical_loc);
744 /* "message" property (SARIF v2.1.0 section 3.28.5). */
745 label_text ev_desc = event.get_desc (false);
746 json::object *message_obj = make_message_object (ev_desc.get ());
747 location_obj->set ("message", message_obj);
749 return location_obj;
752 /* Make a physicalLocation object (SARIF v2.1.0 section 3.29) for LOC,
753 or return NULL;
754 Add any filename to the m_artifacts. */
756 json::object *
757 sarif_builder::maybe_make_physical_location_object (location_t loc)
759 if (loc <= BUILTINS_LOCATION || LOCATION_FILE (loc) == NULL)
760 return NULL;
762 json::object *phys_loc_obj = new json::object ();
764 /* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */
765 json::object *artifact_loc_obj = make_artifact_location_object (loc);
766 phys_loc_obj->set ("artifactLocation", artifact_loc_obj);
767 m_filenames.add (LOCATION_FILE (loc));
769 /* "region" property (SARIF v2.1.0 section 3.29.4). */
770 if (json::object *region_obj = maybe_make_region_object (loc))
771 phys_loc_obj->set ("region", region_obj);
773 /* "contextRegion" property (SARIF v2.1.0 section 3.29.5). */
774 if (json::object *context_region_obj
775 = maybe_make_region_object_for_context (loc))
776 phys_loc_obj->set ("contextRegion", context_region_obj);
778 /* Instead, we add artifacts to the run as a whole,
779 with artifact.contents.
780 Could do both, though. */
782 return phys_loc_obj;
785 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for LOC,
786 or return NULL. */
788 json::object *
789 sarif_builder::make_artifact_location_object (location_t loc)
791 return make_artifact_location_object (LOCATION_FILE (loc));
794 /* The ID value for use in "uriBaseId" properties (SARIF v2.1.0 section 3.4.4)
795 for when we need to express paths relative to PWD. */
797 #define PWD_PROPERTY_NAME ("PWD")
799 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for FILENAME,
800 or return NULL. */
802 json::object *
803 sarif_builder::make_artifact_location_object (const char *filename)
805 json::object *artifact_loc_obj = new json::object ();
807 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
808 artifact_loc_obj->set ("uri", new json::string (filename));
810 if (filename[0] != '/')
812 /* If we have a relative path, set the "uriBaseId" property
813 (SARIF v2.1.0 section 3.4.4). */
814 artifact_loc_obj->set ("uriBaseId", new json::string (PWD_PROPERTY_NAME));
815 m_seen_any_relative_paths = true;
818 return artifact_loc_obj;
821 /* Get the PWD, or NULL, as an absolute file-based URI,
822 adding a trailing forward slash (as required by SARIF v2.1.0
823 section 3.14.14). */
825 static char *
826 make_pwd_uri_str ()
828 /* The prefix of a file-based URI, up to, but not including the path. */
829 #define FILE_PREFIX ("file://")
831 const char *pwd = getpwd ();
832 if (!pwd)
833 return NULL;
834 size_t len = strlen (pwd);
835 if (len == 0 || pwd[len - 1] != '/')
836 return concat (FILE_PREFIX, pwd, "/", NULL);
837 else
839 gcc_assert (pwd[len - 1] == '/');
840 return concat (FILE_PREFIX, pwd, NULL);
844 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for the pwd,
845 for use in the "run.originalUriBaseIds" property (SARIF v2.1.0
846 section 3.14.14) when we have any relative paths. */
848 json::object *
849 sarif_builder::make_artifact_location_object_for_pwd () const
851 json::object *artifact_loc_obj = new json::object ();
853 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
854 if (char *pwd = make_pwd_uri_str ())
856 gcc_assert (strlen (pwd) > 0);
857 gcc_assert (pwd[strlen (pwd) - 1] == '/');
858 artifact_loc_obj->set ("uri", new json::string (pwd));
859 free (pwd);
862 return artifact_loc_obj;
865 /* Get the column number within EXPLOC. */
868 sarif_builder::get_sarif_column (expanded_location exploc) const
870 cpp_char_column_policy policy (m_tabstop, cpp_wcwidth);
871 return location_compute_display_column (exploc, policy);
874 /* Make a region object (SARIF v2.1.0 section 3.30) for LOC,
875 or return NULL. */
877 json::object *
878 sarif_builder::maybe_make_region_object (location_t loc) const
880 location_t caret_loc = get_pure_location (loc);
882 if (caret_loc <= BUILTINS_LOCATION)
883 return NULL;
885 location_t start_loc = get_start (loc);
886 location_t finish_loc = get_finish (loc);
888 expanded_location exploc_caret = expand_location (caret_loc);
889 expanded_location exploc_start = expand_location (start_loc);
890 expanded_location exploc_finish = expand_location (finish_loc);
892 if (exploc_start.file !=exploc_caret.file)
893 return NULL;
894 if (exploc_finish.file !=exploc_caret.file)
895 return NULL;
897 json::object *region_obj = new json::object ();
899 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
900 region_obj->set ("startLine", new json::integer_number (exploc_start.line));
902 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
903 region_obj->set ("startColumn",
904 new json::integer_number (get_sarif_column (exploc_start)));
906 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
907 if (exploc_finish.line != exploc_start.line)
908 region_obj->set ("endLine", new json::integer_number (exploc_finish.line));
910 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
911 This expresses the column immediately beyond the range. */
913 int next_column = sarif_builder::get_sarif_column (exploc_finish) + 1;
914 region_obj->set ("endColumn", new json::integer_number (next_column));
917 return region_obj;
920 /* Make a region object (SARIF v2.1.0 section 3.30) for the "contextRegion"
921 property (SARIF v2.1.0 section 3.29.5) of a physicalLocation.
923 This is similar to maybe_make_region_object, but ignores column numbers,
924 covering the line(s) as a whole, and including a "snippet" property
925 embedding those source lines, making it easier for consumers to show
926 the pertinent source. */
928 json::object *
929 sarif_builder::maybe_make_region_object_for_context (location_t loc) const
931 location_t caret_loc = get_pure_location (loc);
933 if (caret_loc <= BUILTINS_LOCATION)
934 return NULL;
936 location_t start_loc = get_start (loc);
937 location_t finish_loc = get_finish (loc);
939 expanded_location exploc_caret = expand_location (caret_loc);
940 expanded_location exploc_start = expand_location (start_loc);
941 expanded_location exploc_finish = expand_location (finish_loc);
943 if (exploc_start.file !=exploc_caret.file)
944 return NULL;
945 if (exploc_finish.file !=exploc_caret.file)
946 return NULL;
948 json::object *region_obj = new json::object ();
950 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
951 region_obj->set ("startLine", new json::integer_number (exploc_start.line));
953 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
954 if (exploc_finish.line != exploc_start.line)
955 region_obj->set ("endLine", new json::integer_number (exploc_finish.line));
957 /* "snippet" property (SARIF v2.1.0 section 3.30.13). */
958 if (json::object *artifact_content_obj
959 = maybe_make_artifact_content_object (exploc_start.file,
960 exploc_start.line,
961 exploc_finish.line))
962 region_obj->set ("snippet", artifact_content_obj);
964 return region_obj;
967 /* Make a region object (SARIF v2.1.0 section 3.30) for the deletion region
968 of HINT (as per SARIF v2.1.0 section 3.57.3). */
970 json::object *
971 sarif_builder::make_region_object_for_hint (const fixit_hint &hint) const
973 location_t start_loc = hint.get_start_loc ();
974 location_t next_loc = hint.get_next_loc ();
976 expanded_location exploc_start = expand_location (start_loc);
977 expanded_location exploc_next = expand_location (next_loc);
979 json::object *region_obj = new json::object ();
981 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
982 region_obj->set ("startLine", new json::integer_number (exploc_start.line));
984 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
985 int start_col = get_sarif_column (exploc_start);
986 region_obj->set ("startColumn",
987 new json::integer_number (start_col));
989 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
990 if (exploc_next.line != exploc_start.line)
991 region_obj->set ("endLine", new json::integer_number (exploc_next.line));
993 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
994 This expresses the column immediately beyond the range. */
995 int next_col = get_sarif_column (exploc_next);
996 region_obj->set ("endColumn", new json::integer_number (next_col));
998 return region_obj;
1001 /* Attempt to get a string for a logicalLocation's "kind" property
1002 (SARIF v2.1.0 section 3.33.7).
1003 Return NULL if unknown. */
1005 static const char *
1006 maybe_get_sarif_kind (enum logical_location_kind kind)
1008 switch (kind)
1010 default:
1011 gcc_unreachable ();
1012 case LOGICAL_LOCATION_KIND_UNKNOWN:
1013 return NULL;
1015 case LOGICAL_LOCATION_KIND_FUNCTION:
1016 return "function";
1017 case LOGICAL_LOCATION_KIND_MEMBER:
1018 return "member";
1019 case LOGICAL_LOCATION_KIND_MODULE:
1020 return "module";
1021 case LOGICAL_LOCATION_KIND_NAMESPACE:
1022 return "namespace";
1023 case LOGICAL_LOCATION_KIND_TYPE:
1024 return "type";
1025 case LOGICAL_LOCATION_KIND_RETURN_TYPE:
1026 return "returnType";
1027 case LOGICAL_LOCATION_KIND_PARAMETER:
1028 return "parameter";
1029 case LOGICAL_LOCATION_KIND_VARIABLE:
1030 return "variable";
1034 /* Make a logicalLocation object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC,
1035 or return NULL. */
1037 json::object *
1038 sarif_builder::
1039 make_logical_location_object (const logical_location &logical_loc) const
1041 json::object *logical_loc_obj = new json::object ();
1043 /* "name" property (SARIF v2.1.0 section 3.33.4). */
1044 if (const char *short_name = logical_loc.get_short_name ())
1045 logical_loc_obj->set ("name", new json::string (short_name));
1047 /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
1048 if (const char *name_with_scope = logical_loc.get_name_with_scope ())
1049 logical_loc_obj->set ("fullyQualifiedName",
1050 new json::string (name_with_scope));
1052 /* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
1053 if (const char *internal_name = logical_loc.get_internal_name ())
1054 logical_loc_obj->set ("decoratedName", new json::string (internal_name));
1056 /* "kind" property (SARIF v2.1.0 section 3.33.7). */
1057 enum logical_location_kind kind = logical_loc.get_kind ();
1058 if (const char *sarif_kind_str = maybe_get_sarif_kind (kind))
1059 logical_loc_obj->set ("kind", new json::string (sarif_kind_str));
1061 return logical_loc_obj;
1064 /* Make a codeFlow object (SARIF v2.1.0 section 3.36) for PATH. */
1066 json::object *
1067 sarif_builder::make_code_flow_object (const diagnostic_path &path)
1069 json::object *code_flow_obj = new json::object ();
1071 /* "threadFlows" property (SARIF v2.1.0 section 3.36.3).
1072 Currently we only support one thread per result. */
1073 json::array *thread_flows_arr = new json::array ();
1074 json::object *thread_flow_obj = make_thread_flow_object (path);
1075 thread_flows_arr->append (thread_flow_obj);
1076 code_flow_obj->set ("threadFlows", thread_flows_arr);
1078 return code_flow_obj;
1081 /* Make a threadFlow object (SARIF v2.1.0 section 3.37) for PATH. */
1083 json::object *
1084 sarif_builder::make_thread_flow_object (const diagnostic_path &path)
1086 json::object *thread_flow_obj = new json::object ();
1088 /* "locations" property (SARIF v2.1.0 section 3.37.6). */
1089 json::array *locations_arr = new json::array ();
1090 for (unsigned i = 0; i < path.num_events (); i++)
1092 const diagnostic_event &event = path.get_event (i);
1093 json::object *thread_flow_loc_obj
1094 = make_thread_flow_location_object (event);
1095 locations_arr->append (thread_flow_loc_obj);
1097 thread_flow_obj->set ("locations", locations_arr);
1099 return thread_flow_obj;
1102 /* Make a threadFlowLocation object (SARIF v2.1.0 section 3.38) for EVENT. */
1104 json::object *
1105 sarif_builder::make_thread_flow_location_object (const diagnostic_event &ev)
1107 json::object *thread_flow_loc_obj = new json::object ();
1109 /* "location" property (SARIF v2.1.0 section 3.38.3). */
1110 json::object *location_obj = make_location_object (ev);
1111 thread_flow_loc_obj->set ("location", location_obj);
1113 /* "kinds" property (SARIF v2.1.0 section 3.38.8). */
1114 diagnostic_event::meaning m = ev.get_meaning ();
1115 if (json::array *kinds_arr = maybe_make_kinds_array (m))
1116 thread_flow_loc_obj->set ("kinds", kinds_arr);
1118 /* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */
1119 thread_flow_loc_obj->set ("nestingLevel",
1120 new json::integer_number (ev.get_stack_depth ()));
1122 /* It might be nice to eventually implement the following for -fanalyzer:
1123 - the "stack" property (SARIF v2.1.0 section 3.38.5)
1124 - the "state" property (SARIF v2.1.0 section 3.38.9)
1125 - the "importance" property (SARIF v2.1.0 section 3.38.13). */
1127 return thread_flow_loc_obj;
1130 /* If M has any known meaning, make a json array suitable for the "kinds"
1131 property of a threadFlowLocation object (SARIF v2.1.0 section 3.38.8).
1133 Otherwise, return NULL. */
1135 json::array *
1136 sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const
1138 if (m.m_verb == diagnostic_event::VERB_unknown
1139 && m.m_noun == diagnostic_event::NOUN_unknown
1140 && m.m_property == diagnostic_event::PROPERTY_unknown)
1141 return NULL;
1143 json::array *kinds_arr = new json::array ();
1144 if (const char *verb_str
1145 = diagnostic_event::meaning::maybe_get_verb_str (m.m_verb))
1146 kinds_arr->append (new json::string (verb_str));
1147 if (const char *noun_str
1148 = diagnostic_event::meaning::maybe_get_noun_str (m.m_noun))
1149 kinds_arr->append (new json::string (noun_str));
1150 if (const char *property_str
1151 = diagnostic_event::meaning::maybe_get_property_str (m.m_property))
1152 kinds_arr->append (new json::string (property_str));
1153 return kinds_arr;
1156 /* Make a message object (SARIF v2.1.0 section 3.11) for MSG. */
1158 json::object *
1159 sarif_builder::make_message_object (const char *msg) const
1161 json::object *message_obj = new json::object ();
1163 /* "text" property (SARIF v2.1.0 section 3.11.8). */
1164 message_obj->set ("text", new json::string (msg));
1166 return message_obj;
1169 /* Make a message object (SARIF v2.1.0 section 3.11) for DIAGRAM.
1170 We emit the diagram as a code block within the Markdown part
1171 of the message. */
1173 json::object *
1174 sarif_builder::make_message_object_for_diagram (diagnostic_context *context,
1175 const diagnostic_diagram &diagram)
1177 json::object *message_obj = new json::object ();
1179 /* "text" property (SARIF v2.1.0 section 3.11.8). */
1180 message_obj->set ("text", new json::string (diagram.get_alt_text ()));
1182 char *saved_prefix = pp_take_prefix (context->printer);
1183 pp_set_prefix (context->printer, NULL);
1185 /* "To produce a code block in Markdown, simply indent every line of
1186 the block by at least 4 spaces or 1 tab."
1187 Here we use 4 spaces. */
1188 diagram.get_canvas ().print_to_pp (context->printer, " ");
1189 pp_set_prefix (context->printer, saved_prefix);
1191 /* "markdown" property (SARIF v2.1.0 section 3.11.9). */
1192 message_obj->set ("markdown",
1193 new json::string (pp_formatted_text (context->printer)));
1195 pp_clear_output_area (context->printer);
1197 return message_obj;
1200 /* Make a multiformatMessageString object (SARIF v2.1.0 section 3.12)
1201 for MSG. */
1203 json::object *
1204 sarif_builder::make_multiformat_message_string (const char *msg) const
1206 json::object *message_obj = new json::object ();
1208 /* "text" property (SARIF v2.1.0 section 3.12.3). */
1209 message_obj->set ("text", new json::string (msg));
1211 return message_obj;
1214 #define SARIF_SCHEMA "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"
1215 #define SARIF_VERSION "2.1.0"
1217 /* Make a top-level sarifLog object (SARIF v2.1.0 section 3.13).
1218 Take ownership of INVOCATION_OBJ and RESULTS. */
1220 json::object *
1221 sarif_builder::make_top_level_object (sarif_invocation *invocation_obj,
1222 json::array *results)
1224 json::object *log_obj = new json::object ();
1226 /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */
1227 log_obj->set ("$schema", new json::string (SARIF_SCHEMA));
1229 /* "version" property (SARIF v2.1.0 section 3.13.2). */
1230 log_obj->set ("version", new json::string (SARIF_VERSION));
1232 /* "runs" property (SARIF v2.1.0 section 3.13.4). */
1233 json::array *run_arr = new json::array ();
1234 json::object *run_obj = make_run_object (invocation_obj, results);
1235 run_arr->append (run_obj);
1236 log_obj->set ("runs", run_arr);
1238 return log_obj;
1241 /* Make a run object (SARIF v2.1.0 section 3.14).
1242 Take ownership of INVOCATION_OBJ and RESULTS. */
1244 json::object *
1245 sarif_builder::make_run_object (sarif_invocation *invocation_obj,
1246 json::array *results)
1248 json::object *run_obj = new json::object ();
1250 /* "tool" property (SARIF v2.1.0 section 3.14.6). */
1251 json::object *tool_obj = make_tool_object ();
1252 run_obj->set ("tool", tool_obj);
1254 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1255 if (json::array *taxonomies_arr = maybe_make_taxonomies_array ())
1256 run_obj->set ("taxonomies", taxonomies_arr);
1258 /* "invocations" property (SARIF v2.1.0 section 3.14.11). */
1260 json::array *invocations_arr = new json::array ();
1261 invocations_arr->append (invocation_obj);
1262 run_obj->set ("invocations", invocations_arr);
1265 /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */
1266 if (m_seen_any_relative_paths)
1268 json::object *orig_uri_base_ids = new json::object ();
1269 run_obj->set ("originalUriBaseIds", orig_uri_base_ids);
1270 json::object *pwd_art_loc_obj = make_artifact_location_object_for_pwd ();
1271 orig_uri_base_ids->set (PWD_PROPERTY_NAME, pwd_art_loc_obj);
1274 /* "artifacts" property (SARIF v2.1.0 section 3.14.15). */
1275 json::array *artifacts_arr = new json::array ();
1276 for (auto iter : m_filenames)
1278 json::object *artifact_obj = make_artifact_object (iter);
1279 artifacts_arr->append (artifact_obj);
1281 run_obj->set ("artifacts", artifacts_arr);
1283 /* "results" property (SARIF v2.1.0 section 3.14.23). */
1284 run_obj->set ("results", results);
1286 return run_obj;
1289 /* Make a tool object (SARIF v2.1.0 section 3.18). */
1291 json::object *
1292 sarif_builder::make_tool_object () const
1294 json::object *tool_obj = new json::object ();
1296 /* "driver" property (SARIF v2.1.0 section 3.18.2). */
1297 json::object *driver_obj = make_driver_tool_component_object ();
1298 tool_obj->set ("driver", driver_obj);
1300 /* Report plugins via the "extensions" property
1301 (SARIF v2.1.0 section 3.18.3). */
1302 if (m_context->m_client_data_hooks)
1303 if (const client_version_info *vinfo
1304 = m_context->m_client_data_hooks->get_any_version_info ())
1306 class my_plugin_visitor : public client_version_info :: plugin_visitor
1308 public:
1309 void on_plugin (const diagnostic_client_plugin_info &p) final override
1311 /* Create a toolComponent object (SARIF v2.1.0 section 3.19)
1312 for the plugin. */
1313 json::object *plugin_obj = new json::object ();
1314 m_plugin_objs.safe_push (plugin_obj);
1316 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1317 if (const char *short_name = p.get_short_name ())
1318 plugin_obj->set ("name", new json::string (short_name));
1320 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1321 if (const char *full_name = p.get_full_name ())
1322 plugin_obj->set ("fullName", new json::string (full_name));
1324 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1325 if (const char *version = p.get_version ())
1326 plugin_obj->set ("version", new json::string (version));
1328 auto_vec <json::object *> m_plugin_objs;
1330 my_plugin_visitor v;
1331 vinfo->for_each_plugin (v);
1332 if (v.m_plugin_objs.length () > 0)
1334 json::array *extensions_arr = new json::array ();
1335 tool_obj->set ("extensions", extensions_arr);
1336 for (auto iter : v.m_plugin_objs)
1337 extensions_arr->append (iter);
1341 /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other
1342 "extensions" (see toplev.cc: print_version). */
1344 return tool_obj;
1347 /* Make a toolComponent object (SARIF v2.1.0 section 3.19) for what SARIF
1348 calls the "driver" (see SARIF v2.1.0 section 3.18.1). */
1350 json::object *
1351 sarif_builder::make_driver_tool_component_object () const
1353 json::object *driver_obj = new json::object ();
1355 if (m_context->m_client_data_hooks)
1356 if (const client_version_info *vinfo
1357 = m_context->m_client_data_hooks->get_any_version_info ())
1359 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1360 if (const char *name = vinfo->get_tool_name ())
1361 driver_obj->set ("name", new json::string (name));
1363 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1364 if (char *full_name = vinfo->maybe_make_full_name ())
1366 driver_obj->set ("fullName", new json::string (full_name));
1367 free (full_name);
1370 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1371 if (const char *version = vinfo->get_version_string ())
1372 driver_obj->set ("version", new json::string (version));
1374 /* "informationUri" property (SARIF v2.1.0 section 3.19.17). */
1375 if (char *version_url = vinfo->maybe_make_version_url ())
1377 driver_obj->set ("informationUri", new json::string (version_url));
1378 free (version_url);
1382 /* "rules" property (SARIF v2.1.0 section 3.19.23). */
1383 driver_obj->set ("rules", m_rules_arr);
1385 return driver_obj;
1388 /* If we've seen any CWE IDs, make an array for the "taxonomies" property
1389 (SARIF v2.1.0 section 3.14.8) of a run object, containting a singl
1390 toolComponent (3.19) as per 3.19.3, representing the CWE.
1392 Otherwise return NULL. */
1394 json::array *
1395 sarif_builder::maybe_make_taxonomies_array () const
1397 json::object *cwe_obj = maybe_make_cwe_taxonomy_object ();
1398 if (!cwe_obj)
1399 return NULL;
1401 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1402 json::array *taxonomies_arr = new json::array ();
1403 taxonomies_arr->append (cwe_obj);
1404 return taxonomies_arr;
1407 /* If we've seen any CWE IDs, make a toolComponent object
1408 (SARIF v2.1.0 section 3.19) representing the CWE taxonomy, as per 3.19.3.
1409 Populate the "taxa" property with all of the CWE IDs in m_cwe_id_set.
1411 Otherwise return NULL. */
1413 json::object *
1414 sarif_builder::maybe_make_cwe_taxonomy_object () const
1416 if (m_cwe_id_set.is_empty ())
1417 return NULL;
1419 json::object *taxonomy_obj = new json::object ();
1421 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1422 taxonomy_obj->set ("name", new json::string ("CWE"));
1424 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1425 taxonomy_obj->set ("version", new json::string ("4.7"));
1427 /* "organization" property (SARIF v2.1.0 section 3.19.18). */
1428 taxonomy_obj->set ("organization", new json::string ("MITRE"));
1430 /* "shortDescription" property (SARIF v2.1.0 section 3.19.19). */
1431 json::object *short_desc
1432 = make_multiformat_message_string ("The MITRE"
1433 " Common Weakness Enumeration");
1434 taxonomy_obj->set ("shortDescription", short_desc);
1436 /* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */
1437 json::array *taxa_arr = new json::array ();
1438 for (auto cwe_id : m_cwe_id_set)
1440 json::object *cwe_taxon
1441 = make_reporting_descriptor_object_for_cwe_id (cwe_id);
1442 taxa_arr->append (cwe_taxon);
1444 taxonomy_obj->set ("taxa", taxa_arr);
1446 return taxonomy_obj;
1449 /* Make an artifact object (SARIF v2.1.0 section 3.24). */
1451 json::object *
1452 sarif_builder::make_artifact_object (const char *filename)
1454 json::object *artifact_obj = new json::object ();
1456 /* "location" property (SARIF v2.1.0 section 3.24.2). */
1457 json::object *artifact_loc_obj = make_artifact_location_object (filename);
1458 artifact_obj->set ("location", artifact_loc_obj);
1460 /* "contents" property (SARIF v2.1.0 section 3.24.8). */
1461 if (json::object *artifact_content_obj
1462 = maybe_make_artifact_content_object (filename))
1463 artifact_obj->set ("contents", artifact_content_obj);
1465 /* "sourceLanguage" property (SARIF v2.1.0 section 3.24.10). */
1466 if (m_context->m_client_data_hooks)
1467 if (const char *source_lang
1468 = m_context->m_client_data_hooks->maybe_get_sarif_source_language
1469 (filename))
1470 artifact_obj->set ("sourceLanguage", new json::string (source_lang));
1472 return artifact_obj;
1475 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the
1476 full contents of FILENAME. */
1478 json::object *
1479 sarif_builder::maybe_make_artifact_content_object (const char *filename) const
1481 /* Let input.cc handle any charset conversion. */
1482 char_span utf8_content = get_source_file_content (filename);
1483 if (!utf8_content)
1484 return NULL;
1486 /* Don't add it if it's not valid UTF-8. */
1487 if (!cpp_valid_utf8_p(utf8_content.get_buffer (), utf8_content.length ()))
1488 return NULL;
1490 json::object *artifact_content_obj = new json::object ();
1491 artifact_content_obj->set ("text",
1492 new json::string (utf8_content.get_buffer (),
1493 utf8_content.length ()));
1494 return artifact_content_obj;
1497 /* Attempt to read the given range of lines from FILENAME; return
1498 a freshly-allocated 0-terminated buffer containing them, or NULL. */
1500 static char *
1501 get_source_lines (const char *filename,
1502 int start_line,
1503 int end_line)
1505 auto_vec<char> result;
1507 for (int line = start_line; line <= end_line; line++)
1509 char_span line_content = location_get_source_line (filename, line);
1510 if (!line_content.get_buffer ())
1511 return NULL;
1512 result.reserve (line_content.length () + 1);
1513 for (size_t i = 0; i < line_content.length (); i++)
1514 result.quick_push (line_content[i]);
1515 result.quick_push ('\n');
1517 result.safe_push ('\0');
1519 return xstrdup (result.address ());
1522 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the given
1523 run of lines within FILENAME (including the endpoints). */
1525 json::object *
1526 sarif_builder::maybe_make_artifact_content_object (const char *filename,
1527 int start_line,
1528 int end_line) const
1530 char *text_utf8 = get_source_lines (filename, start_line, end_line);
1532 if (!text_utf8)
1533 return NULL;
1535 /* Don't add it if it's not valid UTF-8. */
1536 if (!cpp_valid_utf8_p(text_utf8, strlen(text_utf8)))
1538 free (text_utf8);
1539 return NULL;
1542 json::object *artifact_content_obj = new json::object ();
1543 artifact_content_obj->set ("text", new json::string (text_utf8));
1544 free (text_utf8);
1546 return artifact_content_obj;
1549 /* Make a fix object (SARIF v2.1.0 section 3.55) for RICHLOC. */
1551 json::object *
1552 sarif_builder::make_fix_object (const rich_location &richloc)
1554 json::object *fix_obj = new json::object ();
1556 /* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */
1557 /* We assume that all fix-it hints in RICHLOC affect the same file. */
1558 json::array *artifact_change_arr = new json::array ();
1559 json::object *artifact_change_obj = make_artifact_change_object (richloc);
1560 artifact_change_arr->append (artifact_change_obj);
1561 fix_obj->set ("artifactChanges", artifact_change_arr);
1563 return fix_obj;
1566 /* Make an artifactChange object (SARIF v2.1.0 section 3.56) for RICHLOC. */
1568 json::object *
1569 sarif_builder::make_artifact_change_object (const rich_location &richloc)
1571 json::object *artifact_change_obj = new json::object ();
1573 /* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */
1574 json::object *artifact_location_obj
1575 = make_artifact_location_object (richloc.get_loc ());
1576 artifact_change_obj->set ("artifactLocation", artifact_location_obj);
1578 /* "replacements" property (SARIF v2.1.0 section 3.56.3). */
1579 json::array *replacement_arr = new json::array ();
1580 for (unsigned int i = 0; i < richloc.get_num_fixit_hints (); i++)
1582 const fixit_hint *hint = richloc.get_fixit_hint (i);
1583 json::object *replacement_obj = make_replacement_object (*hint);
1584 replacement_arr->append (replacement_obj);
1586 artifact_change_obj->set ("replacements", replacement_arr);
1588 return artifact_change_obj;
1591 /* Make a replacement object (SARIF v2.1.0 section 3.57) for HINT. */
1593 json::object *
1594 sarif_builder::make_replacement_object (const fixit_hint &hint) const
1596 json::object *replacement_obj = new json::object ();
1598 /* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */
1599 json::object *region_obj = make_region_object_for_hint (hint);
1600 replacement_obj->set ("deletedRegion", region_obj);
1602 /* "insertedContent" property (SARIF v2.1.0 section 3.57.4). */
1603 json::object *content_obj = make_artifact_content_object (hint.get_string ());
1604 replacement_obj->set ("insertedContent", content_obj);
1606 return replacement_obj;
1609 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for TEXT. */
1611 json::object *
1612 sarif_builder::make_artifact_content_object (const char *text) const
1614 json::object *content_obj = new json::object ();
1616 /* "text" property (SARIF v2.1.0 section 3.3.2). */
1617 content_obj->set ("text", new json::string (text));
1619 return content_obj;
1622 /* No-op implementation of "begin_diagnostic" for SARIF output. */
1624 static void
1625 sarif_begin_diagnostic (diagnostic_context *, diagnostic_info *)
1629 /* Implementation of "end_diagnostic" for SARIF output. */
1631 static void
1632 sarif_end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic,
1633 diagnostic_t orig_diag_kind)
1635 gcc_assert (the_builder);
1636 the_builder->end_diagnostic (context, diagnostic, orig_diag_kind);
1639 /* No-op implementation of "begin_group_cb" for SARIF output. */
1641 static void
1642 sarif_begin_group (diagnostic_context *)
1646 /* Implementation of "end_group_cb" for SARIF output. */
1648 static void
1649 sarif_end_group (diagnostic_context *)
1651 gcc_assert (the_builder);
1652 the_builder->end_group ();
1655 /* Flush the top-level array to OUTF. */
1657 static void
1658 sarif_flush_to_file (FILE *outf)
1660 gcc_assert (the_builder);
1661 the_builder->flush_to_file (outf);
1662 delete the_builder;
1663 the_builder = NULL;
1666 /* Callback for final cleanup for SARIF output to stderr. */
1668 static void
1669 sarif_stderr_final_cb (diagnostic_context *)
1671 gcc_assert (the_builder);
1672 sarif_flush_to_file (stderr);
1675 static char *sarif_output_base_file_name;
1677 /* Callback for final cleanup for SARIF output to a file. */
1679 static void
1680 sarif_file_final_cb (diagnostic_context *)
1682 char *filename = concat (sarif_output_base_file_name, ".sarif", NULL);
1683 FILE *outf = fopen (filename, "w");
1684 if (!outf)
1686 const char *errstr = xstrerror (errno);
1687 fnotice (stderr, "error: unable to open '%s' for writing: %s\n",
1688 filename, errstr);
1689 free (filename);
1690 return;
1692 gcc_assert (the_builder);
1693 sarif_flush_to_file (outf);
1694 fclose (outf);
1695 free (filename);
1698 /* Callback for diagnostic_context::ice_handler_cb for when an ICE
1699 occurs. */
1701 static void
1702 sarif_ice_handler (diagnostic_context *context)
1704 /* Attempt to ensure that a .sarif file is written out. */
1705 diagnostic_finish (context);
1707 /* Print a header for the remaining output to stderr, and
1708 return, attempting to print the usual ICE messages to
1709 stderr. Hopefully this will be helpful to the user in
1710 indicating what's gone wrong (also for DejaGnu, for pruning
1711 those messages). */
1712 fnotice (stderr, "Internal compiler error:\n");
1715 /* Callback for diagnostic_context::m_diagrams.m_emission_cb. */
1717 static void
1718 sarif_emit_diagram (diagnostic_context *context,
1719 const diagnostic_diagram &diagram)
1721 gcc_assert (the_builder);
1722 the_builder->emit_diagram (context, diagram);
1725 /* Populate CONTEXT in preparation for SARIF output (either to stderr, or
1726 to a file). */
1728 static void
1729 diagnostic_output_format_init_sarif (diagnostic_context *context)
1731 the_builder = new sarif_builder (context);
1733 /* Override callbacks. */
1734 context->begin_diagnostic = sarif_begin_diagnostic;
1735 context->end_diagnostic = sarif_end_diagnostic;
1736 context->begin_group_cb = sarif_begin_group;
1737 context->end_group_cb = sarif_end_group;
1738 context->print_path = NULL; /* handled in sarif_end_diagnostic. */
1739 context->ice_handler_cb = sarif_ice_handler;
1740 context->m_diagrams.m_emission_cb = sarif_emit_diagram;
1742 /* The metadata is handled in SARIF format, rather than as text. */
1743 context->show_cwe = false;
1744 context->show_rules = false;
1746 /* The option is handled in SARIF format, rather than as text. */
1747 context->show_option_requested = false;
1749 /* Don't colorize the text. */
1750 pp_show_color (context->printer) = false;
1753 /* Populate CONTEXT in preparation for SARIF output to stderr. */
1755 void
1756 diagnostic_output_format_init_sarif_stderr (diagnostic_context *context)
1758 diagnostic_output_format_init_sarif (context);
1759 context->final_cb = sarif_stderr_final_cb;
1762 /* Populate CONTEXT in preparation for SARIF output to a file named
1763 BASE_FILE_NAME.sarif. */
1765 void
1766 diagnostic_output_format_init_sarif_file (diagnostic_context *context,
1767 const char *base_file_name)
1769 diagnostic_output_format_init_sarif (context);
1770 context->final_cb = sarif_file_final_cb;
1771 sarif_output_base_file_name = xstrdup (base_file_name);