]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/diagnostic-format-sarif.cc
[PATCH v1 1/1] RISC-V: Nan-box the result of movbf on soft-bf16
[thirdparty/gcc.git] / gcc / diagnostic-format-sarif.cc
CommitLineData
6cf276dd 1/* SARIF output for diagnostics
a945c346 2 Copyright (C) 2018-2024 Free Software Foundation, Inc.
6cf276dd
DM
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21
22#include "config.h"
b2e075a5 23#define INCLUDE_VECTOR
6cf276dd
DM
24#include "system.h"
25#include "coretypes.h"
26#include "diagnostic.h"
27#include "diagnostic-metadata.h"
28#include "diagnostic-path.h"
29#include "json.h"
30#include "cpplib.h"
31#include "logical-location.h"
32#include "diagnostic-client-data-hooks.h"
4f01ae37
DM
33#include "diagnostic-diagram.h"
34#include "text-art/canvas.h"
75d62394 35#include "diagnostic-format-sarif.h"
6cf276dd
DM
36
37class sarif_builder;
38
79aaba0a
DM
39/* Subclass of json::object for SARIF invocation objects
40 (SARIF v2.1.0 section 3.20). */
41
75d62394 42class sarif_invocation : public sarif_object
79aaba0a
DM
43{
44public:
45 sarif_invocation ()
46 : m_notifications_arr (new json::array ()),
47 m_success (true)
48 {}
49
50 void add_notification_for_ice (diagnostic_context *context,
8fc4e6c3 51 const diagnostic_info &diagnostic,
79aaba0a 52 sarif_builder *builder);
75d62394 53 void prepare_to_flush (diagnostic_context *context);
79aaba0a
DM
54
55private:
56 json::array *m_notifications_arr;
57 bool m_success;
58};
59
75d62394 60/* Subclass of sarif_object for SARIF result objects
79aaba0a 61 (SARIF v2.1.0 section 3.27). */
6cf276dd 62
75d62394 63class sarif_result : public sarif_object
6cf276dd
DM
64{
65public:
66 sarif_result () : m_related_locations_arr (NULL) {}
67
68 void
69 on_nested_diagnostic (diagnostic_context *context,
8fc4e6c3 70 const diagnostic_info &diagnostic,
6cf276dd
DM
71 diagnostic_t orig_diag_kind,
72 sarif_builder *builder);
4f01ae37
DM
73 void on_diagram (diagnostic_context *context,
74 const diagnostic_diagram &diagram,
75 sarif_builder *builder);
6cf276dd
DM
76
77private:
4f01ae37
DM
78 void add_related_location (json::object *location_obj);
79
6cf276dd
DM
80 json::array *m_related_locations_arr;
81};
82
75d62394 83/* Subclass of sarif_object for SARIF notification objects
79aaba0a
DM
84 (SARIF v2.1.0 section 3.58).
85
86 This subclass is specifically for notifying when an
87 internal compiler error occurs. */
88
75d62394 89class sarif_ice_notification : public sarif_object
79aaba0a
DM
90{
91public:
92 sarif_ice_notification (diagnostic_context *context,
8fc4e6c3 93 const diagnostic_info &diagnostic,
79aaba0a
DM
94 sarif_builder *builder);
95};
96
3a1e9f3e
DM
97/* Subclass of sarif_object for SARIF threadFlow objects
98 (SARIF v2.1.0 section 3.37) for PATH. */
99
100class sarif_thread_flow : public sarif_object
101{
102public:
103 sarif_thread_flow (const diagnostic_thread &thread);
104
105 void add_location (json::object *thread_flow_loc_obj)
106 {
107 m_locations_arr->append (thread_flow_loc_obj);
108 }
109
110private:
111 json::array *m_locations_arr;
112};
113
6cf276dd
DM
114/* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
115 and -fdiagnostics-format=sarif-file).
116
117 As diagnostics occur, we build "result" JSON objects, and
118 accumulate state:
119 - which source files are referenced
120 - which warnings are emitted
121 - which CWEs are used
122
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
126 referenced.
127
128 Implemented:
129 - fix-it hints
130 - CWE metadata
131 - diagnostic groups (see limitations below)
132 - logical locations (e.g. cfun)
133
134 Known limitations:
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
145 section 3.27.22)
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?). */
156
157class sarif_builder
158{
159public:
3bd8241a
DM
160 sarif_builder (diagnostic_context *context,
161 bool formatted);
6cf276dd 162
8fc4e6c3
DM
163 void end_diagnostic (diagnostic_context *context,
164 const diagnostic_info &diagnostic,
6cf276dd 165 diagnostic_t orig_diag_kind);
4f01ae37
DM
166 void emit_diagram (diagnostic_context *context,
167 const diagnostic_diagram &diagram);
6cf276dd
DM
168 void end_group ();
169
170 void flush_to_file (FILE *outf);
171
8fc4e6c3 172 json::array *make_locations_arr (const diagnostic_info &diagnostic);
6cf276dd
DM
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;
4f01ae37
DM
176 json::object *
177 make_message_object_for_diagram (diagnostic_context *context,
178 const diagnostic_diagram &diagram);
6cf276dd
DM
179
180private:
181 sarif_result *make_result_object (diagnostic_context *context,
8fc4e6c3 182 const diagnostic_info &diagnostic,
6cf276dd
DM
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);
6cf276dd 187 json::object *make_code_flow_object (const diagnostic_path &path);
6cf276dd 188 json::object *
3a1e9f3e
DM
189 make_thread_flow_location_object (const diagnostic_event &event,
190 int path_event_idx);
6cf276dd
DM
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;
79aaba0a
DM
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);
6cf276dd
DM
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;
209 json::object *
210 make_reporting_descriptor_object_for_warning (diagnostic_context *context,
8fc4e6c3 211 const diagnostic_info &diagnostic,
6cf276dd
DM
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;
215 json::object *
216 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id);
217 json::object *make_artifact_object (const char *filename);
14082026
DM
218 char *get_source_lines (const char *filename,
219 int start_line,
220 int end_line) const;
6cf276dd
DM
221 json::object *maybe_make_artifact_content_object (const char *filename) const;
222 json::object *maybe_make_artifact_content_object (const char *filename,
223 int start_line,
224 int end_line) const;
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;
230
231 diagnostic_context *m_context;
232
79aaba0a
DM
233 /* The JSON object for the invocation object. */
234 sarif_invocation *m_invocation_obj;
235
6cf276dd
DM
236 /* The JSON array of pending diagnostics. */
237 json::array *m_results_array;
238
239 /* The JSON object for the result object (if any) in the current
240 diagnostic group. */
241 sarif_result *m_cur_group_result;
242
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;
247
248 /* The set of all CWE IDs we've seen, if any. */
249 hash_set <int_hash <int, 0, 1> > m_cwe_id_set;
250
251 int m_tabstop;
3bd8241a
DM
252
253 bool m_formatted;
6cf276dd
DM
254};
255
75d62394
DM
256/* class sarif_object : public json::object. */
257
258sarif_property_bag &
259sarif_object::get_or_create_properties ()
260{
261 json::value *properties_val = get ("properties");
262 if (properties_val)
263 {
264 if (properties_val->get_kind () == json::JSON_OBJECT)
265 return *static_cast <sarif_property_bag *> (properties_val);
266 }
267
268 sarif_property_bag *bag = new sarif_property_bag ();
269 set ("properties", bag);
270 return *bag;
271}
272
273/* class sarif_invocation : public sarif_object. */
79aaba0a
DM
274
275/* Handle an internal compiler error DIAGNOSTIC occurring on CONTEXT.
276 Add an object representing the ICE to the notifications array. */
277
278void
279sarif_invocation::add_notification_for_ice (diagnostic_context *context,
8fc4e6c3 280 const diagnostic_info &diagnostic,
79aaba0a
DM
281 sarif_builder *builder)
282{
283 m_success = false;
284
285 sarif_ice_notification *notification_obj
286 = new sarif_ice_notification (context, diagnostic, builder);
287 m_notifications_arr->append (notification_obj);
288}
289
290void
75d62394 291sarif_invocation::prepare_to_flush (diagnostic_context *context)
79aaba0a
DM
292{
293 /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */
070944fd 294 set_bool ("executionSuccessful", m_success);
79aaba0a
DM
295
296 /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */
297 set ("toolExecutionNotifications", m_notifications_arr);
75d62394
DM
298
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. */
8200cd97
DM
301 if (auto client_data_hooks = context->get_client_data_hooks ())
302 client_data_hooks->add_sarif_invocation_properties (*this);
79aaba0a
DM
303}
304
75d62394 305/* class sarif_result : public sarif_object. */
6cf276dd
DM
306
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). */
312
313void
314sarif_result::on_nested_diagnostic (diagnostic_context *context,
8fc4e6c3 315 const diagnostic_info &diagnostic,
6cf276dd
DM
316 diagnostic_t /*orig_diag_kind*/,
317 sarif_builder *builder)
318{
6cf276dd
DM
319 /* We don't yet generate meaningful logical locations for notes;
320 sometimes these will related to current_function_decl, but
321 often they won't. */
322 json::object *location_obj
8fc4e6c3 323 = builder->make_location_object (*diagnostic.richloc, NULL);
6cf276dd
DM
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);
328
4f01ae37
DM
329 add_related_location (location_obj);
330}
331
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). */
337
338void
339sarif_result::on_diagram (diagnostic_context *context,
340 const diagnostic_diagram &diagram,
341 sarif_builder *builder)
342{
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);
347
348 add_related_location (location_obj);
349}
350
351/* Add LOCATION_OBJ to this result's "relatedLocations" array,
352 creating it if it doesn't yet exist. */
353
354void
355sarif_result::add_related_location (json::object *location_obj)
356{
357 if (!m_related_locations_arr)
358 {
359 m_related_locations_arr = new json::array ();
360 set ("relatedLocations", m_related_locations_arr);
361 }
6cf276dd
DM
362 m_related_locations_arr->append (location_obj);
363}
364
75d62394 365/* class sarif_ice_notification : public sarif_object. */
79aaba0a
DM
366
367/* sarif_ice_notification's ctor.
368 DIAGNOSTIC is an internal compiler error. */
369
370sarif_ice_notification::sarif_ice_notification (diagnostic_context *context,
8fc4e6c3 371 const diagnostic_info &diagnostic,
79aaba0a
DM
372 sarif_builder *builder)
373{
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);
377
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);
383
384 /* "level" property (SARIF v2.1.0 section 3.58.6). */
070944fd 385 set_string ("level", "error");
79aaba0a
DM
386}
387
3a1e9f3e
DM
388/* class sarif_thread_flow : public sarif_object. */
389
390sarif_thread_flow::sarif_thread_flow (const diagnostic_thread &thread)
391{
392 /* "id" property (SARIF v2.1.0 section 3.37.2). */
393 label_text name (thread.get_name (false));
070944fd 394 set_string ("id", name.get ());
3a1e9f3e
DM
395
396 /* "locations" property (SARIF v2.1.0 section 3.37.6). */
397 m_locations_arr = new json::array ();
398 set ("locations", m_locations_arr);
399}
400
6cf276dd
DM
401/* class sarif_builder. */
402
403/* sarif_builder's ctor. */
404
3bd8241a
DM
405sarif_builder::sarif_builder (diagnostic_context *context,
406 bool formatted)
6cf276dd 407: m_context (context),
79aaba0a 408 m_invocation_obj (new sarif_invocation ()),
6cf276dd
DM
409 m_results_array (new json::array ()),
410 m_cur_group_result (NULL),
411 m_seen_any_relative_paths (false),
412 m_rule_id_set (),
413 m_rules_arr (new json::array ()),
3bd8241a
DM
414 m_tabstop (context->m_tabstop),
415 m_formatted (formatted)
6cf276dd
DM
416{
417}
418
419/* Implementation of "end_diagnostic" for SARIF output. */
420
421void
422sarif_builder::end_diagnostic (diagnostic_context *context,
8fc4e6c3 423 const diagnostic_info &diagnostic,
6cf276dd
DM
424 diagnostic_t orig_diag_kind)
425{
8fc4e6c3 426 if (diagnostic.kind == DK_ICE || diagnostic.kind == DK_ICE_NOBT)
79aaba0a
DM
427 {
428 m_invocation_obj->add_notification_for_ice (context, diagnostic, this);
429 return;
430 }
6cf276dd
DM
431
432 if (m_cur_group_result)
433 /* Nested diagnostic. */
434 m_cur_group_result->on_nested_diagnostic (context,
435 diagnostic,
436 orig_diag_kind,
437 this);
438 else
439 {
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;
445 }
446}
447
4f01ae37
DM
448/* Implementation of diagnostic_context::m_diagrams.m_emission_cb
449 for SARIF output. */
450
451void
452sarif_builder::emit_diagram (diagnostic_context *context,
453 const diagnostic_diagram &diagram)
454{
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);
458}
459
6cf276dd
DM
460/* Implementation of "end_group_cb" for SARIF output. */
461
462void
463sarif_builder::end_group ()
464{
465 m_cur_group_result = NULL;
466}
467
468/* Create a top-level object, and add it to all the results
469 (and other entities) we've seen so far.
470
471 Flush it all to OUTF. */
472
473void
474sarif_builder::flush_to_file (FILE *outf)
475{
75d62394 476 m_invocation_obj->prepare_to_flush (m_context);
79aaba0a 477 json::object *top = make_top_level_object (m_invocation_obj, m_results_array);
3bd8241a 478 top->dump (outf, m_formatted);
79aaba0a 479 m_invocation_obj = NULL;
6cf276dd
DM
480 m_results_array = NULL;
481 fprintf (outf, "\n");
482 delete top;
483}
484
485/* Attempt to convert DIAG_KIND to a suitable value for the "level"
486 property (SARIF v2.1.0 section 3.27.10).
487
488 Return NULL if there isn't one. */
489
490static const char *
491maybe_get_sarif_level (diagnostic_t diag_kind)
492{
493 switch (diag_kind)
494 {
495 case DK_WARNING:
496 return "warning";
497 case DK_ERROR:
498 return "error";
499 case DK_NOTE:
500 case DK_ANACHRONISM:
501 return "note";
502 default:
503 return NULL;
504 }
505}
506
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. */
510
511static char *
512make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind)
513{
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
518 "must-not-happen"
519 };
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';
528 return rstrip;
529}
530
531/* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */
532
533sarif_result *
534sarif_builder::make_result_object (diagnostic_context *context,
8fc4e6c3 535 const diagnostic_info &diagnostic,
6cf276dd
DM
536 diagnostic_t orig_diag_kind)
537{
538 sarif_result *result_obj = new sarif_result ();
539
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
8fc4e6c3
DM
543 = context->make_option_name (diagnostic.option_index,
544 orig_diag_kind, diagnostic.kind))
6cf276dd
DM
545 {
546 /* Lazily create reportingDescriptor objects for and add to m_rules_arr.
547 Set ruleId referencing them. */
070944fd 548 result_obj->set_string ("ruleId", option_text);
6cf276dd
DM
549 if (m_rule_id_set.contains (option_text))
550 free (option_text);
551 else
552 {
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);
556
557 json::object *reporting_desc_obj
558 = make_reporting_descriptor_object_for_warning (context,
559 diagnostic,
560 orig_diag_kind,
561 option_text);
562 m_rules_arr->append (reporting_desc_obj);
563 }
564 }
565 else
566 {
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
569 has a ruleId.
570 We don't bother creating reportingDescriptor objects for these. */
571 char *rule_id = make_rule_id_for_diagnostic_kind (orig_diag_kind);
070944fd 572 result_obj->set_string ("ruleId", rule_id);
6cf276dd
DM
573 free (rule_id);
574 }
575
8fc4e6c3 576 if (diagnostic.metadata)
12b67d1e
DM
577 {
578 /* "taxa" property (SARIF v2.1.0 section 3.27.8). */
8fc4e6c3 579 if (int cwe_id = diagnostic.metadata->get_cwe ())
12b67d1e
DM
580 {
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);
586 }
587
8fc4e6c3 588 diagnostic.metadata->maybe_add_sarif_properties (*result_obj);
12b67d1e 589 }
6cf276dd
DM
590
591 /* "level" property (SARIF v2.1.0 section 3.27.10). */
8fc4e6c3 592 if (const char *sarif_level = maybe_get_sarif_level (diagnostic.kind))
070944fd 593 result_obj->set_string ("level", sarif_level);
6cf276dd
DM
594
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);
600
601 /* "locations" property (SARIF v2.1.0 section 3.27.12). */
79aaba0a 602 json::array *locations_arr = make_locations_arr (diagnostic);
6cf276dd
DM
603 result_obj->set ("locations", locations_arr);
604
605 /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
8fc4e6c3 606 if (const diagnostic_path *path = diagnostic.richloc->get_path ())
6cf276dd
DM
607 {
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);
612 }
613
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
616 group. */
617
618 /* "fixes" property (SARIF v2.1.0 section 3.27.30). */
8fc4e6c3 619 const rich_location *richloc = diagnostic.richloc;
6cf276dd
DM
620 if (richloc->get_num_fixit_hints ())
621 {
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);
626 }
627
628 return result_obj;
629}
630
631/* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
632 for a GCC warning. */
633
634json::object *
635sarif_builder::
636make_reporting_descriptor_object_for_warning (diagnostic_context *context,
8fc4e6c3 637 const diagnostic_info &diagnostic,
6cf276dd
DM
638 diagnostic_t /*orig_diag_kind*/,
639 const char *option_text)
640{
641 json::object *reporting_desc = new json::object ();
642
643 /* "id" property (SARIF v2.1.0 section 3.49.3). */
070944fd 644 reporting_desc->set_string ("id", option_text);
6cf276dd
DM
645
646 /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since
647 it seems redundant compared to "id". */
648
649 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
8fc4e6c3 650 if (char *option_url = context->make_option_url (diagnostic.option_index))
6cf276dd 651 {
353f146c
DM
652 reporting_desc->set_string ("helpUri", option_url);
653 free (option_url);
6cf276dd
DM
654 }
655
656 return reporting_desc;
657}
658
659/* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
660 for CWE_ID, for use within the CWE taxa array. */
661
662json::object *
663sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id) const
664{
665 json::object *reporting_desc = new json::object ();
666
667 /* "id" property (SARIF v2.1.0 section 3.49.3). */
668 {
669 pretty_printer pp;
670 pp_printf (&pp, "%i", cwe_id);
070944fd 671 reporting_desc->set_string ("id", pp_formatted_text (&pp));
6cf276dd
DM
672 }
673
674 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
675 {
676 char *url = get_cwe_url (cwe_id);
070944fd 677 reporting_desc->set_string ("helpUri", url);
6cf276dd
DM
678 free (url);
679 }
680
681 return reporting_desc;
682}
683
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. */
687
688json::object *
689sarif_builder::
690make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id)
691{
692 json::object *desc_ref_obj = new json::object ();
693
694 /* "id" property (SARIF v2.1.0 section 3.52.4). */
695 {
696 pretty_printer pp;
697 pp_printf (&pp, "%i", cwe_id);
070944fd 698 desc_ref_obj->set_string ("id", pp_formatted_text (&pp));
6cf276dd
DM
699 }
700
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);
704
705 /* Add CWE_ID to our set. */
706 gcc_assert (cwe_id > 0);
707 m_cwe_id_set.add (cwe_id);
708
709 return desc_ref_obj;
710}
711
712/* Make a toolComponentReference object (SARIF v2.1.0 section 3.54) that
713 references the CWE taxonomy. */
714
715json::object *
716sarif_builder::
717make_tool_component_reference_object_for_cwe () const
718{
719 json::object *comp_ref_obj = new json::object ();
720
721 /* "name" property (SARIF v2.1.0 section 3.54.3). */
070944fd 722 comp_ref_obj->set_string ("name", "cwe");
6cf276dd
DM
723
724 return comp_ref_obj;
725}
726
79aaba0a
DM
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). */
730
731json::array *
8fc4e6c3 732sarif_builder::make_locations_arr (const diagnostic_info &diagnostic)
79aaba0a
DM
733{
734 json::array *locations_arr = new json::array ();
735 const logical_location *logical_loc = NULL;
8200cd97
DM
736 if (auto client_data_hooks = m_context->get_client_data_hooks ())
737 logical_loc = client_data_hooks->get_current_logical_location ();
79aaba0a
DM
738
739 json::object *location_obj
8fc4e6c3 740 = make_location_object (*diagnostic.richloc, logical_loc);
79aaba0a
DM
741 locations_arr->append (location_obj);
742 return locations_arr;
743}
744
6cf276dd
DM
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). */
747
748void
749sarif_builder::
750set_any_logical_locs_arr (json::object *location_obj,
751 const logical_location *logical_loc)
752{
753 if (!logical_loc)
754 return;
05c99b1c 755 json::object *logical_loc_obj = make_sarif_logical_location_object (*logical_loc);
6cf276dd
DM
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);
759}
760
761/* Make a location object (SARIF v2.1.0 section 3.28) for RICH_LOC
762 and LOGICAL_LOC. */
763
764json::object *
765sarif_builder::make_location_object (const rich_location &rich_loc,
766 const logical_location *logical_loc)
767{
768 json::object *location_obj = new json::object ();
769
770 /* Get primary loc from RICH_LOC. */
771 location_t loc = rich_loc.get_loc ();
772
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);
776
777 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
778 set_any_logical_locs_arr (location_obj, logical_loc);
779
780 return location_obj;
781}
782
783/* Make a location object (SARIF v2.1.0 section 3.28) for EVENT
784 within a diagnostic_path. */
785
786json::object *
787sarif_builder::make_location_object (const diagnostic_event &event)
788{
789 json::object *location_obj = new json::object ();
790
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);
795
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);
799
800 /* "message" property (SARIF v2.1.0 section 3.28.5). */
801 label_text ev_desc = event.get_desc (false);
f858fe7a 802 json::object *message_obj = make_message_object (ev_desc.get ());
6cf276dd 803 location_obj->set ("message", message_obj);
6cf276dd
DM
804
805 return location_obj;
806}
807
808/* Make a physicalLocation object (SARIF v2.1.0 section 3.29) for LOC,
809 or return NULL;
810 Add any filename to the m_artifacts. */
811
812json::object *
813sarif_builder::maybe_make_physical_location_object (location_t loc)
814{
2e8a0553 815 if (loc <= BUILTINS_LOCATION || LOCATION_FILE (loc) == NULL)
6cf276dd
DM
816 return NULL;
817
818 json::object *phys_loc_obj = new json::object ();
819
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));
824
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);
828
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);
833
834 /* Instead, we add artifacts to the run as a whole,
835 with artifact.contents.
836 Could do both, though. */
837
838 return phys_loc_obj;
839}
840
841/* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for LOC,
842 or return NULL. */
843
844json::object *
845sarif_builder::make_artifact_location_object (location_t loc)
846{
847 return make_artifact_location_object (LOCATION_FILE (loc));
848}
849
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. */
852
853#define PWD_PROPERTY_NAME ("PWD")
854
855/* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for FILENAME,
856 or return NULL. */
857
858json::object *
859sarif_builder::make_artifact_location_object (const char *filename)
860{
861 json::object *artifact_loc_obj = new json::object ();
862
863 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
070944fd 864 artifact_loc_obj->set_string ("uri", filename);
6cf276dd
DM
865
866 if (filename[0] != '/')
867 {
868 /* If we have a relative path, set the "uriBaseId" property
869 (SARIF v2.1.0 section 3.4.4). */
070944fd 870 artifact_loc_obj->set_string ("uriBaseId", PWD_PROPERTY_NAME);
6cf276dd
DM
871 m_seen_any_relative_paths = true;
872 }
873
874 return artifact_loc_obj;
875}
876
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
879 section 3.14.14). */
880
881static char *
882make_pwd_uri_str ()
883{
884 /* The prefix of a file-based URI, up to, but not including the path. */
885#define FILE_PREFIX ("file://")
886
887 const char *pwd = getpwd ();
888 if (!pwd)
889 return NULL;
890 size_t len = strlen (pwd);
891 if (len == 0 || pwd[len - 1] != '/')
892 return concat (FILE_PREFIX, pwd, "/", NULL);
893 else
894 {
895 gcc_assert (pwd[len - 1] == '/');
896 return concat (FILE_PREFIX, pwd, NULL);
897 }
898}
899
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. */
903
904json::object *
905sarif_builder::make_artifact_location_object_for_pwd () const
906{
907 json::object *artifact_loc_obj = new json::object ();
908
909 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
910 if (char *pwd = make_pwd_uri_str ())
911 {
912 gcc_assert (strlen (pwd) > 0);
913 gcc_assert (pwd[strlen (pwd) - 1] == '/');
070944fd 914 artifact_loc_obj->set_string ("uri", pwd);
6cf276dd
DM
915 free (pwd);
916 }
917
918 return artifact_loc_obj;
919}
920
921/* Get the column number within EXPLOC. */
922
923int
924sarif_builder::get_sarif_column (expanded_location exploc) const
925{
926 cpp_char_column_policy policy (m_tabstop, cpp_wcwidth);
1bdd665a
DM
927 return location_compute_display_column (m_context->get_file_cache (),
928 exploc, policy);
6cf276dd
DM
929}
930
931/* Make a region object (SARIF v2.1.0 section 3.30) for LOC,
932 or return NULL. */
933
934json::object *
935sarif_builder::maybe_make_region_object (location_t loc) const
936{
937 location_t caret_loc = get_pure_location (loc);
938
939 if (caret_loc <= BUILTINS_LOCATION)
940 return NULL;
941
942 location_t start_loc = get_start (loc);
943 location_t finish_loc = get_finish (loc);
944
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);
948
949 if (exploc_start.file !=exploc_caret.file)
950 return NULL;
951 if (exploc_finish.file !=exploc_caret.file)
952 return NULL;
953
954 json::object *region_obj = new json::object ();
955
956 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
070944fd 957 region_obj->set_integer ("startLine", exploc_start.line);
6cf276dd
DM
958
959 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
070944fd 960 region_obj->set_integer ("startColumn", get_sarif_column (exploc_start));
6cf276dd
DM
961
962 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
963 if (exploc_finish.line != exploc_start.line)
070944fd 964 region_obj->set_integer ("endLine", exploc_finish.line);
6cf276dd
DM
965
966 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
967 This expresses the column immediately beyond the range. */
968 {
969 int next_column = sarif_builder::get_sarif_column (exploc_finish) + 1;
070944fd 970 region_obj->set_integer ("endColumn", next_column);
6cf276dd
DM
971 }
972
973 return region_obj;
974}
975
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.
978
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. */
983
984json::object *
985sarif_builder::maybe_make_region_object_for_context (location_t loc) const
986{
987 location_t caret_loc = get_pure_location (loc);
988
989 if (caret_loc <= BUILTINS_LOCATION)
990 return NULL;
991
992 location_t start_loc = get_start (loc);
993 location_t finish_loc = get_finish (loc);
994
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);
998
999 if (exploc_start.file !=exploc_caret.file)
1000 return NULL;
1001 if (exploc_finish.file !=exploc_caret.file)
1002 return NULL;
1003
1004 json::object *region_obj = new json::object ();
1005
1006 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
070944fd 1007 region_obj->set_integer ("startLine", exploc_start.line);
6cf276dd
DM
1008
1009 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
1010 if (exploc_finish.line != exploc_start.line)
070944fd 1011 region_obj->set_integer ("endLine", exploc_finish.line);
6cf276dd
DM
1012
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,
1016 exploc_start.line,
1017 exploc_finish.line))
1018 region_obj->set ("snippet", artifact_content_obj);
1019
1020 return region_obj;
1021}
1022
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). */
1025
1026json::object *
1027sarif_builder::make_region_object_for_hint (const fixit_hint &hint) const
1028{
1029 location_t start_loc = hint.get_start_loc ();
1030 location_t next_loc = hint.get_next_loc ();
1031
1032 expanded_location exploc_start = expand_location (start_loc);
1033 expanded_location exploc_next = expand_location (next_loc);
1034
1035 json::object *region_obj = new json::object ();
1036
1037 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
070944fd 1038 region_obj->set_integer ("startLine", exploc_start.line);
6cf276dd
DM
1039
1040 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
1041 int start_col = get_sarif_column (exploc_start);
070944fd 1042 region_obj->set_integer ("startColumn", start_col);
6cf276dd
DM
1043
1044 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
1045 if (exploc_next.line != exploc_start.line)
070944fd 1046 region_obj->set_integer ("endLine", exploc_next.line);
6cf276dd
DM
1047
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);
070944fd 1051 region_obj->set_integer ("endColumn", next_col);
6cf276dd
DM
1052
1053 return region_obj;
1054}
1055
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. */
1059
1060static const char *
1061maybe_get_sarif_kind (enum logical_location_kind kind)
1062{
1063 switch (kind)
1064 {
1065 default:
1066 gcc_unreachable ();
1067 case LOGICAL_LOCATION_KIND_UNKNOWN:
1068 return NULL;
1069
1070 case LOGICAL_LOCATION_KIND_FUNCTION:
1071 return "function";
1072 case LOGICAL_LOCATION_KIND_MEMBER:
1073 return "member";
1074 case LOGICAL_LOCATION_KIND_MODULE:
1075 return "module";
1076 case LOGICAL_LOCATION_KIND_NAMESPACE:
1077 return "namespace";
1078 case LOGICAL_LOCATION_KIND_TYPE:
1079 return "type";
1080 case LOGICAL_LOCATION_KIND_RETURN_TYPE:
1081 return "returnType";
1082 case LOGICAL_LOCATION_KIND_PARAMETER:
1083 return "parameter";
1084 case LOGICAL_LOCATION_KIND_VARIABLE:
1085 return "variable";
1086 }
1087}
1088
1089/* Make a logicalLocation object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC,
1090 or return NULL. */
1091
1092json::object *
05c99b1c 1093make_sarif_logical_location_object (const logical_location &logical_loc)
6cf276dd
DM
1094{
1095 json::object *logical_loc_obj = new json::object ();
1096
1097 /* "name" property (SARIF v2.1.0 section 3.33.4). */
1098 if (const char *short_name = logical_loc.get_short_name ())
070944fd 1099 logical_loc_obj->set_string ("name", short_name);
6cf276dd
DM
1100
1101 /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
1102 if (const char *name_with_scope = logical_loc.get_name_with_scope ())
070944fd 1103 logical_loc_obj->set_string ("fullyQualifiedName", name_with_scope);
6cf276dd
DM
1104
1105 /* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
1106 if (const char *internal_name = logical_loc.get_internal_name ())
070944fd 1107 logical_loc_obj->set_string ("decoratedName", internal_name);
6cf276dd
DM
1108
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))
070944fd 1112 logical_loc_obj->set_string ("kind", sarif_kind_str);
6cf276dd
DM
1113
1114 return logical_loc_obj;
1115}
1116
1117/* Make a codeFlow object (SARIF v2.1.0 section 3.36) for PATH. */
1118
1119json::object *
1120sarif_builder::make_code_flow_object (const diagnostic_path &path)
1121{
1122 json::object *code_flow_obj = new json::object ();
1123
3a1e9f3e 1124 /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
6cf276dd 1125 json::array *thread_flows_arr = new json::array ();
6cf276dd 1126
3a1e9f3e
DM
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;
6cf276dd
DM
1131 for (unsigned i = 0; i < path.num_events (); i++)
1132 {
1133 const diagnostic_event &event = path.get_event (i);
3a1e9f3e
DM
1134 const diagnostic_thread_id_t thread_id = event.get_thread_id ();
1135 sarif_thread_flow *thread_flow_obj;
1136
1137 if (sarif_thread_flow **slot = thread_id_map.get (thread_id))
1138 thread_flow_obj = *slot;
1139 else
1140 {
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);
1145 }
1146
1147 /* Add event to thread's threadFlow object. */
6cf276dd 1148 json::object *thread_flow_loc_obj
3a1e9f3e
DM
1149 = make_thread_flow_location_object (event, i);
1150 thread_flow_obj->add_location (thread_flow_loc_obj);
6cf276dd 1151 }
3a1e9f3e 1152 code_flow_obj->set ("threadFlows", thread_flows_arr);
6cf276dd 1153
3a1e9f3e 1154 return code_flow_obj;
6cf276dd
DM
1155}
1156
1157/* Make a threadFlowLocation object (SARIF v2.1.0 section 3.38) for EVENT. */
1158
1159json::object *
3a1e9f3e
DM
1160sarif_builder::make_thread_flow_location_object (const diagnostic_event &ev,
1161 int path_event_idx)
6cf276dd 1162{
05c99b1c
DM
1163 sarif_object *thread_flow_loc_obj = new sarif_object ();
1164
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);
6cf276dd
DM
1168
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);
1172
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);
1177
1178 /* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */
070944fd 1179 thread_flow_loc_obj->set_integer ("nestingLevel", ev.get_stack_depth ());
6cf276dd 1180
3a1e9f3e
DM
1181 /* "executionOrder" property (SARIF v2.1.0 3.38.11).
1182 Offset by 1 to match the human-readable values emitted by %@. */
070944fd 1183 thread_flow_loc_obj->set_integer ("executionOrder", path_event_idx + 1);
3a1e9f3e 1184
6cf276dd
DM
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). */
1189
1190 return thread_flow_loc_obj;
1191}
1192
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).
1195
1196 Otherwise, return NULL. */
1197
1198json::array *
1199sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const
1200{
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)
1204 return NULL;
1205
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));
1216 return kinds_arr;
1217}
1218
1219/* Make a message object (SARIF v2.1.0 section 3.11) for MSG. */
1220
1221json::object *
1222sarif_builder::make_message_object (const char *msg) const
1223{
1224 json::object *message_obj = new json::object ();
1225
1226 /* "text" property (SARIF v2.1.0 section 3.11.8). */
070944fd 1227 message_obj->set_string ("text", msg);
6cf276dd
DM
1228
1229 return message_obj;
1230}
1231
4f01ae37
DM
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
1234 of the message. */
1235
1236json::object *
1237sarif_builder::make_message_object_for_diagram (diagnostic_context *context,
1238 const diagnostic_diagram &diagram)
1239{
1240 json::object *message_obj = new json::object ();
1241
1242 /* "text" property (SARIF v2.1.0 section 3.11.8). */
070944fd 1243 message_obj->set_string ("text", diagram.get_alt_text ());
4f01ae37
DM
1244
1245 char *saved_prefix = pp_take_prefix (context->printer);
1246 pp_set_prefix (context->printer, NULL);
1247
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);
1253
1254 /* "markdown" property (SARIF v2.1.0 section 3.11.9). */
070944fd 1255 message_obj->set_string ("markdown", pp_formatted_text (context->printer));
4f01ae37
DM
1256
1257 pp_clear_output_area (context->printer);
1258
1259 return message_obj;
1260}
1261
6cf276dd
DM
1262/* Make a multiformatMessageString object (SARIF v2.1.0 section 3.12)
1263 for MSG. */
1264
1265json::object *
1266sarif_builder::make_multiformat_message_string (const char *msg) const
1267{
1268 json::object *message_obj = new json::object ();
1269
1270 /* "text" property (SARIF v2.1.0 section 3.12.3). */
070944fd 1271 message_obj->set_string ("text", msg);
6cf276dd
DM
1272
1273 return message_obj;
1274}
1275
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"
1278
1279/* Make a top-level sarifLog object (SARIF v2.1.0 section 3.13).
79aaba0a 1280 Take ownership of INVOCATION_OBJ and RESULTS. */
6cf276dd
DM
1281
1282json::object *
79aaba0a
DM
1283sarif_builder::make_top_level_object (sarif_invocation *invocation_obj,
1284 json::array *results)
6cf276dd
DM
1285{
1286 json::object *log_obj = new json::object ();
1287
1288 /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */
070944fd 1289 log_obj->set_string ("$schema", SARIF_SCHEMA);
6cf276dd
DM
1290
1291 /* "version" property (SARIF v2.1.0 section 3.13.2). */
070944fd 1292 log_obj->set_string ("version", SARIF_VERSION);
6cf276dd
DM
1293
1294 /* "runs" property (SARIF v2.1.0 section 3.13.4). */
1295 json::array *run_arr = new json::array ();
79aaba0a 1296 json::object *run_obj = make_run_object (invocation_obj, results);
6cf276dd
DM
1297 run_arr->append (run_obj);
1298 log_obj->set ("runs", run_arr);
1299
1300 return log_obj;
1301}
1302
1303/* Make a run object (SARIF v2.1.0 section 3.14).
79aaba0a 1304 Take ownership of INVOCATION_OBJ and RESULTS. */
6cf276dd
DM
1305
1306json::object *
79aaba0a
DM
1307sarif_builder::make_run_object (sarif_invocation *invocation_obj,
1308 json::array *results)
6cf276dd
DM
1309{
1310 json::object *run_obj = new json::object ();
1311
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);
1315
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);
1319
79aaba0a
DM
1320 /* "invocations" property (SARIF v2.1.0 section 3.14.11). */
1321 {
1322 json::array *invocations_arr = new json::array ();
1323 invocations_arr->append (invocation_obj);
1324 run_obj->set ("invocations", invocations_arr);
1325 }
1326
6cf276dd
DM
1327 /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */
1328 if (m_seen_any_relative_paths)
1329 {
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);
1334 }
1335
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)
1339 {
1340 json::object *artifact_obj = make_artifact_object (iter);
1341 artifacts_arr->append (artifact_obj);
1342 }
1343 run_obj->set ("artifacts", artifacts_arr);
1344
1345 /* "results" property (SARIF v2.1.0 section 3.14.23). */
1346 run_obj->set ("results", results);
1347
1348 return run_obj;
1349}
1350
1351/* Make a tool object (SARIF v2.1.0 section 3.18). */
1352
1353json::object *
1354sarif_builder::make_tool_object () const
1355{
1356 json::object *tool_obj = new json::object ();
1357
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);
1361
1362 /* Report plugins via the "extensions" property
1363 (SARIF v2.1.0 section 3.18.3). */
8200cd97 1364 if (auto client_data_hooks = m_context->get_client_data_hooks ())
6cf276dd 1365 if (const client_version_info *vinfo
8200cd97 1366 = client_data_hooks->get_any_version_info ())
6cf276dd
DM
1367 {
1368 class my_plugin_visitor : public client_version_info :: plugin_visitor
1369 {
1370 public:
1371 void on_plugin (const diagnostic_client_plugin_info &p) final override
1372 {
1373 /* Create a toolComponent object (SARIF v2.1.0 section 3.19)
1374 for the plugin. */
1375 json::object *plugin_obj = new json::object ();
1376 m_plugin_objs.safe_push (plugin_obj);
1377
1378 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1379 if (const char *short_name = p.get_short_name ())
070944fd 1380 plugin_obj->set_string ("name", short_name);
6cf276dd
DM
1381
1382 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1383 if (const char *full_name = p.get_full_name ())
070944fd 1384 plugin_obj->set_string ("fullName", full_name);
6cf276dd
DM
1385
1386 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1387 if (const char *version = p.get_version ())
070944fd 1388 plugin_obj->set_string ("version", version);
6cf276dd
DM
1389 }
1390 auto_vec <json::object *> m_plugin_objs;
1391 };
1392 my_plugin_visitor v;
1393 vinfo->for_each_plugin (v);
1394 if (v.m_plugin_objs.length () > 0)
1395 {
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);
1400 }
1401 }
1402
1403 /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other
1404 "extensions" (see toplev.cc: print_version). */
1405
1406 return tool_obj;
1407}
1408
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). */
1411
1412json::object *
1413sarif_builder::make_driver_tool_component_object () const
1414{
1415 json::object *driver_obj = new json::object ();
1416
8200cd97 1417 if (auto client_data_hooks = m_context->get_client_data_hooks ())
6cf276dd 1418 if (const client_version_info *vinfo
8200cd97 1419 = client_data_hooks->get_any_version_info ())
6cf276dd
DM
1420 {
1421 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1422 if (const char *name = vinfo->get_tool_name ())
070944fd 1423 driver_obj->set_string ("name", name);
6cf276dd
DM
1424
1425 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1426 if (char *full_name = vinfo->maybe_make_full_name ())
1427 {
070944fd 1428 driver_obj->set_string ("fullName", full_name);
6cf276dd
DM
1429 free (full_name);
1430 }
1431
1432 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1433 if (const char *version = vinfo->get_version_string ())
070944fd 1434 driver_obj->set_string ("version", version);
6cf276dd
DM
1435
1436 /* "informationUri" property (SARIF v2.1.0 section 3.19.17). */
1437 if (char *version_url = vinfo->maybe_make_version_url ())
1438 {
070944fd 1439 driver_obj->set_string ("informationUri", version_url);
6cf276dd
DM
1440 free (version_url);
1441 }
1442 }
1443
1444 /* "rules" property (SARIF v2.1.0 section 3.19.23). */
1445 driver_obj->set ("rules", m_rules_arr);
1446
1447 return driver_obj;
1448}
1449
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.
1453
1454 Otherwise return NULL. */
1455
1456json::array *
1457sarif_builder::maybe_make_taxonomies_array () const
1458{
1459 json::object *cwe_obj = maybe_make_cwe_taxonomy_object ();
1460 if (!cwe_obj)
1461 return NULL;
1462
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;
1467}
1468
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.
1472
1473 Otherwise return NULL. */
1474
1475json::object *
1476sarif_builder::maybe_make_cwe_taxonomy_object () const
1477{
1478 if (m_cwe_id_set.is_empty ())
1479 return NULL;
1480
1481 json::object *taxonomy_obj = new json::object ();
1482
1483 /* "name" property (SARIF v2.1.0 section 3.19.8). */
070944fd 1484 taxonomy_obj->set_string ("name", "CWE");
6cf276dd
DM
1485
1486 /* "version" property (SARIF v2.1.0 section 3.19.13). */
070944fd 1487 taxonomy_obj->set_string ("version", "4.7");
6cf276dd
DM
1488
1489 /* "organization" property (SARIF v2.1.0 section 3.19.18). */
070944fd 1490 taxonomy_obj->set_string ("organization", "MITRE");
6cf276dd
DM
1491
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);
1497
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)
1501 {
1502 json::object *cwe_taxon
1503 = make_reporting_descriptor_object_for_cwe_id (cwe_id);
1504 taxa_arr->append (cwe_taxon);
1505 }
1506 taxonomy_obj->set ("taxa", taxa_arr);
1507
1508 return taxonomy_obj;
1509}
1510
1511/* Make an artifact object (SARIF v2.1.0 section 3.24). */
1512
1513json::object *
1514sarif_builder::make_artifact_object (const char *filename)
1515{
1516 json::object *artifact_obj = new json::object ();
1517
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);
1521
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);
1526
1527 /* "sourceLanguage" property (SARIF v2.1.0 section 3.24.10). */
8200cd97 1528 if (auto client_data_hooks = m_context->get_client_data_hooks ())
6cf276dd 1529 if (const char *source_lang
8200cd97 1530 = client_data_hooks->maybe_get_sarif_source_language (filename))
070944fd 1531 artifact_obj->set_string ("sourceLanguage", source_lang);
6cf276dd
DM
1532
1533 return artifact_obj;
1534}
1535
6cf276dd
DM
1536/* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the
1537 full contents of FILENAME. */
1538
1539json::object *
1540sarif_builder::maybe_make_artifact_content_object (const char *filename) const
1541{
d495ea2b 1542 /* Let input.cc handle any charset conversion. */
14082026 1543 char_span utf8_content
1bdd665a 1544 = m_context->get_file_cache ().get_source_file_content (filename);
d495ea2b 1545 if (!utf8_content)
6cf276dd
DM
1546 return NULL;
1547
d495ea2b
DM
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 ()))
1550 return NULL;
6cf276dd 1551
d495ea2b
DM
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 ()));
6cf276dd
DM
1556 return artifact_content_obj;
1557}
1558
1559/* Attempt to read the given range of lines from FILENAME; return
1560 a freshly-allocated 0-terminated buffer containing them, or NULL. */
1561
14082026
DM
1562char *
1563sarif_builder::get_source_lines (const char *filename,
1564 int start_line,
1565 int end_line) const
6cf276dd
DM
1566{
1567 auto_vec<char> result;
1568
1569 for (int line = start_line; line <= end_line; line++)
1570 {
14082026 1571 char_span line_content
1bdd665a 1572 = m_context->get_file_cache ().get_source_line (filename, line);
6cf276dd
DM
1573 if (!line_content.get_buffer ())
1574 return NULL;
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');
1579 }
1580 result.safe_push ('\0');
1581
1582 return xstrdup (result.address ());
1583}
1584
1585/* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the given
1586 run of lines within FILENAME (including the endpoints). */
1587
1588json::object *
1589sarif_builder::maybe_make_artifact_content_object (const char *filename,
1590 int start_line,
1591 int end_line) const
1592{
1593 char *text_utf8 = get_source_lines (filename, start_line, end_line);
1594
1595 if (!text_utf8)
1596 return NULL;
1597
d495ea2b
DM
1598 /* Don't add it if it's not valid UTF-8. */
1599 if (!cpp_valid_utf8_p(text_utf8, strlen(text_utf8)))
1600 {
1601 free (text_utf8);
1602 return NULL;
1603 }
1604
6cf276dd 1605 json::object *artifact_content_obj = new json::object ();
070944fd 1606 artifact_content_obj->set_string ("text", text_utf8);
6cf276dd
DM
1607 free (text_utf8);
1608
1609 return artifact_content_obj;
1610}
1611
1612/* Make a fix object (SARIF v2.1.0 section 3.55) for RICHLOC. */
1613
1614json::object *
1615sarif_builder::make_fix_object (const rich_location &richloc)
1616{
1617 json::object *fix_obj = new json::object ();
1618
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);
1625
1626 return fix_obj;
1627}
1628
1629/* Make an artifactChange object (SARIF v2.1.0 section 3.56) for RICHLOC. */
1630
1631json::object *
1632sarif_builder::make_artifact_change_object (const rich_location &richloc)
1633{
1634 json::object *artifact_change_obj = new json::object ();
1635
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);
1640
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++)
1644 {
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);
1648 }
1649 artifact_change_obj->set ("replacements", replacement_arr);
1650
1651 return artifact_change_obj;
1652}
1653
1654/* Make a replacement object (SARIF v2.1.0 section 3.57) for HINT. */
1655
1656json::object *
1657sarif_builder::make_replacement_object (const fixit_hint &hint) const
1658{
1659 json::object *replacement_obj = new json::object ();
1660
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);
1664
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);
1668
1669 return replacement_obj;
1670}
1671
1672/* Make an artifactContent object (SARIF v2.1.0 section 3.3) for TEXT. */
1673
1674json::object *
1675sarif_builder::make_artifact_content_object (const char *text) const
1676{
1677 json::object *content_obj = new json::object ();
1678
1679 /* "text" property (SARIF v2.1.0 section 3.3.2). */
070944fd 1680 content_obj->set_string ("text", text);
6cf276dd
DM
1681
1682 return content_obj;
1683}
1684
79aaba0a
DM
1685/* Callback for diagnostic_context::ice_handler_cb for when an ICE
1686 occurs. */
1687
1688static void
1689sarif_ice_handler (diagnostic_context *context)
1690{
1691 /* Attempt to ensure that a .sarif file is written out. */
1692 diagnostic_finish (context);
1693
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
1698 those messages). */
1699 fnotice (stderr, "Internal compiler error:\n");
1700}
1701
14082026
DM
1702class sarif_output_format : public diagnostic_output_format
1703{
1704public:
1705 void on_begin_group () final override
1706 {
1707 /* No-op, */
1708 }
1709 void on_end_group () final override
1710 {
1711 m_builder.end_group ();
1712 }
1713 void
8fc4e6c3 1714 on_begin_diagnostic (const diagnostic_info &) final override
14082026
DM
1715 {
1716 /* No-op, */
1717 }
1718 void
8fc4e6c3 1719 on_end_diagnostic (const diagnostic_info &diagnostic,
14082026
DM
1720 diagnostic_t orig_diag_kind) final override
1721 {
1722 m_builder.end_diagnostic (&m_context, diagnostic, orig_diag_kind);
1723 }
1724 void on_diagram (const diagnostic_diagram &diagram) final override
1725 {
1726 m_builder.emit_diagram (&m_context, diagram);
1727 }
4f01ae37 1728
14082026 1729protected:
3bd8241a
DM
1730 sarif_output_format (diagnostic_context &context,
1731 bool formatted)
14082026 1732 : diagnostic_output_format (context),
3bd8241a 1733 m_builder (&context, formatted)
14082026
DM
1734 {}
1735
1736 sarif_builder m_builder;
1737};
1738
1739class sarif_stream_output_format : public sarif_output_format
4f01ae37 1740{
14082026 1741public:
3bd8241a
DM
1742 sarif_stream_output_format (diagnostic_context &context,
1743 bool formatted,
1744 FILE *stream)
1745 : sarif_output_format (context, formatted),
14082026
DM
1746 m_stream (stream)
1747 {
1748 }
1749 ~sarif_stream_output_format ()
1750 {
1751 m_builder.flush_to_file (m_stream);
1752 }
0bf99b1b
DM
1753 bool machine_readable_stderr_p () const final override
1754 {
1755 return m_stream == stderr;
1756 }
14082026
DM
1757private:
1758 FILE *m_stream;
1759};
1760
1761class sarif_file_output_format : public sarif_output_format
1762{
1763public:
1764 sarif_file_output_format (diagnostic_context &context,
3bd8241a
DM
1765 bool formatted,
1766 const char *base_file_name)
1767 : sarif_output_format (context, formatted),
14082026
DM
1768 m_base_file_name (xstrdup (base_file_name))
1769 {
1770 }
1771 ~sarif_file_output_format ()
1772 {
1773 char *filename = concat (m_base_file_name, ".sarif", NULL);
1774 free (m_base_file_name);
1775 m_base_file_name = nullptr;
1776 FILE *outf = fopen (filename, "w");
1777 if (!outf)
1778 {
1779 const char *errstr = xstrerror (errno);
1780 fnotice (stderr, "error: unable to open '%s' for writing: %s\n",
1781 filename, errstr);
1782 free (filename);
1783 return;
1784 }
1785 m_builder.flush_to_file (outf);
1786 fclose (outf);
1787 free (filename);
1788 }
0bf99b1b
DM
1789 bool machine_readable_stderr_p () const final override
1790 {
1791 return false;
1792 }
14082026
DM
1793
1794private:
1795 char *m_base_file_name;
1796};
4f01ae37 1797
6cf276dd
DM
1798/* Populate CONTEXT in preparation for SARIF output (either to stderr, or
1799 to a file). */
1800
1801static void
1802diagnostic_output_format_init_sarif (diagnostic_context *context)
1803{
6cf276dd 1804 /* Override callbacks. */
8200cd97
DM
1805 context->m_print_path = nullptr; /* handled in sarif_end_diagnostic. */
1806 context->set_ice_handler_callback (sarif_ice_handler);
6cf276dd
DM
1807
1808 /* The metadata is handled in SARIF format, rather than as text. */
8200cd97
DM
1809 context->set_show_cwe (false);
1810 context->set_show_rules (false);
6cf276dd
DM
1811
1812 /* The option is handled in SARIF format, rather than as text. */
8200cd97 1813 context->set_show_option_requested (false);
6cf276dd
DM
1814
1815 /* Don't colorize the text. */
1816 pp_show_color (context->printer) = false;
1817}
1818
1819/* Populate CONTEXT in preparation for SARIF output to stderr. */
1820
1821void
3bd8241a
DM
1822diagnostic_output_format_init_sarif_stderr (diagnostic_context *context,
1823 bool formatted)
6cf276dd
DM
1824{
1825 diagnostic_output_format_init_sarif (context);
8200cd97 1826 context->set_output_format (new sarif_stream_output_format (*context,
3bd8241a 1827 formatted,
8200cd97 1828 stderr));
6cf276dd
DM
1829}
1830
1831/* Populate CONTEXT in preparation for SARIF output to a file named
1832 BASE_FILE_NAME.sarif. */
1833
1834void
1835diagnostic_output_format_init_sarif_file (diagnostic_context *context,
3bd8241a 1836 bool formatted,
14082026
DM
1837 const char *base_file_name)
1838{
1839 diagnostic_output_format_init_sarif (context);
8200cd97 1840 context->set_output_format (new sarif_file_output_format (*context,
3bd8241a 1841 formatted,
8200cd97 1842 base_file_name));
14082026
DM
1843}
1844
1845/* Populate CONTEXT in preparation for SARIF output to STREAM. */
1846
1847void
1848diagnostic_output_format_init_sarif_stream (diagnostic_context *context,
3bd8241a 1849 bool formatted,
14082026 1850 FILE *stream)
6cf276dd
DM
1851{
1852 diagnostic_output_format_init_sarif (context);
8200cd97 1853 context->set_output_format (new sarif_stream_output_format (*context,
3bd8241a 1854 formatted,
8200cd97 1855 stream));
6cf276dd 1856}