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
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
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/>. */
23 #define INCLUDE_VECTOR
25 #include "coretypes.h"
26 #include "diagnostic.h"
27 #include "diagnostic-metadata.h"
28 #include "diagnostic-path.h"
31 #include "logical-location.h"
32 #include "diagnostic-client-data-hooks.h"
33 #include "diagnostic-diagram.h"
34 #include "text-art/canvas.h"
35 #include "diagnostic-format-sarif.h"
39 /* Subclass of json::object for SARIF invocation objects
40 (SARIF v2.1.0 section 3.20). */
42 class sarif_invocation
: public sarif_object
46 : m_notifications_arr (new json::array ()),
50 void add_notification_for_ice (diagnostic_context
*context
,
51 diagnostic_info
*diagnostic
,
52 sarif_builder
*builder
);
53 void prepare_to_flush (diagnostic_context
*context
);
56 json::array
*m_notifications_arr
;
60 /* Subclass of sarif_object for SARIF result objects
61 (SARIF v2.1.0 section 3.27). */
63 class sarif_result
: public sarif_object
66 sarif_result () : m_related_locations_arr (NULL
) {}
69 on_nested_diagnostic (diagnostic_context
*context
,
70 diagnostic_info
*diagnostic
,
71 diagnostic_t orig_diag_kind
,
72 sarif_builder
*builder
);
73 void on_diagram (diagnostic_context
*context
,
74 const diagnostic_diagram
&diagram
,
75 sarif_builder
*builder
);
78 void add_related_location (json::object
*location_obj
);
80 json::array
*m_related_locations_arr
;
83 /* Subclass of sarif_object for SARIF notification objects
84 (SARIF v2.1.0 section 3.58).
86 This subclass is specifically for notifying when an
87 internal compiler error occurs. */
89 class sarif_ice_notification
: public sarif_object
92 sarif_ice_notification (diagnostic_context
*context
,
93 diagnostic_info
*diagnostic
,
94 sarif_builder
*builder
);
97 /* Subclass of sarif_object for SARIF threadFlow objects
98 (SARIF v2.1.0 section 3.37) for PATH. */
100 class sarif_thread_flow
: public sarif_object
103 sarif_thread_flow (const diagnostic_thread
&thread
);
105 void add_location (json::object
*thread_flow_loc_obj
)
107 m_locations_arr
->append (thread_flow_loc_obj
);
111 json::array
*m_locations_arr
;
114 /* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
115 and -fdiagnostics-format=sarif-file).
117 As diagnostics occur, we build "result" JSON objects, and
119 - which source files are referenced
120 - which warnings are emitted
121 - which CWEs are used
123 At the end of the compile, we use the above to build the full SARIF
124 object tree, adding the result objects to the correct place, and
125 creating objects for the various source files, warnings and CWEs
131 - diagnostic groups (see limitations below)
132 - logical locations (e.g. cfun)
135 - GCC supports one-deep nesting of diagnostics (via auto_diagnostic_group),
136 but we only capture location and message information from such nested
137 diagnostics (e.g. we ignore fix-it hints on them)
138 - doesn't yet capture command-line arguments: would be run.invocations
139 property (SARIF v2.1.0 section 3.14.11), as invocation objects
140 (SARIF v2.1.0 section 3.20), but we'd want to capture the arguments to
141 toplev::main, and the response files.
142 - doesn't capture escape_on_output_p
143 - doesn't capture secondary locations within a rich_location
144 (perhaps we should use the "relatedLocations" property: SARIF v2.1.0
146 - doesn't capture "artifact.encoding" property
147 (SARIF v2.1.0 section 3.24.9).
148 - doesn't capture hashes of the source files
149 ("artifact.hashes" property (SARIF v2.1.0 section 3.24.11).
150 - doesn't capture the "analysisTarget" property
151 (SARIF v2.1.0 section 3.27.13).
152 - doesn't capture labelled ranges
153 - doesn't capture -Werror cleanly
154 - doesn't capture inlining information (can SARIF handle this?)
155 - doesn't capture macro expansion information (can SARIF handle this?). */
160 sarif_builder (diagnostic_context
*context
);
162 void end_diagnostic (diagnostic_context
*context
, diagnostic_info
*diagnostic
,
163 diagnostic_t orig_diag_kind
);
164 void emit_diagram (diagnostic_context
*context
,
165 const diagnostic_diagram
&diagram
);
168 void flush_to_file (FILE *outf
);
170 json::array
*make_locations_arr (diagnostic_info
*diagnostic
);
171 json::object
*make_location_object (const rich_location
&rich_loc
,
172 const logical_location
*logical_loc
);
173 json::object
*make_message_object (const char *msg
) const;
175 make_message_object_for_diagram (diagnostic_context
*context
,
176 const diagnostic_diagram
&diagram
);
179 sarif_result
*make_result_object (diagnostic_context
*context
,
180 diagnostic_info
*diagnostic
,
181 diagnostic_t orig_diag_kind
);
182 void set_any_logical_locs_arr (json::object
*location_obj
,
183 const logical_location
*logical_loc
);
184 json::object
*make_location_object (const diagnostic_event
&event
);
186 make_logical_location_object (const logical_location
&logical_loc
) const;
187 json::object
*make_code_flow_object (const diagnostic_path
&path
);
189 make_thread_flow_location_object (const diagnostic_event
&event
,
191 json::array
*maybe_make_kinds_array (diagnostic_event::meaning m
) const;
192 json::object
*maybe_make_physical_location_object (location_t loc
);
193 json::object
*make_artifact_location_object (location_t loc
);
194 json::object
*make_artifact_location_object (const char *filename
);
195 json::object
*make_artifact_location_object_for_pwd () const;
196 json::object
*maybe_make_region_object (location_t loc
) const;
197 json::object
*maybe_make_region_object_for_context (location_t loc
) const;
198 json::object
*make_region_object_for_hint (const fixit_hint
&hint
) const;
199 json::object
*make_multiformat_message_string (const char *msg
) const;
200 json::object
*make_top_level_object (sarif_invocation
*invocation_obj
,
201 json::array
*results
);
202 json::object
*make_run_object (sarif_invocation
*invocation_obj
,
203 json::array
*results
);
204 json::object
*make_tool_object () const;
205 json::object
*make_driver_tool_component_object () const;
206 json::array
*maybe_make_taxonomies_array () const;
207 json::object
*maybe_make_cwe_taxonomy_object () const;
208 json::object
*make_tool_component_reference_object_for_cwe () const;
210 make_reporting_descriptor_object_for_warning (diagnostic_context
*context
,
211 diagnostic_info
*diagnostic
,
212 diagnostic_t orig_diag_kind
,
213 const char *option_text
);
214 json::object
*make_reporting_descriptor_object_for_cwe_id (int cwe_id
) const;
216 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id
);
217 json::object
*make_artifact_object (const char *filename
);
218 char *get_source_lines (const char *filename
,
221 json::object
*maybe_make_artifact_content_object (const char *filename
) const;
222 json::object
*maybe_make_artifact_content_object (const char *filename
,
225 json::object
*make_fix_object (const rich_location
&rich_loc
);
226 json::object
*make_artifact_change_object (const rich_location
&richloc
);
227 json::object
*make_replacement_object (const fixit_hint
&hint
) const;
228 json::object
*make_artifact_content_object (const char *text
) const;
229 int get_sarif_column (expanded_location exploc
) const;
231 diagnostic_context
*m_context
;
233 /* The JSON object for the invocation object. */
234 sarif_invocation
*m_invocation_obj
;
236 /* The JSON array of pending diagnostics. */
237 json::array
*m_results_array
;
239 /* The JSON object for the result object (if any) in the current
241 sarif_result
*m_cur_group_result
;
243 hash_set
<const char *> m_filenames
;
244 bool m_seen_any_relative_paths
;
245 hash_set
<free_string_hash
> m_rule_id_set
;
246 json::array
*m_rules_arr
;
248 /* The set of all CWE IDs we've seen, if any. */
249 hash_set
<int_hash
<int, 0, 1> > m_cwe_id_set
;
254 /* class sarif_object : public json::object. */
257 sarif_object::get_or_create_properties ()
259 json::value
*properties_val
= get ("properties");
262 if (properties_val
->get_kind () == json::JSON_OBJECT
)
263 return *static_cast <sarif_property_bag
*> (properties_val
);
266 sarif_property_bag
*bag
= new sarif_property_bag ();
267 set ("properties", bag
);
271 /* class sarif_invocation : public sarif_object. */
273 /* Handle an internal compiler error DIAGNOSTIC occurring on CONTEXT.
274 Add an object representing the ICE to the notifications array. */
277 sarif_invocation::add_notification_for_ice (diagnostic_context
*context
,
278 diagnostic_info
*diagnostic
,
279 sarif_builder
*builder
)
283 sarif_ice_notification
*notification_obj
284 = new sarif_ice_notification (context
, diagnostic
, builder
);
285 m_notifications_arr
->append (notification_obj
);
289 sarif_invocation::prepare_to_flush (diagnostic_context
*context
)
291 /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */
292 set_bool ("executionSuccessful", m_success
);
294 /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */
295 set ("toolExecutionNotifications", m_notifications_arr
);
297 /* Call client hook, allowing it to create a custom property bag for
298 this object (SARIF v2.1.0 section 3.8) e.g. for recording time vars. */
299 if (auto client_data_hooks
= context
->get_client_data_hooks ())
300 client_data_hooks
->add_sarif_invocation_properties (*this);
303 /* class sarif_result : public sarif_object. */
305 /* Handle secondary diagnostics that occur within a diagnostic group.
306 The closest SARIF seems to have to nested diagnostics is the
307 "relatedLocations" property of result objects (SARIF v2.1.0 section 3.27.22),
308 so we lazily set this property and populate the array if and when
309 secondary diagnostics occur (such as notes to a warning). */
312 sarif_result::on_nested_diagnostic (diagnostic_context
*context
,
313 diagnostic_info
*diagnostic
,
314 diagnostic_t
/*orig_diag_kind*/,
315 sarif_builder
*builder
)
317 /* We don't yet generate meaningful logical locations for notes;
318 sometimes these will related to current_function_decl, but
320 json::object
*location_obj
321 = builder
->make_location_object (*diagnostic
->richloc
, NULL
);
322 json::object
*message_obj
323 = builder
->make_message_object (pp_formatted_text (context
->printer
));
324 pp_clear_output_area (context
->printer
);
325 location_obj
->set ("message", message_obj
);
327 add_related_location (location_obj
);
330 /* Handle diagrams that occur within a diagnostic group.
331 The closest thing in SARIF seems to be to add a location to the
332 "releatedLocations" property (SARIF v2.1.0 section 3.27.22),
333 and to put the diagram into the "message" property of that location
334 (SARIF v2.1.0 section 3.28.5). */
337 sarif_result::on_diagram (diagnostic_context
*context
,
338 const diagnostic_diagram
&diagram
,
339 sarif_builder
*builder
)
341 json::object
*location_obj
= new json::object ();
342 json::object
*message_obj
343 = builder
->make_message_object_for_diagram (context
, diagram
);
344 location_obj
->set ("message", message_obj
);
346 add_related_location (location_obj
);
349 /* Add LOCATION_OBJ to this result's "relatedLocations" array,
350 creating it if it doesn't yet exist. */
353 sarif_result::add_related_location (json::object
*location_obj
)
355 if (!m_related_locations_arr
)
357 m_related_locations_arr
= new json::array ();
358 set ("relatedLocations", m_related_locations_arr
);
360 m_related_locations_arr
->append (location_obj
);
363 /* class sarif_ice_notification : public sarif_object. */
365 /* sarif_ice_notification's ctor.
366 DIAGNOSTIC is an internal compiler error. */
368 sarif_ice_notification::sarif_ice_notification (diagnostic_context
*context
,
369 diagnostic_info
*diagnostic
,
370 sarif_builder
*builder
)
372 /* "locations" property (SARIF v2.1.0 section 3.58.4). */
373 json::array
*locations_arr
= builder
->make_locations_arr (diagnostic
);
374 set ("locations", locations_arr
);
376 /* "message" property (SARIF v2.1.0 section 3.85.5). */
377 json::object
*message_obj
378 = builder
->make_message_object (pp_formatted_text (context
->printer
));
379 pp_clear_output_area (context
->printer
);
380 set ("message", message_obj
);
382 /* "level" property (SARIF v2.1.0 section 3.58.6). */
383 set_string ("level", "error");
386 /* class sarif_thread_flow : public sarif_object. */
388 sarif_thread_flow::sarif_thread_flow (const diagnostic_thread
&thread
)
390 /* "id" property (SARIF v2.1.0 section 3.37.2). */
391 label_text
name (thread
.get_name (false));
392 set_string ("id", name
.get ());
394 /* "locations" property (SARIF v2.1.0 section 3.37.6). */
395 m_locations_arr
= new json::array ();
396 set ("locations", m_locations_arr
);
399 /* class sarif_builder. */
401 /* sarif_builder's ctor. */
403 sarif_builder::sarif_builder (diagnostic_context
*context
)
404 : m_context (context
),
405 m_invocation_obj (new sarif_invocation ()),
406 m_results_array (new json::array ()),
407 m_cur_group_result (NULL
),
408 m_seen_any_relative_paths (false),
410 m_rules_arr (new json::array ()),
411 m_tabstop (context
->m_tabstop
)
415 /* Implementation of "end_diagnostic" for SARIF output. */
418 sarif_builder::end_diagnostic (diagnostic_context
*context
,
419 diagnostic_info
*diagnostic
,
420 diagnostic_t orig_diag_kind
)
422 if (diagnostic
->kind
== DK_ICE
|| diagnostic
->kind
== DK_ICE_NOBT
)
424 m_invocation_obj
->add_notification_for_ice (context
, diagnostic
, this);
428 if (m_cur_group_result
)
429 /* Nested diagnostic. */
430 m_cur_group_result
->on_nested_diagnostic (context
,
436 /* Top-level diagnostic. */
437 sarif_result
*result_obj
438 = make_result_object (context
, diagnostic
, orig_diag_kind
);
439 m_results_array
->append (result_obj
);
440 m_cur_group_result
= result_obj
;
444 /* Implementation of diagnostic_context::m_diagrams.m_emission_cb
448 sarif_builder::emit_diagram (diagnostic_context
*context
,
449 const diagnostic_diagram
&diagram
)
451 /* We must be within the emission of a top-level diagnostic. */
452 gcc_assert (m_cur_group_result
);
453 m_cur_group_result
->on_diagram (context
, diagram
, this);
456 /* Implementation of "end_group_cb" for SARIF output. */
459 sarif_builder::end_group ()
461 m_cur_group_result
= NULL
;
464 /* Create a top-level object, and add it to all the results
465 (and other entities) we've seen so far.
467 Flush it all to OUTF. */
470 sarif_builder::flush_to_file (FILE *outf
)
472 m_invocation_obj
->prepare_to_flush (m_context
);
473 json::object
*top
= make_top_level_object (m_invocation_obj
, m_results_array
);
475 m_invocation_obj
= NULL
;
476 m_results_array
= NULL
;
477 fprintf (outf
, "\n");
481 /* Attempt to convert DIAG_KIND to a suitable value for the "level"
482 property (SARIF v2.1.0 section 3.27.10).
484 Return NULL if there isn't one. */
487 maybe_get_sarif_level (diagnostic_t diag_kind
)
503 /* Make a string for DIAG_KIND suitable for use a ruleId
504 (SARIF v2.1.0 section 3.27.5) as a fallback for when we don't
505 have anything better to use. */
508 make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind
)
510 static const char *const diagnostic_kind_text
[] = {
511 #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
512 #include "diagnostic.def"
513 #undef DEFINE_DIAGNOSTIC_KIND
516 /* Lose the trailing ": ". */
517 const char *kind_text
= diagnostic_kind_text
[diag_kind
];
518 size_t len
= strlen (kind_text
);
519 gcc_assert (len
> 2);
520 gcc_assert (kind_text
[len
- 2] == ':');
521 gcc_assert (kind_text
[len
- 1] == ' ');
522 char *rstrip
= xstrdup (kind_text
);
523 rstrip
[len
- 2] = '\0';
527 /* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */
530 sarif_builder::make_result_object (diagnostic_context
*context
,
531 diagnostic_info
*diagnostic
,
532 diagnostic_t orig_diag_kind
)
534 sarif_result
*result_obj
= new sarif_result ();
536 /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
537 /* Ideally we'd have an option_name for these. */
538 if (char *option_text
539 = context
->make_option_name (diagnostic
->option_index
,
540 orig_diag_kind
, diagnostic
->kind
))
542 /* Lazily create reportingDescriptor objects for and add to m_rules_arr.
543 Set ruleId referencing them. */
544 result_obj
->set_string ("ruleId", option_text
);
545 if (m_rule_id_set
.contains (option_text
))
549 /* This is the first time we've seen this ruleId. */
550 /* Add to set, taking ownership. */
551 m_rule_id_set
.add (option_text
);
553 json::object
*reporting_desc_obj
554 = make_reporting_descriptor_object_for_warning (context
,
558 m_rules_arr
->append (reporting_desc_obj
);
563 /* Otherwise, we have an "error" or a stray "note"; use the
564 diagnostic kind as the ruleId, so that the result object at least
566 We don't bother creating reportingDescriptor objects for these. */
567 char *rule_id
= make_rule_id_for_diagnostic_kind (orig_diag_kind
);
568 result_obj
->set_string ("ruleId", rule_id
);
572 /* "taxa" property (SARIF v2.1.0 section 3.27.8). */
573 if (diagnostic
->metadata
)
574 if (int cwe_id
= diagnostic
->metadata
->get_cwe ())
576 json::array
*taxa_arr
= new json::array ();
577 json::object
*cwe_id_obj
578 = make_reporting_descriptor_reference_object_for_cwe_id (cwe_id
);
579 taxa_arr
->append (cwe_id_obj
);
580 result_obj
->set ("taxa", taxa_arr
);
583 /* "level" property (SARIF v2.1.0 section 3.27.10). */
584 if (const char *sarif_level
= maybe_get_sarif_level (diagnostic
->kind
))
585 result_obj
->set_string ("level", sarif_level
);
587 /* "message" property (SARIF v2.1.0 section 3.27.11). */
588 json::object
*message_obj
589 = make_message_object (pp_formatted_text (context
->printer
));
590 pp_clear_output_area (context
->printer
);
591 result_obj
->set ("message", message_obj
);
593 /* "locations" property (SARIF v2.1.0 section 3.27.12). */
594 json::array
*locations_arr
= make_locations_arr (diagnostic
);
595 result_obj
->set ("locations", locations_arr
);
597 /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
598 if (const diagnostic_path
*path
= diagnostic
->richloc
->get_path ())
600 json::array
*code_flows_arr
= new json::array ();
601 json::object
*code_flow_obj
= make_code_flow_object (*path
);
602 code_flows_arr
->append (code_flow_obj
);
603 result_obj
->set ("codeFlows", code_flows_arr
);
606 /* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is
607 set up later, if any nested diagnostics occur within this diagnostic
610 /* "fixes" property (SARIF v2.1.0 section 3.27.30). */
611 const rich_location
*richloc
= diagnostic
->richloc
;
612 if (richloc
->get_num_fixit_hints ())
614 json::array
*fix_arr
= new json::array ();
615 json::object
*fix_obj
= make_fix_object (*richloc
);
616 fix_arr
->append (fix_obj
);
617 result_obj
->set ("fixes", fix_arr
);
623 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
624 for a GCC warning. */
628 make_reporting_descriptor_object_for_warning (diagnostic_context
*context
,
629 diagnostic_info
*diagnostic
,
630 diagnostic_t
/*orig_diag_kind*/,
631 const char *option_text
)
633 json::object
*reporting_desc
= new json::object ();
635 /* "id" property (SARIF v2.1.0 section 3.49.3). */
636 reporting_desc
->set_string ("id", option_text
);
638 /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since
639 it seems redundant compared to "id". */
641 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
642 if (char *option_url
= context
->make_option_url (diagnostic
->option_index
))
644 reporting_desc
->set_string ("helpUri", option_url
);
648 return reporting_desc
;
651 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
652 for CWE_ID, for use within the CWE taxa array. */
655 sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id
) const
657 json::object
*reporting_desc
= new json::object ();
659 /* "id" property (SARIF v2.1.0 section 3.49.3). */
662 pp_printf (&pp
, "%i", cwe_id
);
663 reporting_desc
->set_string ("id", pp_formatted_text (&pp
));
666 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
668 char *url
= get_cwe_url (cwe_id
);
669 reporting_desc
->set_string ("helpUri", url
);
673 return reporting_desc
;
676 /* Make a reportingDescriptorReference object (SARIF v2.1.0 section 3.52)
677 referencing CWE_ID, for use within a result object.
678 Also, add CWE_ID to m_cwe_id_set. */
682 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id
)
684 json::object
*desc_ref_obj
= new json::object ();
686 /* "id" property (SARIF v2.1.0 section 3.52.4). */
689 pp_printf (&pp
, "%i", cwe_id
);
690 desc_ref_obj
->set_string ("id", pp_formatted_text (&pp
));
693 /* "toolComponent" property (SARIF v2.1.0 section 3.52.7). */
694 json::object
*comp_ref_obj
= make_tool_component_reference_object_for_cwe ();
695 desc_ref_obj
->set ("toolComponent", comp_ref_obj
);
697 /* Add CWE_ID to our set. */
698 gcc_assert (cwe_id
> 0);
699 m_cwe_id_set
.add (cwe_id
);
704 /* Make a toolComponentReference object (SARIF v2.1.0 section 3.54) that
705 references the CWE taxonomy. */
709 make_tool_component_reference_object_for_cwe () const
711 json::object
*comp_ref_obj
= new json::object ();
713 /* "name" property (SARIF v2.1.0 section 3.54.3). */
714 comp_ref_obj
->set_string ("name", "cwe");
719 /* Make an array suitable for use as the "locations" property of:
720 - a "result" object (SARIF v2.1.0 section 3.27.12), or
721 - a "notification" object (SARIF v2.1.0 section 3.58.4). */
724 sarif_builder::make_locations_arr (diagnostic_info
*diagnostic
)
726 json::array
*locations_arr
= new json::array ();
727 const logical_location
*logical_loc
= NULL
;
728 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
729 logical_loc
= client_data_hooks
->get_current_logical_location ();
731 json::object
*location_obj
732 = make_location_object (*diagnostic
->richloc
, logical_loc
);
733 locations_arr
->append (location_obj
);
734 return locations_arr
;
737 /* If LOGICAL_LOC is non-NULL, use it to create a "logicalLocations" property
738 within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */
742 set_any_logical_locs_arr (json::object
*location_obj
,
743 const logical_location
*logical_loc
)
747 json::object
*logical_loc_obj
= make_logical_location_object (*logical_loc
);
748 json::array
*location_locs_arr
= new json::array ();
749 location_locs_arr
->append (logical_loc_obj
);
750 location_obj
->set ("logicalLocations", location_locs_arr
);
753 /* Make a location object (SARIF v2.1.0 section 3.28) for RICH_LOC
757 sarif_builder::make_location_object (const rich_location
&rich_loc
,
758 const logical_location
*logical_loc
)
760 json::object
*location_obj
= new json::object ();
762 /* Get primary loc from RICH_LOC. */
763 location_t loc
= rich_loc
.get_loc ();
765 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
766 if (json::object
*phs_loc_obj
= maybe_make_physical_location_object (loc
))
767 location_obj
->set ("physicalLocation", phs_loc_obj
);
769 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
770 set_any_logical_locs_arr (location_obj
, logical_loc
);
775 /* Make a location object (SARIF v2.1.0 section 3.28) for EVENT
776 within a diagnostic_path. */
779 sarif_builder::make_location_object (const diagnostic_event
&event
)
781 json::object
*location_obj
= new json::object ();
783 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
784 location_t loc
= event
.get_location ();
785 if (json::object
*phs_loc_obj
= maybe_make_physical_location_object (loc
))
786 location_obj
->set ("physicalLocation", phs_loc_obj
);
788 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
789 const logical_location
*logical_loc
= event
.get_logical_location ();
790 set_any_logical_locs_arr (location_obj
, logical_loc
);
792 /* "message" property (SARIF v2.1.0 section 3.28.5). */
793 label_text ev_desc
= event
.get_desc (false);
794 json::object
*message_obj
= make_message_object (ev_desc
.get ());
795 location_obj
->set ("message", message_obj
);
800 /* Make a physicalLocation object (SARIF v2.1.0 section 3.29) for LOC,
802 Add any filename to the m_artifacts. */
805 sarif_builder::maybe_make_physical_location_object (location_t loc
)
807 if (loc
<= BUILTINS_LOCATION
|| LOCATION_FILE (loc
) == NULL
)
810 json::object
*phys_loc_obj
= new json::object ();
812 /* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */
813 json::object
*artifact_loc_obj
= make_artifact_location_object (loc
);
814 phys_loc_obj
->set ("artifactLocation", artifact_loc_obj
);
815 m_filenames
.add (LOCATION_FILE (loc
));
817 /* "region" property (SARIF v2.1.0 section 3.29.4). */
818 if (json::object
*region_obj
= maybe_make_region_object (loc
))
819 phys_loc_obj
->set ("region", region_obj
);
821 /* "contextRegion" property (SARIF v2.1.0 section 3.29.5). */
822 if (json::object
*context_region_obj
823 = maybe_make_region_object_for_context (loc
))
824 phys_loc_obj
->set ("contextRegion", context_region_obj
);
826 /* Instead, we add artifacts to the run as a whole,
827 with artifact.contents.
828 Could do both, though. */
833 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for LOC,
837 sarif_builder::make_artifact_location_object (location_t loc
)
839 return make_artifact_location_object (LOCATION_FILE (loc
));
842 /* The ID value for use in "uriBaseId" properties (SARIF v2.1.0 section 3.4.4)
843 for when we need to express paths relative to PWD. */
845 #define PWD_PROPERTY_NAME ("PWD")
847 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for FILENAME,
851 sarif_builder::make_artifact_location_object (const char *filename
)
853 json::object
*artifact_loc_obj
= new json::object ();
855 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
856 artifact_loc_obj
->set_string ("uri", filename
);
858 if (filename
[0] != '/')
860 /* If we have a relative path, set the "uriBaseId" property
861 (SARIF v2.1.0 section 3.4.4). */
862 artifact_loc_obj
->set_string ("uriBaseId", PWD_PROPERTY_NAME
);
863 m_seen_any_relative_paths
= true;
866 return artifact_loc_obj
;
869 /* Get the PWD, or NULL, as an absolute file-based URI,
870 adding a trailing forward slash (as required by SARIF v2.1.0
876 /* The prefix of a file-based URI, up to, but not including the path. */
877 #define FILE_PREFIX ("file://")
879 const char *pwd
= getpwd ();
882 size_t len
= strlen (pwd
);
883 if (len
== 0 || pwd
[len
- 1] != '/')
884 return concat (FILE_PREFIX
, pwd
, "/", NULL
);
887 gcc_assert (pwd
[len
- 1] == '/');
888 return concat (FILE_PREFIX
, pwd
, NULL
);
892 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for the pwd,
893 for use in the "run.originalUriBaseIds" property (SARIF v2.1.0
894 section 3.14.14) when we have any relative paths. */
897 sarif_builder::make_artifact_location_object_for_pwd () const
899 json::object
*artifact_loc_obj
= new json::object ();
901 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
902 if (char *pwd
= make_pwd_uri_str ())
904 gcc_assert (strlen (pwd
) > 0);
905 gcc_assert (pwd
[strlen (pwd
) - 1] == '/');
906 artifact_loc_obj
->set_string ("uri", pwd
);
910 return artifact_loc_obj
;
913 /* Get the column number within EXPLOC. */
916 sarif_builder::get_sarif_column (expanded_location exploc
) const
918 cpp_char_column_policy
policy (m_tabstop
, cpp_wcwidth
);
919 return location_compute_display_column (m_context
->get_file_cache (),
923 /* Make a region object (SARIF v2.1.0 section 3.30) for LOC,
927 sarif_builder::maybe_make_region_object (location_t loc
) const
929 location_t caret_loc
= get_pure_location (loc
);
931 if (caret_loc
<= BUILTINS_LOCATION
)
934 location_t start_loc
= get_start (loc
);
935 location_t finish_loc
= get_finish (loc
);
937 expanded_location exploc_caret
= expand_location (caret_loc
);
938 expanded_location exploc_start
= expand_location (start_loc
);
939 expanded_location exploc_finish
= expand_location (finish_loc
);
941 if (exploc_start
.file
!=exploc_caret
.file
)
943 if (exploc_finish
.file
!=exploc_caret
.file
)
946 json::object
*region_obj
= new json::object ();
948 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
949 region_obj
->set_integer ("startLine", exploc_start
.line
);
951 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
952 region_obj
->set_integer ("startColumn", get_sarif_column (exploc_start
));
954 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
955 if (exploc_finish
.line
!= exploc_start
.line
)
956 region_obj
->set_integer ("endLine", exploc_finish
.line
);
958 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
959 This expresses the column immediately beyond the range. */
961 int next_column
= sarif_builder::get_sarif_column (exploc_finish
) + 1;
962 region_obj
->set_integer ("endColumn", next_column
);
968 /* Make a region object (SARIF v2.1.0 section 3.30) for the "contextRegion"
969 property (SARIF v2.1.0 section 3.29.5) of a physicalLocation.
971 This is similar to maybe_make_region_object, but ignores column numbers,
972 covering the line(s) as a whole, and including a "snippet" property
973 embedding those source lines, making it easier for consumers to show
974 the pertinent source. */
977 sarif_builder::maybe_make_region_object_for_context (location_t loc
) const
979 location_t caret_loc
= get_pure_location (loc
);
981 if (caret_loc
<= BUILTINS_LOCATION
)
984 location_t start_loc
= get_start (loc
);
985 location_t finish_loc
= get_finish (loc
);
987 expanded_location exploc_caret
= expand_location (caret_loc
);
988 expanded_location exploc_start
= expand_location (start_loc
);
989 expanded_location exploc_finish
= expand_location (finish_loc
);
991 if (exploc_start
.file
!=exploc_caret
.file
)
993 if (exploc_finish
.file
!=exploc_caret
.file
)
996 json::object
*region_obj
= new json::object ();
998 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
999 region_obj
->set_integer ("startLine", exploc_start
.line
);
1001 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
1002 if (exploc_finish
.line
!= exploc_start
.line
)
1003 region_obj
->set_integer ("endLine", exploc_finish
.line
);
1005 /* "snippet" property (SARIF v2.1.0 section 3.30.13). */
1006 if (json::object
*artifact_content_obj
1007 = maybe_make_artifact_content_object (exploc_start
.file
,
1009 exploc_finish
.line
))
1010 region_obj
->set ("snippet", artifact_content_obj
);
1015 /* Make a region object (SARIF v2.1.0 section 3.30) for the deletion region
1016 of HINT (as per SARIF v2.1.0 section 3.57.3). */
1019 sarif_builder::make_region_object_for_hint (const fixit_hint
&hint
) const
1021 location_t start_loc
= hint
.get_start_loc ();
1022 location_t next_loc
= hint
.get_next_loc ();
1024 expanded_location exploc_start
= expand_location (start_loc
);
1025 expanded_location exploc_next
= expand_location (next_loc
);
1027 json::object
*region_obj
= new json::object ();
1029 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
1030 region_obj
->set_integer ("startLine", exploc_start
.line
);
1032 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
1033 int start_col
= get_sarif_column (exploc_start
);
1034 region_obj
->set_integer ("startColumn", start_col
);
1036 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
1037 if (exploc_next
.line
!= exploc_start
.line
)
1038 region_obj
->set_integer ("endLine", exploc_next
.line
);
1040 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
1041 This expresses the column immediately beyond the range. */
1042 int next_col
= get_sarif_column (exploc_next
);
1043 region_obj
->set_integer ("endColumn", next_col
);
1048 /* Attempt to get a string for a logicalLocation's "kind" property
1049 (SARIF v2.1.0 section 3.33.7).
1050 Return NULL if unknown. */
1053 maybe_get_sarif_kind (enum logical_location_kind kind
)
1059 case LOGICAL_LOCATION_KIND_UNKNOWN
:
1062 case LOGICAL_LOCATION_KIND_FUNCTION
:
1064 case LOGICAL_LOCATION_KIND_MEMBER
:
1066 case LOGICAL_LOCATION_KIND_MODULE
:
1068 case LOGICAL_LOCATION_KIND_NAMESPACE
:
1070 case LOGICAL_LOCATION_KIND_TYPE
:
1072 case LOGICAL_LOCATION_KIND_RETURN_TYPE
:
1073 return "returnType";
1074 case LOGICAL_LOCATION_KIND_PARAMETER
:
1076 case LOGICAL_LOCATION_KIND_VARIABLE
:
1081 /* Make a logicalLocation object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC,
1086 make_logical_location_object (const logical_location
&logical_loc
) const
1088 json::object
*logical_loc_obj
= new json::object ();
1090 /* "name" property (SARIF v2.1.0 section 3.33.4). */
1091 if (const char *short_name
= logical_loc
.get_short_name ())
1092 logical_loc_obj
->set_string ("name", short_name
);
1094 /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
1095 if (const char *name_with_scope
= logical_loc
.get_name_with_scope ())
1096 logical_loc_obj
->set_string ("fullyQualifiedName", name_with_scope
);
1098 /* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
1099 if (const char *internal_name
= logical_loc
.get_internal_name ())
1100 logical_loc_obj
->set_string ("decoratedName", internal_name
);
1102 /* "kind" property (SARIF v2.1.0 section 3.33.7). */
1103 enum logical_location_kind kind
= logical_loc
.get_kind ();
1104 if (const char *sarif_kind_str
= maybe_get_sarif_kind (kind
))
1105 logical_loc_obj
->set_string ("kind", sarif_kind_str
);
1107 return logical_loc_obj
;
1110 /* Make a codeFlow object (SARIF v2.1.0 section 3.36) for PATH. */
1113 sarif_builder::make_code_flow_object (const diagnostic_path
&path
)
1115 json::object
*code_flow_obj
= new json::object ();
1117 /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
1118 json::array
*thread_flows_arr
= new json::array ();
1120 /* Walk the events, consolidating into per-thread threadFlow objects,
1121 using the index with PATH as the overall executionOrder. */
1122 hash_map
<int_hash
<diagnostic_thread_id_t
, -1, -2>,
1123 sarif_thread_flow
*> thread_id_map
;
1124 for (unsigned i
= 0; i
< path
.num_events (); i
++)
1126 const diagnostic_event
&event
= path
.get_event (i
);
1127 const diagnostic_thread_id_t thread_id
= event
.get_thread_id ();
1128 sarif_thread_flow
*thread_flow_obj
;
1130 if (sarif_thread_flow
**slot
= thread_id_map
.get (thread_id
))
1131 thread_flow_obj
= *slot
;
1134 const diagnostic_thread
&thread
= path
.get_thread (thread_id
);
1135 thread_flow_obj
= new sarif_thread_flow (thread
);
1136 thread_flows_arr
->append (thread_flow_obj
);
1137 thread_id_map
.put (thread_id
, thread_flow_obj
);
1140 /* Add event to thread's threadFlow object. */
1141 json::object
*thread_flow_loc_obj
1142 = make_thread_flow_location_object (event
, i
);
1143 thread_flow_obj
->add_location (thread_flow_loc_obj
);
1145 code_flow_obj
->set ("threadFlows", thread_flows_arr
);
1147 return code_flow_obj
;
1150 /* Make a threadFlowLocation object (SARIF v2.1.0 section 3.38) for EVENT. */
1153 sarif_builder::make_thread_flow_location_object (const diagnostic_event
&ev
,
1156 json::object
*thread_flow_loc_obj
= new json::object ();
1158 /* "location" property (SARIF v2.1.0 section 3.38.3). */
1159 json::object
*location_obj
= make_location_object (ev
);
1160 thread_flow_loc_obj
->set ("location", location_obj
);
1162 /* "kinds" property (SARIF v2.1.0 section 3.38.8). */
1163 diagnostic_event::meaning m
= ev
.get_meaning ();
1164 if (json::array
*kinds_arr
= maybe_make_kinds_array (m
))
1165 thread_flow_loc_obj
->set ("kinds", kinds_arr
);
1167 /* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */
1168 thread_flow_loc_obj
->set_integer ("nestingLevel", ev
.get_stack_depth ());
1170 /* "executionOrder" property (SARIF v2.1.0 3.38.11).
1171 Offset by 1 to match the human-readable values emitted by %@. */
1172 thread_flow_loc_obj
->set_integer ("executionOrder", path_event_idx
+ 1);
1174 /* It might be nice to eventually implement the following for -fanalyzer:
1175 - the "stack" property (SARIF v2.1.0 section 3.38.5)
1176 - the "state" property (SARIF v2.1.0 section 3.38.9)
1177 - the "importance" property (SARIF v2.1.0 section 3.38.13). */
1179 return thread_flow_loc_obj
;
1182 /* If M has any known meaning, make a json array suitable for the "kinds"
1183 property of a threadFlowLocation object (SARIF v2.1.0 section 3.38.8).
1185 Otherwise, return NULL. */
1188 sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m
) const
1190 if (m
.m_verb
== diagnostic_event::VERB_unknown
1191 && m
.m_noun
== diagnostic_event::NOUN_unknown
1192 && m
.m_property
== diagnostic_event::PROPERTY_unknown
)
1195 json::array
*kinds_arr
= new json::array ();
1196 if (const char *verb_str
1197 = diagnostic_event::meaning::maybe_get_verb_str (m
.m_verb
))
1198 kinds_arr
->append (new json::string (verb_str
));
1199 if (const char *noun_str
1200 = diagnostic_event::meaning::maybe_get_noun_str (m
.m_noun
))
1201 kinds_arr
->append (new json::string (noun_str
));
1202 if (const char *property_str
1203 = diagnostic_event::meaning::maybe_get_property_str (m
.m_property
))
1204 kinds_arr
->append (new json::string (property_str
));
1208 /* Make a message object (SARIF v2.1.0 section 3.11) for MSG. */
1211 sarif_builder::make_message_object (const char *msg
) const
1213 json::object
*message_obj
= new json::object ();
1215 /* "text" property (SARIF v2.1.0 section 3.11.8). */
1216 message_obj
->set_string ("text", msg
);
1221 /* Make a message object (SARIF v2.1.0 section 3.11) for DIAGRAM.
1222 We emit the diagram as a code block within the Markdown part
1226 sarif_builder::make_message_object_for_diagram (diagnostic_context
*context
,
1227 const diagnostic_diagram
&diagram
)
1229 json::object
*message_obj
= new json::object ();
1231 /* "text" property (SARIF v2.1.0 section 3.11.8). */
1232 message_obj
->set_string ("text", diagram
.get_alt_text ());
1234 char *saved_prefix
= pp_take_prefix (context
->printer
);
1235 pp_set_prefix (context
->printer
, NULL
);
1237 /* "To produce a code block in Markdown, simply indent every line of
1238 the block by at least 4 spaces or 1 tab."
1239 Here we use 4 spaces. */
1240 diagram
.get_canvas ().print_to_pp (context
->printer
, " ");
1241 pp_set_prefix (context
->printer
, saved_prefix
);
1243 /* "markdown" property (SARIF v2.1.0 section 3.11.9). */
1244 message_obj
->set_string ("markdown", pp_formatted_text (context
->printer
));
1246 pp_clear_output_area (context
->printer
);
1251 /* Make a multiformatMessageString object (SARIF v2.1.0 section 3.12)
1255 sarif_builder::make_multiformat_message_string (const char *msg
) const
1257 json::object
*message_obj
= new json::object ();
1259 /* "text" property (SARIF v2.1.0 section 3.12.3). */
1260 message_obj
->set_string ("text", msg
);
1265 #define SARIF_SCHEMA "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"
1266 #define SARIF_VERSION "2.1.0"
1268 /* Make a top-level sarifLog object (SARIF v2.1.0 section 3.13).
1269 Take ownership of INVOCATION_OBJ and RESULTS. */
1272 sarif_builder::make_top_level_object (sarif_invocation
*invocation_obj
,
1273 json::array
*results
)
1275 json::object
*log_obj
= new json::object ();
1277 /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */
1278 log_obj
->set_string ("$schema", SARIF_SCHEMA
);
1280 /* "version" property (SARIF v2.1.0 section 3.13.2). */
1281 log_obj
->set_string ("version", SARIF_VERSION
);
1283 /* "runs" property (SARIF v2.1.0 section 3.13.4). */
1284 json::array
*run_arr
= new json::array ();
1285 json::object
*run_obj
= make_run_object (invocation_obj
, results
);
1286 run_arr
->append (run_obj
);
1287 log_obj
->set ("runs", run_arr
);
1292 /* Make a run object (SARIF v2.1.0 section 3.14).
1293 Take ownership of INVOCATION_OBJ and RESULTS. */
1296 sarif_builder::make_run_object (sarif_invocation
*invocation_obj
,
1297 json::array
*results
)
1299 json::object
*run_obj
= new json::object ();
1301 /* "tool" property (SARIF v2.1.0 section 3.14.6). */
1302 json::object
*tool_obj
= make_tool_object ();
1303 run_obj
->set ("tool", tool_obj
);
1305 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1306 if (json::array
*taxonomies_arr
= maybe_make_taxonomies_array ())
1307 run_obj
->set ("taxonomies", taxonomies_arr
);
1309 /* "invocations" property (SARIF v2.1.0 section 3.14.11). */
1311 json::array
*invocations_arr
= new json::array ();
1312 invocations_arr
->append (invocation_obj
);
1313 run_obj
->set ("invocations", invocations_arr
);
1316 /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */
1317 if (m_seen_any_relative_paths
)
1319 json::object
*orig_uri_base_ids
= new json::object ();
1320 run_obj
->set ("originalUriBaseIds", orig_uri_base_ids
);
1321 json::object
*pwd_art_loc_obj
= make_artifact_location_object_for_pwd ();
1322 orig_uri_base_ids
->set (PWD_PROPERTY_NAME
, pwd_art_loc_obj
);
1325 /* "artifacts" property (SARIF v2.1.0 section 3.14.15). */
1326 json::array
*artifacts_arr
= new json::array ();
1327 for (auto iter
: m_filenames
)
1329 json::object
*artifact_obj
= make_artifact_object (iter
);
1330 artifacts_arr
->append (artifact_obj
);
1332 run_obj
->set ("artifacts", artifacts_arr
);
1334 /* "results" property (SARIF v2.1.0 section 3.14.23). */
1335 run_obj
->set ("results", results
);
1340 /* Make a tool object (SARIF v2.1.0 section 3.18). */
1343 sarif_builder::make_tool_object () const
1345 json::object
*tool_obj
= new json::object ();
1347 /* "driver" property (SARIF v2.1.0 section 3.18.2). */
1348 json::object
*driver_obj
= make_driver_tool_component_object ();
1349 tool_obj
->set ("driver", driver_obj
);
1351 /* Report plugins via the "extensions" property
1352 (SARIF v2.1.0 section 3.18.3). */
1353 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
1354 if (const client_version_info
*vinfo
1355 = client_data_hooks
->get_any_version_info ())
1357 class my_plugin_visitor
: public client_version_info :: plugin_visitor
1360 void on_plugin (const diagnostic_client_plugin_info
&p
) final override
1362 /* Create a toolComponent object (SARIF v2.1.0 section 3.19)
1364 json::object
*plugin_obj
= new json::object ();
1365 m_plugin_objs
.safe_push (plugin_obj
);
1367 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1368 if (const char *short_name
= p
.get_short_name ())
1369 plugin_obj
->set_string ("name", short_name
);
1371 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1372 if (const char *full_name
= p
.get_full_name ())
1373 plugin_obj
->set_string ("fullName", full_name
);
1375 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1376 if (const char *version
= p
.get_version ())
1377 plugin_obj
->set_string ("version", version
);
1379 auto_vec
<json::object
*> m_plugin_objs
;
1381 my_plugin_visitor v
;
1382 vinfo
->for_each_plugin (v
);
1383 if (v
.m_plugin_objs
.length () > 0)
1385 json::array
*extensions_arr
= new json::array ();
1386 tool_obj
->set ("extensions", extensions_arr
);
1387 for (auto iter
: v
.m_plugin_objs
)
1388 extensions_arr
->append (iter
);
1392 /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other
1393 "extensions" (see toplev.cc: print_version). */
1398 /* Make a toolComponent object (SARIF v2.1.0 section 3.19) for what SARIF
1399 calls the "driver" (see SARIF v2.1.0 section 3.18.1). */
1402 sarif_builder::make_driver_tool_component_object () const
1404 json::object
*driver_obj
= new json::object ();
1406 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
1407 if (const client_version_info
*vinfo
1408 = client_data_hooks
->get_any_version_info ())
1410 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1411 if (const char *name
= vinfo
->get_tool_name ())
1412 driver_obj
->set_string ("name", name
);
1414 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1415 if (char *full_name
= vinfo
->maybe_make_full_name ())
1417 driver_obj
->set_string ("fullName", full_name
);
1421 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1422 if (const char *version
= vinfo
->get_version_string ())
1423 driver_obj
->set_string ("version", version
);
1425 /* "informationUri" property (SARIF v2.1.0 section 3.19.17). */
1426 if (char *version_url
= vinfo
->maybe_make_version_url ())
1428 driver_obj
->set_string ("informationUri", version_url
);
1433 /* "rules" property (SARIF v2.1.0 section 3.19.23). */
1434 driver_obj
->set ("rules", m_rules_arr
);
1439 /* If we've seen any CWE IDs, make an array for the "taxonomies" property
1440 (SARIF v2.1.0 section 3.14.8) of a run object, containting a singl
1441 toolComponent (3.19) as per 3.19.3, representing the CWE.
1443 Otherwise return NULL. */
1446 sarif_builder::maybe_make_taxonomies_array () const
1448 json::object
*cwe_obj
= maybe_make_cwe_taxonomy_object ();
1452 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1453 json::array
*taxonomies_arr
= new json::array ();
1454 taxonomies_arr
->append (cwe_obj
);
1455 return taxonomies_arr
;
1458 /* If we've seen any CWE IDs, make a toolComponent object
1459 (SARIF v2.1.0 section 3.19) representing the CWE taxonomy, as per 3.19.3.
1460 Populate the "taxa" property with all of the CWE IDs in m_cwe_id_set.
1462 Otherwise return NULL. */
1465 sarif_builder::maybe_make_cwe_taxonomy_object () const
1467 if (m_cwe_id_set
.is_empty ())
1470 json::object
*taxonomy_obj
= new json::object ();
1472 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1473 taxonomy_obj
->set_string ("name", "CWE");
1475 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1476 taxonomy_obj
->set_string ("version", "4.7");
1478 /* "organization" property (SARIF v2.1.0 section 3.19.18). */
1479 taxonomy_obj
->set_string ("organization", "MITRE");
1481 /* "shortDescription" property (SARIF v2.1.0 section 3.19.19). */
1482 json::object
*short_desc
1483 = make_multiformat_message_string ("The MITRE"
1484 " Common Weakness Enumeration");
1485 taxonomy_obj
->set ("shortDescription", short_desc
);
1487 /* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */
1488 json::array
*taxa_arr
= new json::array ();
1489 for (auto cwe_id
: m_cwe_id_set
)
1491 json::object
*cwe_taxon
1492 = make_reporting_descriptor_object_for_cwe_id (cwe_id
);
1493 taxa_arr
->append (cwe_taxon
);
1495 taxonomy_obj
->set ("taxa", taxa_arr
);
1497 return taxonomy_obj
;
1500 /* Make an artifact object (SARIF v2.1.0 section 3.24). */
1503 sarif_builder::make_artifact_object (const char *filename
)
1505 json::object
*artifact_obj
= new json::object ();
1507 /* "location" property (SARIF v2.1.0 section 3.24.2). */
1508 json::object
*artifact_loc_obj
= make_artifact_location_object (filename
);
1509 artifact_obj
->set ("location", artifact_loc_obj
);
1511 /* "contents" property (SARIF v2.1.0 section 3.24.8). */
1512 if (json::object
*artifact_content_obj
1513 = maybe_make_artifact_content_object (filename
))
1514 artifact_obj
->set ("contents", artifact_content_obj
);
1516 /* "sourceLanguage" property (SARIF v2.1.0 section 3.24.10). */
1517 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
1518 if (const char *source_lang
1519 = client_data_hooks
->maybe_get_sarif_source_language (filename
))
1520 artifact_obj
->set_string ("sourceLanguage", source_lang
);
1522 return artifact_obj
;
1525 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the
1526 full contents of FILENAME. */
1529 sarif_builder::maybe_make_artifact_content_object (const char *filename
) const
1531 /* Let input.cc handle any charset conversion. */
1532 char_span utf8_content
1533 = m_context
->get_file_cache ().get_source_file_content (filename
);
1537 /* Don't add it if it's not valid UTF-8. */
1538 if (!cpp_valid_utf8_p(utf8_content
.get_buffer (), utf8_content
.length ()))
1541 json::object
*artifact_content_obj
= new json::object ();
1542 artifact_content_obj
->set ("text",
1543 new json::string (utf8_content
.get_buffer (),
1544 utf8_content
.length ()));
1545 return artifact_content_obj
;
1548 /* Attempt to read the given range of lines from FILENAME; return
1549 a freshly-allocated 0-terminated buffer containing them, or NULL. */
1552 sarif_builder::get_source_lines (const char *filename
,
1556 auto_vec
<char> result
;
1558 for (int line
= start_line
; line
<= end_line
; line
++)
1560 char_span line_content
1561 = m_context
->get_file_cache ().get_source_line (filename
, line
);
1562 if (!line_content
.get_buffer ())
1564 result
.reserve (line_content
.length () + 1);
1565 for (size_t i
= 0; i
< line_content
.length (); i
++)
1566 result
.quick_push (line_content
[i
]);
1567 result
.quick_push ('\n');
1569 result
.safe_push ('\0');
1571 return xstrdup (result
.address ());
1574 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the given
1575 run of lines within FILENAME (including the endpoints). */
1578 sarif_builder::maybe_make_artifact_content_object (const char *filename
,
1582 char *text_utf8
= get_source_lines (filename
, start_line
, end_line
);
1587 /* Don't add it if it's not valid UTF-8. */
1588 if (!cpp_valid_utf8_p(text_utf8
, strlen(text_utf8
)))
1594 json::object
*artifact_content_obj
= new json::object ();
1595 artifact_content_obj
->set_string ("text", text_utf8
);
1598 return artifact_content_obj
;
1601 /* Make a fix object (SARIF v2.1.0 section 3.55) for RICHLOC. */
1604 sarif_builder::make_fix_object (const rich_location
&richloc
)
1606 json::object
*fix_obj
= new json::object ();
1608 /* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */
1609 /* We assume that all fix-it hints in RICHLOC affect the same file. */
1610 json::array
*artifact_change_arr
= new json::array ();
1611 json::object
*artifact_change_obj
= make_artifact_change_object (richloc
);
1612 artifact_change_arr
->append (artifact_change_obj
);
1613 fix_obj
->set ("artifactChanges", artifact_change_arr
);
1618 /* Make an artifactChange object (SARIF v2.1.0 section 3.56) for RICHLOC. */
1621 sarif_builder::make_artifact_change_object (const rich_location
&richloc
)
1623 json::object
*artifact_change_obj
= new json::object ();
1625 /* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */
1626 json::object
*artifact_location_obj
1627 = make_artifact_location_object (richloc
.get_loc ());
1628 artifact_change_obj
->set ("artifactLocation", artifact_location_obj
);
1630 /* "replacements" property (SARIF v2.1.0 section 3.56.3). */
1631 json::array
*replacement_arr
= new json::array ();
1632 for (unsigned int i
= 0; i
< richloc
.get_num_fixit_hints (); i
++)
1634 const fixit_hint
*hint
= richloc
.get_fixit_hint (i
);
1635 json::object
*replacement_obj
= make_replacement_object (*hint
);
1636 replacement_arr
->append (replacement_obj
);
1638 artifact_change_obj
->set ("replacements", replacement_arr
);
1640 return artifact_change_obj
;
1643 /* Make a replacement object (SARIF v2.1.0 section 3.57) for HINT. */
1646 sarif_builder::make_replacement_object (const fixit_hint
&hint
) const
1648 json::object
*replacement_obj
= new json::object ();
1650 /* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */
1651 json::object
*region_obj
= make_region_object_for_hint (hint
);
1652 replacement_obj
->set ("deletedRegion", region_obj
);
1654 /* "insertedContent" property (SARIF v2.1.0 section 3.57.4). */
1655 json::object
*content_obj
= make_artifact_content_object (hint
.get_string ());
1656 replacement_obj
->set ("insertedContent", content_obj
);
1658 return replacement_obj
;
1661 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for TEXT. */
1664 sarif_builder::make_artifact_content_object (const char *text
) const
1666 json::object
*content_obj
= new json::object ();
1668 /* "text" property (SARIF v2.1.0 section 3.3.2). */
1669 content_obj
->set_string ("text", text
);
1674 /* Callback for diagnostic_context::ice_handler_cb for when an ICE
1678 sarif_ice_handler (diagnostic_context
*context
)
1680 /* Attempt to ensure that a .sarif file is written out. */
1681 diagnostic_finish (context
);
1683 /* Print a header for the remaining output to stderr, and
1684 return, attempting to print the usual ICE messages to
1685 stderr. Hopefully this will be helpful to the user in
1686 indicating what's gone wrong (also for DejaGnu, for pruning
1688 fnotice (stderr
, "Internal compiler error:\n");
1691 class sarif_output_format
: public diagnostic_output_format
1694 void on_begin_group () final override
1698 void on_end_group () final override
1700 m_builder
.end_group ();
1703 on_begin_diagnostic (diagnostic_info
*) final override
1708 on_end_diagnostic (diagnostic_info
*diagnostic
,
1709 diagnostic_t orig_diag_kind
) final override
1711 m_builder
.end_diagnostic (&m_context
, diagnostic
, orig_diag_kind
);
1713 void on_diagram (const diagnostic_diagram
&diagram
) final override
1715 m_builder
.emit_diagram (&m_context
, diagram
);
1719 sarif_output_format (diagnostic_context
&context
)
1720 : diagnostic_output_format (context
),
1721 m_builder (&context
)
1724 sarif_builder m_builder
;
1727 class sarif_stream_output_format
: public sarif_output_format
1730 sarif_stream_output_format (diagnostic_context
&context
, FILE *stream
)
1731 : sarif_output_format (context
),
1735 ~sarif_stream_output_format ()
1737 m_builder
.flush_to_file (m_stream
);
1743 class sarif_file_output_format
: public sarif_output_format
1746 sarif_file_output_format (diagnostic_context
&context
,
1747 const char *base_file_name
)
1748 : sarif_output_format (context
),
1749 m_base_file_name (xstrdup (base_file_name
))
1752 ~sarif_file_output_format ()
1754 char *filename
= concat (m_base_file_name
, ".sarif", NULL
);
1755 free (m_base_file_name
);
1756 m_base_file_name
= nullptr;
1757 FILE *outf
= fopen (filename
, "w");
1760 const char *errstr
= xstrerror (errno
);
1761 fnotice (stderr
, "error: unable to open '%s' for writing: %s\n",
1766 m_builder
.flush_to_file (outf
);
1772 char *m_base_file_name
;
1775 /* Populate CONTEXT in preparation for SARIF output (either to stderr, or
1779 diagnostic_output_format_init_sarif (diagnostic_context
*context
)
1781 /* Override callbacks. */
1782 context
->m_print_path
= nullptr; /* handled in sarif_end_diagnostic. */
1783 context
->set_ice_handler_callback (sarif_ice_handler
);
1785 /* The metadata is handled in SARIF format, rather than as text. */
1786 context
->set_show_cwe (false);
1787 context
->set_show_rules (false);
1789 /* The option is handled in SARIF format, rather than as text. */
1790 context
->set_show_option_requested (false);
1792 /* Don't colorize the text. */
1793 pp_show_color (context
->printer
) = false;
1796 /* Populate CONTEXT in preparation for SARIF output to stderr. */
1799 diagnostic_output_format_init_sarif_stderr (diagnostic_context
*context
)
1801 diagnostic_output_format_init_sarif (context
);
1802 context
->set_output_format (new sarif_stream_output_format (*context
,
1806 /* Populate CONTEXT in preparation for SARIF output to a file named
1807 BASE_FILE_NAME.sarif. */
1810 diagnostic_output_format_init_sarif_file (diagnostic_context
*context
,
1811 const char *base_file_name
)
1813 diagnostic_output_format_init_sarif (context
);
1814 context
->set_output_format (new sarif_file_output_format (*context
,
1818 /* Populate CONTEXT in preparation for SARIF output to STREAM. */
1821 diagnostic_output_format_init_sarif_stream (diagnostic_context
*context
,
1824 diagnostic_output_format_init_sarif (context
);
1825 context
->set_output_format (new sarif_stream_output_format (*context
,