1 /* SARIF output for diagnostics
2 Copyright (C) 2018-2024 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 const 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 const 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 const 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
,
163 void end_diagnostic (diagnostic_context
*context
,
164 const diagnostic_info
&diagnostic
,
165 diagnostic_t orig_diag_kind
);
166 void emit_diagram (diagnostic_context
*context
,
167 const diagnostic_diagram
&diagram
);
170 void flush_to_file (FILE *outf
);
172 json::array
*make_locations_arr (const diagnostic_info
&diagnostic
);
173 json::object
*make_location_object (const rich_location
&rich_loc
,
174 const logical_location
*logical_loc
);
175 json::object
*make_message_object (const char *msg
) const;
177 make_message_object_for_diagram (diagnostic_context
*context
,
178 const diagnostic_diagram
&diagram
);
181 sarif_result
*make_result_object (diagnostic_context
*context
,
182 const diagnostic_info
&diagnostic
,
183 diagnostic_t orig_diag_kind
);
184 void set_any_logical_locs_arr (json::object
*location_obj
,
185 const logical_location
*logical_loc
);
186 json::object
*make_location_object (const diagnostic_event
&event
);
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 const 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
;
256 /* class sarif_object : public json::object. */
259 sarif_object::get_or_create_properties ()
261 json::value
*properties_val
= get ("properties");
264 if (properties_val
->get_kind () == json::JSON_OBJECT
)
265 return *static_cast <sarif_property_bag
*> (properties_val
);
268 sarif_property_bag
*bag
= new sarif_property_bag ();
269 set ("properties", bag
);
273 /* class sarif_invocation : public sarif_object. */
275 /* Handle an internal compiler error DIAGNOSTIC occurring on CONTEXT.
276 Add an object representing the ICE to the notifications array. */
279 sarif_invocation::add_notification_for_ice (diagnostic_context
*context
,
280 const diagnostic_info
&diagnostic
,
281 sarif_builder
*builder
)
285 sarif_ice_notification
*notification_obj
286 = new sarif_ice_notification (context
, diagnostic
, builder
);
287 m_notifications_arr
->append (notification_obj
);
291 sarif_invocation::prepare_to_flush (diagnostic_context
*context
)
293 /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */
294 set_bool ("executionSuccessful", m_success
);
296 /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */
297 set ("toolExecutionNotifications", m_notifications_arr
);
299 /* Call client hook, allowing it to create a custom property bag for
300 this object (SARIF v2.1.0 section 3.8) e.g. for recording time vars. */
301 if (auto client_data_hooks
= context
->get_client_data_hooks ())
302 client_data_hooks
->add_sarif_invocation_properties (*this);
305 /* class sarif_result : public sarif_object. */
307 /* Handle secondary diagnostics that occur within a diagnostic group.
308 The closest SARIF seems to have to nested diagnostics is the
309 "relatedLocations" property of result objects (SARIF v2.1.0 section 3.27.22),
310 so we lazily set this property and populate the array if and when
311 secondary diagnostics occur (such as notes to a warning). */
314 sarif_result::on_nested_diagnostic (diagnostic_context
*context
,
315 const diagnostic_info
&diagnostic
,
316 diagnostic_t
/*orig_diag_kind*/,
317 sarif_builder
*builder
)
319 /* We don't yet generate meaningful logical locations for notes;
320 sometimes these will related to current_function_decl, but
322 json::object
*location_obj
323 = builder
->make_location_object (*diagnostic
.richloc
, NULL
);
324 json::object
*message_obj
325 = builder
->make_message_object (pp_formatted_text (context
->printer
));
326 pp_clear_output_area (context
->printer
);
327 location_obj
->set ("message", message_obj
);
329 add_related_location (location_obj
);
332 /* Handle diagrams that occur within a diagnostic group.
333 The closest thing in SARIF seems to be to add a location to the
334 "releatedLocations" property (SARIF v2.1.0 section 3.27.22),
335 and to put the diagram into the "message" property of that location
336 (SARIF v2.1.0 section 3.28.5). */
339 sarif_result::on_diagram (diagnostic_context
*context
,
340 const diagnostic_diagram
&diagram
,
341 sarif_builder
*builder
)
343 json::object
*location_obj
= new json::object ();
344 json::object
*message_obj
345 = builder
->make_message_object_for_diagram (context
, diagram
);
346 location_obj
->set ("message", message_obj
);
348 add_related_location (location_obj
);
351 /* Add LOCATION_OBJ to this result's "relatedLocations" array,
352 creating it if it doesn't yet exist. */
355 sarif_result::add_related_location (json::object
*location_obj
)
357 if (!m_related_locations_arr
)
359 m_related_locations_arr
= new json::array ();
360 set ("relatedLocations", m_related_locations_arr
);
362 m_related_locations_arr
->append (location_obj
);
365 /* class sarif_ice_notification : public sarif_object. */
367 /* sarif_ice_notification's ctor.
368 DIAGNOSTIC is an internal compiler error. */
370 sarif_ice_notification::sarif_ice_notification (diagnostic_context
*context
,
371 const diagnostic_info
&diagnostic
,
372 sarif_builder
*builder
)
374 /* "locations" property (SARIF v2.1.0 section 3.58.4). */
375 json::array
*locations_arr
= builder
->make_locations_arr (diagnostic
);
376 set ("locations", locations_arr
);
378 /* "message" property (SARIF v2.1.0 section 3.85.5). */
379 json::object
*message_obj
380 = builder
->make_message_object (pp_formatted_text (context
->printer
));
381 pp_clear_output_area (context
->printer
);
382 set ("message", message_obj
);
384 /* "level" property (SARIF v2.1.0 section 3.58.6). */
385 set_string ("level", "error");
388 /* class sarif_thread_flow : public sarif_object. */
390 sarif_thread_flow::sarif_thread_flow (const diagnostic_thread
&thread
)
392 /* "id" property (SARIF v2.1.0 section 3.37.2). */
393 label_text
name (thread
.get_name (false));
394 set_string ("id", name
.get ());
396 /* "locations" property (SARIF v2.1.0 section 3.37.6). */
397 m_locations_arr
= new json::array ();
398 set ("locations", m_locations_arr
);
401 /* class sarif_builder. */
403 /* sarif_builder's ctor. */
405 sarif_builder::sarif_builder (diagnostic_context
*context
,
407 : m_context (context
),
408 m_invocation_obj (new sarif_invocation ()),
409 m_results_array (new json::array ()),
410 m_cur_group_result (NULL
),
411 m_seen_any_relative_paths (false),
413 m_rules_arr (new json::array ()),
414 m_tabstop (context
->m_tabstop
),
415 m_formatted (formatted
)
419 /* Implementation of "end_diagnostic" for SARIF output. */
422 sarif_builder::end_diagnostic (diagnostic_context
*context
,
423 const diagnostic_info
&diagnostic
,
424 diagnostic_t orig_diag_kind
)
426 if (diagnostic
.kind
== DK_ICE
|| diagnostic
.kind
== DK_ICE_NOBT
)
428 m_invocation_obj
->add_notification_for_ice (context
, diagnostic
, this);
432 if (m_cur_group_result
)
433 /* Nested diagnostic. */
434 m_cur_group_result
->on_nested_diagnostic (context
,
440 /* Top-level diagnostic. */
441 sarif_result
*result_obj
442 = make_result_object (context
, diagnostic
, orig_diag_kind
);
443 m_results_array
->append (result_obj
);
444 m_cur_group_result
= result_obj
;
448 /* Implementation of diagnostic_context::m_diagrams.m_emission_cb
452 sarif_builder::emit_diagram (diagnostic_context
*context
,
453 const diagnostic_diagram
&diagram
)
455 /* We must be within the emission of a top-level diagnostic. */
456 gcc_assert (m_cur_group_result
);
457 m_cur_group_result
->on_diagram (context
, diagram
, this);
460 /* Implementation of "end_group_cb" for SARIF output. */
463 sarif_builder::end_group ()
465 m_cur_group_result
= NULL
;
468 /* Create a top-level object, and add it to all the results
469 (and other entities) we've seen so far.
471 Flush it all to OUTF. */
474 sarif_builder::flush_to_file (FILE *outf
)
476 m_invocation_obj
->prepare_to_flush (m_context
);
477 json::object
*top
= make_top_level_object (m_invocation_obj
, m_results_array
);
478 top
->dump (outf
, m_formatted
);
479 m_invocation_obj
= NULL
;
480 m_results_array
= NULL
;
481 fprintf (outf
, "\n");
485 /* Attempt to convert DIAG_KIND to a suitable value for the "level"
486 property (SARIF v2.1.0 section 3.27.10).
488 Return NULL if there isn't one. */
491 maybe_get_sarif_level (diagnostic_t diag_kind
)
507 /* Make a string for DIAG_KIND suitable for use a ruleId
508 (SARIF v2.1.0 section 3.27.5) as a fallback for when we don't
509 have anything better to use. */
512 make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind
)
514 static const char *const diagnostic_kind_text
[] = {
515 #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
516 #include "diagnostic.def"
517 #undef DEFINE_DIAGNOSTIC_KIND
520 /* Lose the trailing ": ". */
521 const char *kind_text
= diagnostic_kind_text
[diag_kind
];
522 size_t len
= strlen (kind_text
);
523 gcc_assert (len
> 2);
524 gcc_assert (kind_text
[len
- 2] == ':');
525 gcc_assert (kind_text
[len
- 1] == ' ');
526 char *rstrip
= xstrdup (kind_text
);
527 rstrip
[len
- 2] = '\0';
531 /* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */
534 sarif_builder::make_result_object (diagnostic_context
*context
,
535 const diagnostic_info
&diagnostic
,
536 diagnostic_t orig_diag_kind
)
538 sarif_result
*result_obj
= new sarif_result ();
540 /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
541 /* Ideally we'd have an option_name for these. */
542 if (char *option_text
543 = context
->make_option_name (diagnostic
.option_index
,
544 orig_diag_kind
, diagnostic
.kind
))
546 /* Lazily create reportingDescriptor objects for and add to m_rules_arr.
547 Set ruleId referencing them. */
548 result_obj
->set_string ("ruleId", option_text
);
549 if (m_rule_id_set
.contains (option_text
))
553 /* This is the first time we've seen this ruleId. */
554 /* Add to set, taking ownership. */
555 m_rule_id_set
.add (option_text
);
557 json::object
*reporting_desc_obj
558 = make_reporting_descriptor_object_for_warning (context
,
562 m_rules_arr
->append (reporting_desc_obj
);
567 /* Otherwise, we have an "error" or a stray "note"; use the
568 diagnostic kind as the ruleId, so that the result object at least
570 We don't bother creating reportingDescriptor objects for these. */
571 char *rule_id
= make_rule_id_for_diagnostic_kind (orig_diag_kind
);
572 result_obj
->set_string ("ruleId", rule_id
);
576 if (diagnostic
.metadata
)
578 /* "taxa" property (SARIF v2.1.0 section 3.27.8). */
579 if (int cwe_id
= diagnostic
.metadata
->get_cwe ())
581 json::array
*taxa_arr
= new json::array ();
582 json::object
*cwe_id_obj
583 = make_reporting_descriptor_reference_object_for_cwe_id (cwe_id
);
584 taxa_arr
->append (cwe_id_obj
);
585 result_obj
->set ("taxa", taxa_arr
);
588 diagnostic
.metadata
->maybe_add_sarif_properties (*result_obj
);
591 /* "level" property (SARIF v2.1.0 section 3.27.10). */
592 if (const char *sarif_level
= maybe_get_sarif_level (diagnostic
.kind
))
593 result_obj
->set_string ("level", sarif_level
);
595 /* "message" property (SARIF v2.1.0 section 3.27.11). */
596 json::object
*message_obj
597 = make_message_object (pp_formatted_text (context
->printer
));
598 pp_clear_output_area (context
->printer
);
599 result_obj
->set ("message", message_obj
);
601 /* "locations" property (SARIF v2.1.0 section 3.27.12). */
602 json::array
*locations_arr
= make_locations_arr (diagnostic
);
603 result_obj
->set ("locations", locations_arr
);
605 /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
606 if (const diagnostic_path
*path
= diagnostic
.richloc
->get_path ())
608 json::array
*code_flows_arr
= new json::array ();
609 json::object
*code_flow_obj
= make_code_flow_object (*path
);
610 code_flows_arr
->append (code_flow_obj
);
611 result_obj
->set ("codeFlows", code_flows_arr
);
614 /* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is
615 set up later, if any nested diagnostics occur within this diagnostic
618 /* "fixes" property (SARIF v2.1.0 section 3.27.30). */
619 const rich_location
*richloc
= diagnostic
.richloc
;
620 if (richloc
->get_num_fixit_hints ())
622 json::array
*fix_arr
= new json::array ();
623 json::object
*fix_obj
= make_fix_object (*richloc
);
624 fix_arr
->append (fix_obj
);
625 result_obj
->set ("fixes", fix_arr
);
631 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
632 for a GCC warning. */
636 make_reporting_descriptor_object_for_warning (diagnostic_context
*context
,
637 const diagnostic_info
&diagnostic
,
638 diagnostic_t
/*orig_diag_kind*/,
639 const char *option_text
)
641 json::object
*reporting_desc
= new json::object ();
643 /* "id" property (SARIF v2.1.0 section 3.49.3). */
644 reporting_desc
->set_string ("id", option_text
);
646 /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since
647 it seems redundant compared to "id". */
649 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
650 if (char *option_url
= context
->make_option_url (diagnostic
.option_index
))
652 reporting_desc
->set_string ("helpUri", option_url
);
656 return reporting_desc
;
659 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
660 for CWE_ID, for use within the CWE taxa array. */
663 sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id
) const
665 json::object
*reporting_desc
= new json::object ();
667 /* "id" property (SARIF v2.1.0 section 3.49.3). */
670 pp_printf (&pp
, "%i", cwe_id
);
671 reporting_desc
->set_string ("id", pp_formatted_text (&pp
));
674 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
676 char *url
= get_cwe_url (cwe_id
);
677 reporting_desc
->set_string ("helpUri", url
);
681 return reporting_desc
;
684 /* Make a reportingDescriptorReference object (SARIF v2.1.0 section 3.52)
685 referencing CWE_ID, for use within a result object.
686 Also, add CWE_ID to m_cwe_id_set. */
690 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id
)
692 json::object
*desc_ref_obj
= new json::object ();
694 /* "id" property (SARIF v2.1.0 section 3.52.4). */
697 pp_printf (&pp
, "%i", cwe_id
);
698 desc_ref_obj
->set_string ("id", pp_formatted_text (&pp
));
701 /* "toolComponent" property (SARIF v2.1.0 section 3.52.7). */
702 json::object
*comp_ref_obj
= make_tool_component_reference_object_for_cwe ();
703 desc_ref_obj
->set ("toolComponent", comp_ref_obj
);
705 /* Add CWE_ID to our set. */
706 gcc_assert (cwe_id
> 0);
707 m_cwe_id_set
.add (cwe_id
);
712 /* Make a toolComponentReference object (SARIF v2.1.0 section 3.54) that
713 references the CWE taxonomy. */
717 make_tool_component_reference_object_for_cwe () const
719 json::object
*comp_ref_obj
= new json::object ();
721 /* "name" property (SARIF v2.1.0 section 3.54.3). */
722 comp_ref_obj
->set_string ("name", "cwe");
727 /* Make an array suitable for use as the "locations" property of:
728 - a "result" object (SARIF v2.1.0 section 3.27.12), or
729 - a "notification" object (SARIF v2.1.0 section 3.58.4). */
732 sarif_builder::make_locations_arr (const diagnostic_info
&diagnostic
)
734 json::array
*locations_arr
= new json::array ();
735 const logical_location
*logical_loc
= NULL
;
736 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
737 logical_loc
= client_data_hooks
->get_current_logical_location ();
739 json::object
*location_obj
740 = make_location_object (*diagnostic
.richloc
, logical_loc
);
741 locations_arr
->append (location_obj
);
742 return locations_arr
;
745 /* If LOGICAL_LOC is non-NULL, use it to create a "logicalLocations" property
746 within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */
750 set_any_logical_locs_arr (json::object
*location_obj
,
751 const logical_location
*logical_loc
)
755 json::object
*logical_loc_obj
= make_sarif_logical_location_object (*logical_loc
);
756 json::array
*location_locs_arr
= new json::array ();
757 location_locs_arr
->append (logical_loc_obj
);
758 location_obj
->set ("logicalLocations", location_locs_arr
);
761 /* Make a location object (SARIF v2.1.0 section 3.28) for RICH_LOC
765 sarif_builder::make_location_object (const rich_location
&rich_loc
,
766 const logical_location
*logical_loc
)
768 json::object
*location_obj
= new json::object ();
770 /* Get primary loc from RICH_LOC. */
771 location_t loc
= rich_loc
.get_loc ();
773 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
774 if (json::object
*phs_loc_obj
= maybe_make_physical_location_object (loc
))
775 location_obj
->set ("physicalLocation", phs_loc_obj
);
777 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
778 set_any_logical_locs_arr (location_obj
, logical_loc
);
783 /* Make a location object (SARIF v2.1.0 section 3.28) for EVENT
784 within a diagnostic_path. */
787 sarif_builder::make_location_object (const diagnostic_event
&event
)
789 json::object
*location_obj
= new json::object ();
791 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
792 location_t loc
= event
.get_location ();
793 if (json::object
*phs_loc_obj
= maybe_make_physical_location_object (loc
))
794 location_obj
->set ("physicalLocation", phs_loc_obj
);
796 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
797 const logical_location
*logical_loc
= event
.get_logical_location ();
798 set_any_logical_locs_arr (location_obj
, logical_loc
);
800 /* "message" property (SARIF v2.1.0 section 3.28.5). */
801 label_text ev_desc
= event
.get_desc (false);
802 json::object
*message_obj
= make_message_object (ev_desc
.get ());
803 location_obj
->set ("message", message_obj
);
808 /* Make a physicalLocation object (SARIF v2.1.0 section 3.29) for LOC,
810 Add any filename to the m_artifacts. */
813 sarif_builder::maybe_make_physical_location_object (location_t loc
)
815 if (loc
<= BUILTINS_LOCATION
|| LOCATION_FILE (loc
) == NULL
)
818 json::object
*phys_loc_obj
= new json::object ();
820 /* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */
821 json::object
*artifact_loc_obj
= make_artifact_location_object (loc
);
822 phys_loc_obj
->set ("artifactLocation", artifact_loc_obj
);
823 m_filenames
.add (LOCATION_FILE (loc
));
825 /* "region" property (SARIF v2.1.0 section 3.29.4). */
826 if (json::object
*region_obj
= maybe_make_region_object (loc
))
827 phys_loc_obj
->set ("region", region_obj
);
829 /* "contextRegion" property (SARIF v2.1.0 section 3.29.5). */
830 if (json::object
*context_region_obj
831 = maybe_make_region_object_for_context (loc
))
832 phys_loc_obj
->set ("contextRegion", context_region_obj
);
834 /* Instead, we add artifacts to the run as a whole,
835 with artifact.contents.
836 Could do both, though. */
841 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for LOC,
845 sarif_builder::make_artifact_location_object (location_t loc
)
847 return make_artifact_location_object (LOCATION_FILE (loc
));
850 /* The ID value for use in "uriBaseId" properties (SARIF v2.1.0 section 3.4.4)
851 for when we need to express paths relative to PWD. */
853 #define PWD_PROPERTY_NAME ("PWD")
855 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for FILENAME,
859 sarif_builder::make_artifact_location_object (const char *filename
)
861 json::object
*artifact_loc_obj
= new json::object ();
863 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
864 artifact_loc_obj
->set_string ("uri", filename
);
866 if (filename
[0] != '/')
868 /* If we have a relative path, set the "uriBaseId" property
869 (SARIF v2.1.0 section 3.4.4). */
870 artifact_loc_obj
->set_string ("uriBaseId", PWD_PROPERTY_NAME
);
871 m_seen_any_relative_paths
= true;
874 return artifact_loc_obj
;
877 /* Get the PWD, or NULL, as an absolute file-based URI,
878 adding a trailing forward slash (as required by SARIF v2.1.0
884 /* The prefix of a file-based URI, up to, but not including the path. */
885 #define FILE_PREFIX ("file://")
887 const char *pwd
= getpwd ();
890 size_t len
= strlen (pwd
);
891 if (len
== 0 || pwd
[len
- 1] != '/')
892 return concat (FILE_PREFIX
, pwd
, "/", NULL
);
895 gcc_assert (pwd
[len
- 1] == '/');
896 return concat (FILE_PREFIX
, pwd
, NULL
);
900 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for the pwd,
901 for use in the "run.originalUriBaseIds" property (SARIF v2.1.0
902 section 3.14.14) when we have any relative paths. */
905 sarif_builder::make_artifact_location_object_for_pwd () const
907 json::object
*artifact_loc_obj
= new json::object ();
909 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
910 if (char *pwd
= make_pwd_uri_str ())
912 gcc_assert (strlen (pwd
) > 0);
913 gcc_assert (pwd
[strlen (pwd
) - 1] == '/');
914 artifact_loc_obj
->set_string ("uri", pwd
);
918 return artifact_loc_obj
;
921 /* Get the column number within EXPLOC. */
924 sarif_builder::get_sarif_column (expanded_location exploc
) const
926 cpp_char_column_policy
policy (m_tabstop
, cpp_wcwidth
);
927 return location_compute_display_column (m_context
->get_file_cache (),
931 /* Make a region object (SARIF v2.1.0 section 3.30) for LOC,
935 sarif_builder::maybe_make_region_object (location_t loc
) const
937 location_t caret_loc
= get_pure_location (loc
);
939 if (caret_loc
<= BUILTINS_LOCATION
)
942 location_t start_loc
= get_start (loc
);
943 location_t finish_loc
= get_finish (loc
);
945 expanded_location exploc_caret
= expand_location (caret_loc
);
946 expanded_location exploc_start
= expand_location (start_loc
);
947 expanded_location exploc_finish
= expand_location (finish_loc
);
949 if (exploc_start
.file
!=exploc_caret
.file
)
951 if (exploc_finish
.file
!=exploc_caret
.file
)
954 json::object
*region_obj
= new json::object ();
956 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
957 region_obj
->set_integer ("startLine", exploc_start
.line
);
959 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
960 region_obj
->set_integer ("startColumn", get_sarif_column (exploc_start
));
962 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
963 if (exploc_finish
.line
!= exploc_start
.line
)
964 region_obj
->set_integer ("endLine", exploc_finish
.line
);
966 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
967 This expresses the column immediately beyond the range. */
969 int next_column
= sarif_builder::get_sarif_column (exploc_finish
) + 1;
970 region_obj
->set_integer ("endColumn", next_column
);
976 /* Make a region object (SARIF v2.1.0 section 3.30) for the "contextRegion"
977 property (SARIF v2.1.0 section 3.29.5) of a physicalLocation.
979 This is similar to maybe_make_region_object, but ignores column numbers,
980 covering the line(s) as a whole, and including a "snippet" property
981 embedding those source lines, making it easier for consumers to show
982 the pertinent source. */
985 sarif_builder::maybe_make_region_object_for_context (location_t loc
) const
987 location_t caret_loc
= get_pure_location (loc
);
989 if (caret_loc
<= BUILTINS_LOCATION
)
992 location_t start_loc
= get_start (loc
);
993 location_t finish_loc
= get_finish (loc
);
995 expanded_location exploc_caret
= expand_location (caret_loc
);
996 expanded_location exploc_start
= expand_location (start_loc
);
997 expanded_location exploc_finish
= expand_location (finish_loc
);
999 if (exploc_start
.file
!=exploc_caret
.file
)
1001 if (exploc_finish
.file
!=exploc_caret
.file
)
1004 json::object
*region_obj
= new json::object ();
1006 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
1007 region_obj
->set_integer ("startLine", exploc_start
.line
);
1009 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
1010 if (exploc_finish
.line
!= exploc_start
.line
)
1011 region_obj
->set_integer ("endLine", exploc_finish
.line
);
1013 /* "snippet" property (SARIF v2.1.0 section 3.30.13). */
1014 if (json::object
*artifact_content_obj
1015 = maybe_make_artifact_content_object (exploc_start
.file
,
1017 exploc_finish
.line
))
1018 region_obj
->set ("snippet", artifact_content_obj
);
1023 /* Make a region object (SARIF v2.1.0 section 3.30) for the deletion region
1024 of HINT (as per SARIF v2.1.0 section 3.57.3). */
1027 sarif_builder::make_region_object_for_hint (const fixit_hint
&hint
) const
1029 location_t start_loc
= hint
.get_start_loc ();
1030 location_t next_loc
= hint
.get_next_loc ();
1032 expanded_location exploc_start
= expand_location (start_loc
);
1033 expanded_location exploc_next
= expand_location (next_loc
);
1035 json::object
*region_obj
= new json::object ();
1037 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
1038 region_obj
->set_integer ("startLine", exploc_start
.line
);
1040 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
1041 int start_col
= get_sarif_column (exploc_start
);
1042 region_obj
->set_integer ("startColumn", start_col
);
1044 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
1045 if (exploc_next
.line
!= exploc_start
.line
)
1046 region_obj
->set_integer ("endLine", exploc_next
.line
);
1048 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
1049 This expresses the column immediately beyond the range. */
1050 int next_col
= get_sarif_column (exploc_next
);
1051 region_obj
->set_integer ("endColumn", next_col
);
1056 /* Attempt to get a string for a logicalLocation's "kind" property
1057 (SARIF v2.1.0 section 3.33.7).
1058 Return NULL if unknown. */
1061 maybe_get_sarif_kind (enum logical_location_kind kind
)
1067 case LOGICAL_LOCATION_KIND_UNKNOWN
:
1070 case LOGICAL_LOCATION_KIND_FUNCTION
:
1072 case LOGICAL_LOCATION_KIND_MEMBER
:
1074 case LOGICAL_LOCATION_KIND_MODULE
:
1076 case LOGICAL_LOCATION_KIND_NAMESPACE
:
1078 case LOGICAL_LOCATION_KIND_TYPE
:
1080 case LOGICAL_LOCATION_KIND_RETURN_TYPE
:
1081 return "returnType";
1082 case LOGICAL_LOCATION_KIND_PARAMETER
:
1084 case LOGICAL_LOCATION_KIND_VARIABLE
:
1089 /* Make a logicalLocation object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC,
1093 make_sarif_logical_location_object (const logical_location
&logical_loc
)
1095 json::object
*logical_loc_obj
= new json::object ();
1097 /* "name" property (SARIF v2.1.0 section 3.33.4). */
1098 if (const char *short_name
= logical_loc
.get_short_name ())
1099 logical_loc_obj
->set_string ("name", short_name
);
1101 /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
1102 if (const char *name_with_scope
= logical_loc
.get_name_with_scope ())
1103 logical_loc_obj
->set_string ("fullyQualifiedName", name_with_scope
);
1105 /* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
1106 if (const char *internal_name
= logical_loc
.get_internal_name ())
1107 logical_loc_obj
->set_string ("decoratedName", internal_name
);
1109 /* "kind" property (SARIF v2.1.0 section 3.33.7). */
1110 enum logical_location_kind kind
= logical_loc
.get_kind ();
1111 if (const char *sarif_kind_str
= maybe_get_sarif_kind (kind
))
1112 logical_loc_obj
->set_string ("kind", sarif_kind_str
);
1114 return logical_loc_obj
;
1117 /* Make a codeFlow object (SARIF v2.1.0 section 3.36) for PATH. */
1120 sarif_builder::make_code_flow_object (const diagnostic_path
&path
)
1122 json::object
*code_flow_obj
= new json::object ();
1124 /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
1125 json::array
*thread_flows_arr
= new json::array ();
1127 /* Walk the events, consolidating into per-thread threadFlow objects,
1128 using the index with PATH as the overall executionOrder. */
1129 hash_map
<int_hash
<diagnostic_thread_id_t
, -1, -2>,
1130 sarif_thread_flow
*> thread_id_map
;
1131 for (unsigned i
= 0; i
< path
.num_events (); i
++)
1133 const diagnostic_event
&event
= path
.get_event (i
);
1134 const diagnostic_thread_id_t thread_id
= event
.get_thread_id ();
1135 sarif_thread_flow
*thread_flow_obj
;
1137 if (sarif_thread_flow
**slot
= thread_id_map
.get (thread_id
))
1138 thread_flow_obj
= *slot
;
1141 const diagnostic_thread
&thread
= path
.get_thread (thread_id
);
1142 thread_flow_obj
= new sarif_thread_flow (thread
);
1143 thread_flows_arr
->append (thread_flow_obj
);
1144 thread_id_map
.put (thread_id
, thread_flow_obj
);
1147 /* Add event to thread's threadFlow object. */
1148 json::object
*thread_flow_loc_obj
1149 = make_thread_flow_location_object (event
, i
);
1150 thread_flow_obj
->add_location (thread_flow_loc_obj
);
1152 code_flow_obj
->set ("threadFlows", thread_flows_arr
);
1154 return code_flow_obj
;
1157 /* Make a threadFlowLocation object (SARIF v2.1.0 section 3.38) for EVENT. */
1160 sarif_builder::make_thread_flow_location_object (const diagnostic_event
&ev
,
1163 sarif_object
*thread_flow_loc_obj
= new sarif_object ();
1165 /* Give diagnostic_event subclasses a chance to add custom properties
1166 via a property bag. */
1167 ev
.maybe_add_sarif_properties (*thread_flow_loc_obj
);
1169 /* "location" property (SARIF v2.1.0 section 3.38.3). */
1170 json::object
*location_obj
= make_location_object (ev
);
1171 thread_flow_loc_obj
->set ("location", location_obj
);
1173 /* "kinds" property (SARIF v2.1.0 section 3.38.8). */
1174 diagnostic_event::meaning m
= ev
.get_meaning ();
1175 if (json::array
*kinds_arr
= maybe_make_kinds_array (m
))
1176 thread_flow_loc_obj
->set ("kinds", kinds_arr
);
1178 /* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */
1179 thread_flow_loc_obj
->set_integer ("nestingLevel", ev
.get_stack_depth ());
1181 /* "executionOrder" property (SARIF v2.1.0 3.38.11).
1182 Offset by 1 to match the human-readable values emitted by %@. */
1183 thread_flow_loc_obj
->set_integer ("executionOrder", path_event_idx
+ 1);
1185 /* It might be nice to eventually implement the following for -fanalyzer:
1186 - the "stack" property (SARIF v2.1.0 section 3.38.5)
1187 - the "state" property (SARIF v2.1.0 section 3.38.9)
1188 - the "importance" property (SARIF v2.1.0 section 3.38.13). */
1190 return thread_flow_loc_obj
;
1193 /* If M has any known meaning, make a json array suitable for the "kinds"
1194 property of a threadFlowLocation object (SARIF v2.1.0 section 3.38.8).
1196 Otherwise, return NULL. */
1199 sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m
) const
1201 if (m
.m_verb
== diagnostic_event::VERB_unknown
1202 && m
.m_noun
== diagnostic_event::NOUN_unknown
1203 && m
.m_property
== diagnostic_event::PROPERTY_unknown
)
1206 json::array
*kinds_arr
= new json::array ();
1207 if (const char *verb_str
1208 = diagnostic_event::meaning::maybe_get_verb_str (m
.m_verb
))
1209 kinds_arr
->append (new json::string (verb_str
));
1210 if (const char *noun_str
1211 = diagnostic_event::meaning::maybe_get_noun_str (m
.m_noun
))
1212 kinds_arr
->append (new json::string (noun_str
));
1213 if (const char *property_str
1214 = diagnostic_event::meaning::maybe_get_property_str (m
.m_property
))
1215 kinds_arr
->append (new json::string (property_str
));
1219 /* Make a message object (SARIF v2.1.0 section 3.11) for MSG. */
1222 sarif_builder::make_message_object (const char *msg
) const
1224 json::object
*message_obj
= new json::object ();
1226 /* "text" property (SARIF v2.1.0 section 3.11.8). */
1227 message_obj
->set_string ("text", msg
);
1232 /* Make a message object (SARIF v2.1.0 section 3.11) for DIAGRAM.
1233 We emit the diagram as a code block within the Markdown part
1237 sarif_builder::make_message_object_for_diagram (diagnostic_context
*context
,
1238 const diagnostic_diagram
&diagram
)
1240 json::object
*message_obj
= new json::object ();
1242 /* "text" property (SARIF v2.1.0 section 3.11.8). */
1243 message_obj
->set_string ("text", diagram
.get_alt_text ());
1245 char *saved_prefix
= pp_take_prefix (context
->printer
);
1246 pp_set_prefix (context
->printer
, NULL
);
1248 /* "To produce a code block in Markdown, simply indent every line of
1249 the block by at least 4 spaces or 1 tab."
1250 Here we use 4 spaces. */
1251 diagram
.get_canvas ().print_to_pp (context
->printer
, " ");
1252 pp_set_prefix (context
->printer
, saved_prefix
);
1254 /* "markdown" property (SARIF v2.1.0 section 3.11.9). */
1255 message_obj
->set_string ("markdown", pp_formatted_text (context
->printer
));
1257 pp_clear_output_area (context
->printer
);
1262 /* Make a multiformatMessageString object (SARIF v2.1.0 section 3.12)
1266 sarif_builder::make_multiformat_message_string (const char *msg
) const
1268 json::object
*message_obj
= new json::object ();
1270 /* "text" property (SARIF v2.1.0 section 3.12.3). */
1271 message_obj
->set_string ("text", msg
);
1276 #define SARIF_SCHEMA "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"
1277 #define SARIF_VERSION "2.1.0"
1279 /* Make a top-level sarifLog object (SARIF v2.1.0 section 3.13).
1280 Take ownership of INVOCATION_OBJ and RESULTS. */
1283 sarif_builder::make_top_level_object (sarif_invocation
*invocation_obj
,
1284 json::array
*results
)
1286 json::object
*log_obj
= new json::object ();
1288 /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */
1289 log_obj
->set_string ("$schema", SARIF_SCHEMA
);
1291 /* "version" property (SARIF v2.1.0 section 3.13.2). */
1292 log_obj
->set_string ("version", SARIF_VERSION
);
1294 /* "runs" property (SARIF v2.1.0 section 3.13.4). */
1295 json::array
*run_arr
= new json::array ();
1296 json::object
*run_obj
= make_run_object (invocation_obj
, results
);
1297 run_arr
->append (run_obj
);
1298 log_obj
->set ("runs", run_arr
);
1303 /* Make a run object (SARIF v2.1.0 section 3.14).
1304 Take ownership of INVOCATION_OBJ and RESULTS. */
1307 sarif_builder::make_run_object (sarif_invocation
*invocation_obj
,
1308 json::array
*results
)
1310 json::object
*run_obj
= new json::object ();
1312 /* "tool" property (SARIF v2.1.0 section 3.14.6). */
1313 json::object
*tool_obj
= make_tool_object ();
1314 run_obj
->set ("tool", tool_obj
);
1316 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1317 if (json::array
*taxonomies_arr
= maybe_make_taxonomies_array ())
1318 run_obj
->set ("taxonomies", taxonomies_arr
);
1320 /* "invocations" property (SARIF v2.1.0 section 3.14.11). */
1322 json::array
*invocations_arr
= new json::array ();
1323 invocations_arr
->append (invocation_obj
);
1324 run_obj
->set ("invocations", invocations_arr
);
1327 /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */
1328 if (m_seen_any_relative_paths
)
1330 json::object
*orig_uri_base_ids
= new json::object ();
1331 run_obj
->set ("originalUriBaseIds", orig_uri_base_ids
);
1332 json::object
*pwd_art_loc_obj
= make_artifact_location_object_for_pwd ();
1333 orig_uri_base_ids
->set (PWD_PROPERTY_NAME
, pwd_art_loc_obj
);
1336 /* "artifacts" property (SARIF v2.1.0 section 3.14.15). */
1337 json::array
*artifacts_arr
= new json::array ();
1338 for (auto iter
: m_filenames
)
1340 json::object
*artifact_obj
= make_artifact_object (iter
);
1341 artifacts_arr
->append (artifact_obj
);
1343 run_obj
->set ("artifacts", artifacts_arr
);
1345 /* "results" property (SARIF v2.1.0 section 3.14.23). */
1346 run_obj
->set ("results", results
);
1351 /* Make a tool object (SARIF v2.1.0 section 3.18). */
1354 sarif_builder::make_tool_object () const
1356 json::object
*tool_obj
= new json::object ();
1358 /* "driver" property (SARIF v2.1.0 section 3.18.2). */
1359 json::object
*driver_obj
= make_driver_tool_component_object ();
1360 tool_obj
->set ("driver", driver_obj
);
1362 /* Report plugins via the "extensions" property
1363 (SARIF v2.1.0 section 3.18.3). */
1364 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
1365 if (const client_version_info
*vinfo
1366 = client_data_hooks
->get_any_version_info ())
1368 class my_plugin_visitor
: public client_version_info :: plugin_visitor
1371 void on_plugin (const diagnostic_client_plugin_info
&p
) final override
1373 /* Create a toolComponent object (SARIF v2.1.0 section 3.19)
1375 json::object
*plugin_obj
= new json::object ();
1376 m_plugin_objs
.safe_push (plugin_obj
);
1378 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1379 if (const char *short_name
= p
.get_short_name ())
1380 plugin_obj
->set_string ("name", short_name
);
1382 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1383 if (const char *full_name
= p
.get_full_name ())
1384 plugin_obj
->set_string ("fullName", full_name
);
1386 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1387 if (const char *version
= p
.get_version ())
1388 plugin_obj
->set_string ("version", version
);
1390 auto_vec
<json::object
*> m_plugin_objs
;
1392 my_plugin_visitor v
;
1393 vinfo
->for_each_plugin (v
);
1394 if (v
.m_plugin_objs
.length () > 0)
1396 json::array
*extensions_arr
= new json::array ();
1397 tool_obj
->set ("extensions", extensions_arr
);
1398 for (auto iter
: v
.m_plugin_objs
)
1399 extensions_arr
->append (iter
);
1403 /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other
1404 "extensions" (see toplev.cc: print_version). */
1409 /* Make a toolComponent object (SARIF v2.1.0 section 3.19) for what SARIF
1410 calls the "driver" (see SARIF v2.1.0 section 3.18.1). */
1413 sarif_builder::make_driver_tool_component_object () const
1415 json::object
*driver_obj
= new json::object ();
1417 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
1418 if (const client_version_info
*vinfo
1419 = client_data_hooks
->get_any_version_info ())
1421 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1422 if (const char *name
= vinfo
->get_tool_name ())
1423 driver_obj
->set_string ("name", name
);
1425 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1426 if (char *full_name
= vinfo
->maybe_make_full_name ())
1428 driver_obj
->set_string ("fullName", full_name
);
1432 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1433 if (const char *version
= vinfo
->get_version_string ())
1434 driver_obj
->set_string ("version", version
);
1436 /* "informationUri" property (SARIF v2.1.0 section 3.19.17). */
1437 if (char *version_url
= vinfo
->maybe_make_version_url ())
1439 driver_obj
->set_string ("informationUri", version_url
);
1444 /* "rules" property (SARIF v2.1.0 section 3.19.23). */
1445 driver_obj
->set ("rules", m_rules_arr
);
1450 /* If we've seen any CWE IDs, make an array for the "taxonomies" property
1451 (SARIF v2.1.0 section 3.14.8) of a run object, containting a singl
1452 toolComponent (3.19) as per 3.19.3, representing the CWE.
1454 Otherwise return NULL. */
1457 sarif_builder::maybe_make_taxonomies_array () const
1459 json::object
*cwe_obj
= maybe_make_cwe_taxonomy_object ();
1463 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1464 json::array
*taxonomies_arr
= new json::array ();
1465 taxonomies_arr
->append (cwe_obj
);
1466 return taxonomies_arr
;
1469 /* If we've seen any CWE IDs, make a toolComponent object
1470 (SARIF v2.1.0 section 3.19) representing the CWE taxonomy, as per 3.19.3.
1471 Populate the "taxa" property with all of the CWE IDs in m_cwe_id_set.
1473 Otherwise return NULL. */
1476 sarif_builder::maybe_make_cwe_taxonomy_object () const
1478 if (m_cwe_id_set
.is_empty ())
1481 json::object
*taxonomy_obj
= new json::object ();
1483 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1484 taxonomy_obj
->set_string ("name", "CWE");
1486 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1487 taxonomy_obj
->set_string ("version", "4.7");
1489 /* "organization" property (SARIF v2.1.0 section 3.19.18). */
1490 taxonomy_obj
->set_string ("organization", "MITRE");
1492 /* "shortDescription" property (SARIF v2.1.0 section 3.19.19). */
1493 json::object
*short_desc
1494 = make_multiformat_message_string ("The MITRE"
1495 " Common Weakness Enumeration");
1496 taxonomy_obj
->set ("shortDescription", short_desc
);
1498 /* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */
1499 json::array
*taxa_arr
= new json::array ();
1500 for (auto cwe_id
: m_cwe_id_set
)
1502 json::object
*cwe_taxon
1503 = make_reporting_descriptor_object_for_cwe_id (cwe_id
);
1504 taxa_arr
->append (cwe_taxon
);
1506 taxonomy_obj
->set ("taxa", taxa_arr
);
1508 return taxonomy_obj
;
1511 /* Make an artifact object (SARIF v2.1.0 section 3.24). */
1514 sarif_builder::make_artifact_object (const char *filename
)
1516 json::object
*artifact_obj
= new json::object ();
1518 /* "location" property (SARIF v2.1.0 section 3.24.2). */
1519 json::object
*artifact_loc_obj
= make_artifact_location_object (filename
);
1520 artifact_obj
->set ("location", artifact_loc_obj
);
1522 /* "contents" property (SARIF v2.1.0 section 3.24.8). */
1523 if (json::object
*artifact_content_obj
1524 = maybe_make_artifact_content_object (filename
))
1525 artifact_obj
->set ("contents", artifact_content_obj
);
1527 /* "sourceLanguage" property (SARIF v2.1.0 section 3.24.10). */
1528 if (auto client_data_hooks
= m_context
->get_client_data_hooks ())
1529 if (const char *source_lang
1530 = client_data_hooks
->maybe_get_sarif_source_language (filename
))
1531 artifact_obj
->set_string ("sourceLanguage", source_lang
);
1533 return artifact_obj
;
1536 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the
1537 full contents of FILENAME. */
1540 sarif_builder::maybe_make_artifact_content_object (const char *filename
) const
1542 /* Let input.cc handle any charset conversion. */
1543 char_span utf8_content
1544 = m_context
->get_file_cache ().get_source_file_content (filename
);
1548 /* Don't add it if it's not valid UTF-8. */
1549 if (!cpp_valid_utf8_p(utf8_content
.get_buffer (), utf8_content
.length ()))
1552 json::object
*artifact_content_obj
= new json::object ();
1553 artifact_content_obj
->set ("text",
1554 new json::string (utf8_content
.get_buffer (),
1555 utf8_content
.length ()));
1556 return artifact_content_obj
;
1559 /* Attempt to read the given range of lines from FILENAME; return
1560 a freshly-allocated 0-terminated buffer containing them, or NULL. */
1563 sarif_builder::get_source_lines (const char *filename
,
1567 auto_vec
<char> result
;
1569 for (int line
= start_line
; line
<= end_line
; line
++)
1571 char_span line_content
1572 = m_context
->get_file_cache ().get_source_line (filename
, line
);
1573 if (!line_content
.get_buffer ())
1575 result
.reserve (line_content
.length () + 1);
1576 for (size_t i
= 0; i
< line_content
.length (); i
++)
1577 result
.quick_push (line_content
[i
]);
1578 result
.quick_push ('\n');
1580 result
.safe_push ('\0');
1582 return xstrdup (result
.address ());
1585 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the given
1586 run of lines within FILENAME (including the endpoints). */
1589 sarif_builder::maybe_make_artifact_content_object (const char *filename
,
1593 char *text_utf8
= get_source_lines (filename
, start_line
, end_line
);
1598 /* Don't add it if it's not valid UTF-8. */
1599 if (!cpp_valid_utf8_p(text_utf8
, strlen(text_utf8
)))
1605 json::object
*artifact_content_obj
= new json::object ();
1606 artifact_content_obj
->set_string ("text", text_utf8
);
1609 return artifact_content_obj
;
1612 /* Make a fix object (SARIF v2.1.0 section 3.55) for RICHLOC. */
1615 sarif_builder::make_fix_object (const rich_location
&richloc
)
1617 json::object
*fix_obj
= new json::object ();
1619 /* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */
1620 /* We assume that all fix-it hints in RICHLOC affect the same file. */
1621 json::array
*artifact_change_arr
= new json::array ();
1622 json::object
*artifact_change_obj
= make_artifact_change_object (richloc
);
1623 artifact_change_arr
->append (artifact_change_obj
);
1624 fix_obj
->set ("artifactChanges", artifact_change_arr
);
1629 /* Make an artifactChange object (SARIF v2.1.0 section 3.56) for RICHLOC. */
1632 sarif_builder::make_artifact_change_object (const rich_location
&richloc
)
1634 json::object
*artifact_change_obj
= new json::object ();
1636 /* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */
1637 json::object
*artifact_location_obj
1638 = make_artifact_location_object (richloc
.get_loc ());
1639 artifact_change_obj
->set ("artifactLocation", artifact_location_obj
);
1641 /* "replacements" property (SARIF v2.1.0 section 3.56.3). */
1642 json::array
*replacement_arr
= new json::array ();
1643 for (unsigned int i
= 0; i
< richloc
.get_num_fixit_hints (); i
++)
1645 const fixit_hint
*hint
= richloc
.get_fixit_hint (i
);
1646 json::object
*replacement_obj
= make_replacement_object (*hint
);
1647 replacement_arr
->append (replacement_obj
);
1649 artifact_change_obj
->set ("replacements", replacement_arr
);
1651 return artifact_change_obj
;
1654 /* Make a replacement object (SARIF v2.1.0 section 3.57) for HINT. */
1657 sarif_builder::make_replacement_object (const fixit_hint
&hint
) const
1659 json::object
*replacement_obj
= new json::object ();
1661 /* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */
1662 json::object
*region_obj
= make_region_object_for_hint (hint
);
1663 replacement_obj
->set ("deletedRegion", region_obj
);
1665 /* "insertedContent" property (SARIF v2.1.0 section 3.57.4). */
1666 json::object
*content_obj
= make_artifact_content_object (hint
.get_string ());
1667 replacement_obj
->set ("insertedContent", content_obj
);
1669 return replacement_obj
;
1672 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for TEXT. */
1675 sarif_builder::make_artifact_content_object (const char *text
) const
1677 json::object
*content_obj
= new json::object ();
1679 /* "text" property (SARIF v2.1.0 section 3.3.2). */
1680 content_obj
->set_string ("text", text
);
1685 /* Callback for diagnostic_context::ice_handler_cb for when an ICE
1689 sarif_ice_handler (diagnostic_context
*context
)
1691 /* Attempt to ensure that a .sarif file is written out. */
1692 diagnostic_finish (context
);
1694 /* Print a header for the remaining output to stderr, and
1695 return, attempting to print the usual ICE messages to
1696 stderr. Hopefully this will be helpful to the user in
1697 indicating what's gone wrong (also for DejaGnu, for pruning
1699 fnotice (stderr
, "Internal compiler error:\n");
1702 class sarif_output_format
: public diagnostic_output_format
1705 void on_begin_group () final override
1709 void on_end_group () final override
1711 m_builder
.end_group ();
1714 on_begin_diagnostic (const diagnostic_info
&) final override
1719 on_end_diagnostic (const diagnostic_info
&diagnostic
,
1720 diagnostic_t orig_diag_kind
) final override
1722 m_builder
.end_diagnostic (&m_context
, diagnostic
, orig_diag_kind
);
1724 void on_diagram (const diagnostic_diagram
&diagram
) final override
1726 m_builder
.emit_diagram (&m_context
, diagram
);
1730 sarif_output_format (diagnostic_context
&context
,
1732 : diagnostic_output_format (context
),
1733 m_builder (&context
, formatted
)
1736 sarif_builder m_builder
;
1739 class sarif_stream_output_format
: public sarif_output_format
1742 sarif_stream_output_format (diagnostic_context
&context
,
1745 : sarif_output_format (context
, formatted
),
1749 ~sarif_stream_output_format ()
1751 m_builder
.flush_to_file (m_stream
);
1757 class sarif_file_output_format
: public sarif_output_format
1760 sarif_file_output_format (diagnostic_context
&context
,
1762 const char *base_file_name
)
1763 : sarif_output_format (context
, formatted
),
1764 m_base_file_name (xstrdup (base_file_name
))
1767 ~sarif_file_output_format ()
1769 char *filename
= concat (m_base_file_name
, ".sarif", NULL
);
1770 free (m_base_file_name
);
1771 m_base_file_name
= nullptr;
1772 FILE *outf
= fopen (filename
, "w");
1775 const char *errstr
= xstrerror (errno
);
1776 fnotice (stderr
, "error: unable to open '%s' for writing: %s\n",
1781 m_builder
.flush_to_file (outf
);
1787 char *m_base_file_name
;
1790 /* Populate CONTEXT in preparation for SARIF output (either to stderr, or
1794 diagnostic_output_format_init_sarif (diagnostic_context
*context
)
1796 /* Override callbacks. */
1797 context
->m_print_path
= nullptr; /* handled in sarif_end_diagnostic. */
1798 context
->set_ice_handler_callback (sarif_ice_handler
);
1800 /* The metadata is handled in SARIF format, rather than as text. */
1801 context
->set_show_cwe (false);
1802 context
->set_show_rules (false);
1804 /* The option is handled in SARIF format, rather than as text. */
1805 context
->set_show_option_requested (false);
1807 /* Don't colorize the text. */
1808 pp_show_color (context
->printer
) = false;
1811 /* Populate CONTEXT in preparation for SARIF output to stderr. */
1814 diagnostic_output_format_init_sarif_stderr (diagnostic_context
*context
,
1817 diagnostic_output_format_init_sarif (context
);
1818 context
->set_output_format (new sarif_stream_output_format (*context
,
1823 /* Populate CONTEXT in preparation for SARIF output to a file named
1824 BASE_FILE_NAME.sarif. */
1827 diagnostic_output_format_init_sarif_file (diagnostic_context
*context
,
1829 const char *base_file_name
)
1831 diagnostic_output_format_init_sarif (context
);
1832 context
->set_output_format (new sarif_file_output_format (*context
,
1837 /* Populate CONTEXT in preparation for SARIF output to STREAM. */
1840 diagnostic_output_format_init_sarif_stream (diagnostic_context
*context
,
1844 diagnostic_output_format_init_sarif (context
);
1845 context
->set_output_format (new sarif_stream_output_format (*context
,