1 /* SARIF output for diagnostics
2 Copyright (C) 2018-2022 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/>. */
24 #include "coretypes.h"
25 #include "diagnostic.h"
26 #include "diagnostic-metadata.h"
27 #include "diagnostic-path.h"
30 #include "logical-location.h"
31 #include "diagnostic-client-data-hooks.h"
35 /* Subclass of json::object for SARIF result objects
36 (SARIF v2.1.0 section 3.27. */
38 class sarif_result
: public json::object
41 sarif_result () : m_related_locations_arr (NULL
) {}
44 on_nested_diagnostic (diagnostic_context
*context
,
45 diagnostic_info
*diagnostic
,
46 diagnostic_t orig_diag_kind
,
47 sarif_builder
*builder
);
50 json::array
*m_related_locations_arr
;
53 /* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
54 and -fdiagnostics-format=sarif-file).
56 As diagnostics occur, we build "result" JSON objects, and
58 - which source files are referenced
59 - which warnings are emitted
62 At the end of the compile, we use the above to build the full SARIF
63 object tree, adding the result objects to the correct place, and
64 creating objects for the various source files, warnings and CWEs
70 - diagnostic groups (see limitations below)
71 - logical locations (e.g. cfun)
74 - GCC supports one-deep nesting of diagnostics (via auto_diagnostic_group),
75 but we only capture location and message information from such nested
76 diagnostics (e.g. we ignore fix-it hints on them)
77 - doesn't yet capture command-line arguments: would be run.invocations
78 property (SARIF v2.1.0 section 3.14.11), as invocation objects
79 (SARIF v2.1.0 section 3.20), but we'd want to capture the arguments to
80 toplev::main, and the response files.
81 - doesn't capture escape_on_output_p
82 - doesn't capture secondary locations within a rich_location
83 (perhaps we should use the "relatedLocations" property: SARIF v2.1.0
85 - doesn't capture "artifact.encoding" property
86 (SARIF v2.1.0 section 3.24.9).
87 - doesn't capture hashes of the source files
88 ("artifact.hashes" property (SARIF v2.1.0 section 3.24.11).
89 - doesn't capture the "analysisTarget" property
90 (SARIF v2.1.0 section 3.27.13).
91 - doesn't capture labelled ranges
92 - doesn't capture -Werror cleanly
93 - doesn't capture inlining information (can SARIF handle this?)
94 - doesn't capture macro expansion information (can SARIF handle this?). */
99 sarif_builder (diagnostic_context
*context
);
101 void end_diagnostic (diagnostic_context
*context
, diagnostic_info
*diagnostic
,
102 diagnostic_t orig_diag_kind
);
106 void flush_to_file (FILE *outf
);
108 json::object
*make_location_object (const rich_location
&rich_loc
,
109 const logical_location
*logical_loc
);
110 json::object
*make_message_object (const char *msg
) const;
113 sarif_result
*make_result_object (diagnostic_context
*context
,
114 diagnostic_info
*diagnostic
,
115 diagnostic_t orig_diag_kind
);
116 void set_any_logical_locs_arr (json::object
*location_obj
,
117 const logical_location
*logical_loc
);
118 json::object
*make_location_object (const diagnostic_event
&event
);
120 make_logical_location_object (const logical_location
&logical_loc
) const;
121 json::object
*make_code_flow_object (const diagnostic_path
&path
);
122 json::object
*make_thread_flow_object (const diagnostic_path
&path
);
124 make_thread_flow_location_object (const diagnostic_event
&event
);
125 json::array
*maybe_make_kinds_array (diagnostic_event::meaning m
) const;
126 json::object
*maybe_make_physical_location_object (location_t loc
);
127 json::object
*make_artifact_location_object (location_t loc
);
128 json::object
*make_artifact_location_object (const char *filename
);
129 json::object
*make_artifact_location_object_for_pwd () const;
130 json::object
*maybe_make_region_object (location_t loc
) const;
131 json::object
*maybe_make_region_object_for_context (location_t loc
) const;
132 json::object
*make_region_object_for_hint (const fixit_hint
&hint
) const;
133 json::object
*make_multiformat_message_string (const char *msg
) const;
134 json::object
*make_top_level_object (json::array
*results
);
135 json::object
*make_run_object (json::array
*results
);
136 json::object
*make_tool_object () const;
137 json::object
*make_driver_tool_component_object () const;
138 json::array
*maybe_make_taxonomies_array () const;
139 json::object
*maybe_make_cwe_taxonomy_object () const;
140 json::object
*make_tool_component_reference_object_for_cwe () const;
142 make_reporting_descriptor_object_for_warning (diagnostic_context
*context
,
143 diagnostic_info
*diagnostic
,
144 diagnostic_t orig_diag_kind
,
145 const char *option_text
);
146 json::object
*make_reporting_descriptor_object_for_cwe_id (int cwe_id
) const;
148 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id
);
149 json::object
*make_artifact_object (const char *filename
);
150 json::object
*maybe_make_artifact_content_object (const char *filename
) const;
151 json::object
*maybe_make_artifact_content_object (const char *filename
,
154 json::object
*make_fix_object (const rich_location
&rich_loc
);
155 json::object
*make_artifact_change_object (const rich_location
&richloc
);
156 json::object
*make_replacement_object (const fixit_hint
&hint
) const;
157 json::object
*make_artifact_content_object (const char *text
) const;
158 int get_sarif_column (expanded_location exploc
) const;
160 diagnostic_context
*m_context
;
162 /* The JSON array of pending diagnostics. */
163 json::array
*m_results_array
;
165 /* The JSON object for the result object (if any) in the current
167 sarif_result
*m_cur_group_result
;
169 hash_set
<const char *> m_filenames
;
170 bool m_seen_any_relative_paths
;
171 hash_set
<free_string_hash
> m_rule_id_set
;
172 json::array
*m_rules_arr
;
174 /* The set of all CWE IDs we've seen, if any. */
175 hash_set
<int_hash
<int, 0, 1> > m_cwe_id_set
;
180 static sarif_builder
*the_builder
;
182 /* class sarif_result : public json::object. */
184 /* Handle secondary diagnostics that occur within a diagnostic group.
185 The closest SARIF seems to have to nested diagnostics is the
186 "relatedLocations" property of result objects (SARIF v2.1.0 section 3.27.22),
187 so we lazily set this property and populate the array if and when
188 secondary diagnostics occur (such as notes to a warning). */
191 sarif_result::on_nested_diagnostic (diagnostic_context
*context
,
192 diagnostic_info
*diagnostic
,
193 diagnostic_t
/*orig_diag_kind*/,
194 sarif_builder
*builder
)
196 if (!m_related_locations_arr
)
198 m_related_locations_arr
= new json::array ();
199 set ("relatedLocations", m_related_locations_arr
);
202 /* We don't yet generate meaningful logical locations for notes;
203 sometimes these will related to current_function_decl, but
205 json::object
*location_obj
206 = builder
->make_location_object (*diagnostic
->richloc
, NULL
);
207 json::object
*message_obj
208 = builder
->make_message_object (pp_formatted_text (context
->printer
));
209 pp_clear_output_area (context
->printer
);
210 location_obj
->set ("message", message_obj
);
212 m_related_locations_arr
->append (location_obj
);
215 /* class sarif_builder. */
217 /* sarif_builder's ctor. */
219 sarif_builder::sarif_builder (diagnostic_context
*context
)
220 : m_context (context
),
221 m_results_array (new json::array ()),
222 m_cur_group_result (NULL
),
223 m_seen_any_relative_paths (false),
225 m_rules_arr (new json::array ()),
226 m_tabstop (context
->tabstop
)
230 /* Implementation of "end_diagnostic" for SARIF output. */
233 sarif_builder::end_diagnostic (diagnostic_context
*context
,
234 diagnostic_info
*diagnostic
,
235 diagnostic_t orig_diag_kind
)
238 if (m_cur_group_result
)
239 /* Nested diagnostic. */
240 m_cur_group_result
->on_nested_diagnostic (context
,
246 /* Top-level diagnostic. */
247 sarif_result
*result_obj
248 = make_result_object (context
, diagnostic
, orig_diag_kind
);
249 m_results_array
->append (result_obj
);
250 m_cur_group_result
= result_obj
;
254 /* Implementation of "end_group_cb" for SARIF output. */
257 sarif_builder::end_group ()
259 m_cur_group_result
= NULL
;
262 /* Create a top-level object, and add it to all the results
263 (and other entities) we've seen so far.
265 Flush it all to OUTF. */
268 sarif_builder::flush_to_file (FILE *outf
)
270 json::object
*top
= make_top_level_object (m_results_array
);
272 m_results_array
= NULL
;
273 fprintf (outf
, "\n");
277 /* Attempt to convert DIAG_KIND to a suitable value for the "level"
278 property (SARIF v2.1.0 section 3.27.10).
280 Return NULL if there isn't one. */
283 maybe_get_sarif_level (diagnostic_t diag_kind
)
299 /* Make a string for DIAG_KIND suitable for use a ruleId
300 (SARIF v2.1.0 section 3.27.5) as a fallback for when we don't
301 have anything better to use. */
304 make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind
)
306 static const char *const diagnostic_kind_text
[] = {
307 #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
308 #include "diagnostic.def"
309 #undef DEFINE_DIAGNOSTIC_KIND
312 /* Lose the trailing ": ". */
313 const char *kind_text
= diagnostic_kind_text
[diag_kind
];
314 size_t len
= strlen (kind_text
);
315 gcc_assert (len
> 2);
316 gcc_assert (kind_text
[len
- 2] == ':');
317 gcc_assert (kind_text
[len
- 1] == ' ');
318 char *rstrip
= xstrdup (kind_text
);
319 rstrip
[len
- 2] = '\0';
323 /* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */
326 sarif_builder::make_result_object (diagnostic_context
*context
,
327 diagnostic_info
*diagnostic
,
328 diagnostic_t orig_diag_kind
)
330 sarif_result
*result_obj
= new sarif_result ();
332 /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
333 /* Ideally we'd have an option_name for these. */
334 if (char *option_text
335 = context
->option_name (context
, diagnostic
->option_index
,
336 orig_diag_kind
, diagnostic
->kind
))
338 /* Lazily create reportingDescriptor objects for and add to m_rules_arr.
339 Set ruleId referencing them. */
340 result_obj
->set ("ruleId", new json::string (option_text
));
341 if (m_rule_id_set
.contains (option_text
))
345 /* This is the first time we've seen this ruleId. */
346 /* Add to set, taking ownership. */
347 m_rule_id_set
.add (option_text
);
349 json::object
*reporting_desc_obj
350 = make_reporting_descriptor_object_for_warning (context
,
354 m_rules_arr
->append (reporting_desc_obj
);
359 /* Otherwise, we have an "error" or a stray "note"; use the
360 diagnostic kind as the ruleId, so that the result object at least
362 We don't bother creating reportingDescriptor objects for these. */
363 char *rule_id
= make_rule_id_for_diagnostic_kind (orig_diag_kind
);
364 result_obj
->set ("ruleId", new json::string (rule_id
));
368 /* "taxa" property (SARIF v2.1.0 section 3.27.8). */
369 if (diagnostic
->metadata
)
370 if (int cwe_id
= diagnostic
->metadata
->get_cwe ())
372 json::array
*taxa_arr
= new json::array ();
373 json::object
*cwe_id_obj
374 = make_reporting_descriptor_reference_object_for_cwe_id (cwe_id
);
375 taxa_arr
->append (cwe_id_obj
);
376 result_obj
->set ("taxa", taxa_arr
);
379 /* "level" property (SARIF v2.1.0 section 3.27.10). */
380 if (const char *sarif_level
= maybe_get_sarif_level (diagnostic
->kind
))
381 result_obj
->set ("level", new json::string (sarif_level
));
383 /* "message" property (SARIF v2.1.0 section 3.27.11). */
384 json::object
*message_obj
385 = make_message_object (pp_formatted_text (context
->printer
));
386 pp_clear_output_area (context
->printer
);
387 result_obj
->set ("message", message_obj
);
389 /* "locations" property (SARIF v2.1.0 section 3.27.12). */
390 json::array
*locations_arr
= new json::array ();
391 const logical_location
*logical_loc
= NULL
;
392 if (m_context
->m_client_data_hooks
)
394 = m_context
->m_client_data_hooks
->get_current_logical_location ();
396 json::object
*location_obj
397 = make_location_object (*diagnostic
->richloc
, logical_loc
);
398 locations_arr
->append (location_obj
);
399 result_obj
->set ("locations", locations_arr
);
401 /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
402 if (const diagnostic_path
*path
= diagnostic
->richloc
->get_path ())
404 json::array
*code_flows_arr
= new json::array ();
405 json::object
*code_flow_obj
= make_code_flow_object (*path
);
406 code_flows_arr
->append (code_flow_obj
);
407 result_obj
->set ("codeFlows", code_flows_arr
);
410 /* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is
411 set up later, if any nested diagnostics occur within this diagnostic
414 /* "fixes" property (SARIF v2.1.0 section 3.27.30). */
415 const rich_location
*richloc
= diagnostic
->richloc
;
416 if (richloc
->get_num_fixit_hints ())
418 json::array
*fix_arr
= new json::array ();
419 json::object
*fix_obj
= make_fix_object (*richloc
);
420 fix_arr
->append (fix_obj
);
421 result_obj
->set ("fixes", fix_arr
);
427 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
428 for a GCC warning. */
432 make_reporting_descriptor_object_for_warning (diagnostic_context
*context
,
433 diagnostic_info
*diagnostic
,
434 diagnostic_t
/*orig_diag_kind*/,
435 const char *option_text
)
437 json::object
*reporting_desc
= new json::object ();
439 /* "id" property (SARIF v2.1.0 section 3.49.3). */
440 reporting_desc
->set ("id", new json::string (option_text
));
442 /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since
443 it seems redundant compared to "id". */
445 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
446 if (context
->get_option_url
)
449 = context
->get_option_url (context
, diagnostic
->option_index
);
452 reporting_desc
->set ("helpUri", new json::string (option_url
));
457 return reporting_desc
;
460 /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49)
461 for CWE_ID, for use within the CWE taxa array. */
464 sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id
) const
466 json::object
*reporting_desc
= new json::object ();
468 /* "id" property (SARIF v2.1.0 section 3.49.3). */
471 pp_printf (&pp
, "%i", cwe_id
);
472 reporting_desc
->set ("id", new json::string (pp_formatted_text (&pp
)));
475 /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
477 char *url
= get_cwe_url (cwe_id
);
478 reporting_desc
->set ("helpUri", new json::string (url
));
482 return reporting_desc
;
485 /* Make a reportingDescriptorReference object (SARIF v2.1.0 section 3.52)
486 referencing CWE_ID, for use within a result object.
487 Also, add CWE_ID to m_cwe_id_set. */
491 make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id
)
493 json::object
*desc_ref_obj
= new json::object ();
495 /* "id" property (SARIF v2.1.0 section 3.52.4). */
498 pp_printf (&pp
, "%i", cwe_id
);
499 desc_ref_obj
->set ("id", new json::string (pp_formatted_text (&pp
)));
502 /* "toolComponent" property (SARIF v2.1.0 section 3.52.7). */
503 json::object
*comp_ref_obj
= make_tool_component_reference_object_for_cwe ();
504 desc_ref_obj
->set ("toolComponent", comp_ref_obj
);
506 /* Add CWE_ID to our set. */
507 gcc_assert (cwe_id
> 0);
508 m_cwe_id_set
.add (cwe_id
);
513 /* Make a toolComponentReference object (SARIF v2.1.0 section 3.54) that
514 references the CWE taxonomy. */
518 make_tool_component_reference_object_for_cwe () const
520 json::object
*comp_ref_obj
= new json::object ();
522 /* "name" property (SARIF v2.1.0 section 3.54.3). */
523 comp_ref_obj
->set ("name", new json::string ("cwe"));
528 /* If LOGICAL_LOC is non-NULL, use it to create a "logicalLocations" property
529 within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */
533 set_any_logical_locs_arr (json::object
*location_obj
,
534 const logical_location
*logical_loc
)
538 json::object
*logical_loc_obj
= make_logical_location_object (*logical_loc
);
539 json::array
*location_locs_arr
= new json::array ();
540 location_locs_arr
->append (logical_loc_obj
);
541 location_obj
->set ("logicalLocations", location_locs_arr
);
544 /* Make a location object (SARIF v2.1.0 section 3.28) for RICH_LOC
548 sarif_builder::make_location_object (const rich_location
&rich_loc
,
549 const logical_location
*logical_loc
)
551 json::object
*location_obj
= new json::object ();
553 /* Get primary loc from RICH_LOC. */
554 location_t loc
= rich_loc
.get_loc ();
556 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
557 if (json::object
*phs_loc_obj
= maybe_make_physical_location_object (loc
))
558 location_obj
->set ("physicalLocation", phs_loc_obj
);
560 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
561 set_any_logical_locs_arr (location_obj
, logical_loc
);
566 /* Make a location object (SARIF v2.1.0 section 3.28) for EVENT
567 within a diagnostic_path. */
570 sarif_builder::make_location_object (const diagnostic_event
&event
)
572 json::object
*location_obj
= new json::object ();
574 /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
575 location_t loc
= event
.get_location ();
576 if (json::object
*phs_loc_obj
= maybe_make_physical_location_object (loc
))
577 location_obj
->set ("physicalLocation", phs_loc_obj
);
579 /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
580 const logical_location
*logical_loc
= event
.get_logical_location ();
581 set_any_logical_locs_arr (location_obj
, logical_loc
);
583 /* "message" property (SARIF v2.1.0 section 3.28.5). */
584 label_text ev_desc
= event
.get_desc (false);
585 json::object
*message_obj
= make_message_object (ev_desc
.m_buffer
);
586 location_obj
->set ("message", message_obj
);
587 ev_desc
.maybe_free ();
592 /* Make a physicalLocation object (SARIF v2.1.0 section 3.29) for LOC,
594 Add any filename to the m_artifacts. */
597 sarif_builder::maybe_make_physical_location_object (location_t loc
)
599 if (loc
<= BUILTINS_LOCATION
)
602 json::object
*phys_loc_obj
= new json::object ();
604 /* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */
605 json::object
*artifact_loc_obj
= make_artifact_location_object (loc
);
606 phys_loc_obj
->set ("artifactLocation", artifact_loc_obj
);
607 m_filenames
.add (LOCATION_FILE (loc
));
609 /* "region" property (SARIF v2.1.0 section 3.29.4). */
610 if (json::object
*region_obj
= maybe_make_region_object (loc
))
611 phys_loc_obj
->set ("region", region_obj
);
613 /* "contextRegion" property (SARIF v2.1.0 section 3.29.5). */
614 if (json::object
*context_region_obj
615 = maybe_make_region_object_for_context (loc
))
616 phys_loc_obj
->set ("contextRegion", context_region_obj
);
618 /* Instead, we add artifacts to the run as a whole,
619 with artifact.contents.
620 Could do both, though. */
625 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for LOC,
629 sarif_builder::make_artifact_location_object (location_t loc
)
631 return make_artifact_location_object (LOCATION_FILE (loc
));
634 /* The ID value for use in "uriBaseId" properties (SARIF v2.1.0 section 3.4.4)
635 for when we need to express paths relative to PWD. */
637 #define PWD_PROPERTY_NAME ("PWD")
639 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for FILENAME,
643 sarif_builder::make_artifact_location_object (const char *filename
)
645 json::object
*artifact_loc_obj
= new json::object ();
647 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
648 artifact_loc_obj
->set ("uri", new json::string (filename
));
650 if (filename
[0] != '/')
652 /* If we have a relative path, set the "uriBaseId" property
653 (SARIF v2.1.0 section 3.4.4). */
654 artifact_loc_obj
->set ("uriBaseId", new json::string (PWD_PROPERTY_NAME
));
655 m_seen_any_relative_paths
= true;
658 return artifact_loc_obj
;
661 /* Get the PWD, or NULL, as an absolute file-based URI,
662 adding a trailing forward slash (as required by SARIF v2.1.0
668 /* The prefix of a file-based URI, up to, but not including the path. */
669 #define FILE_PREFIX ("file://")
671 const char *pwd
= getpwd ();
674 size_t len
= strlen (pwd
);
675 if (len
== 0 || pwd
[len
- 1] != '/')
676 return concat (FILE_PREFIX
, pwd
, "/", NULL
);
679 gcc_assert (pwd
[len
- 1] == '/');
680 return concat (FILE_PREFIX
, pwd
, NULL
);
684 /* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for the pwd,
685 for use in the "run.originalUriBaseIds" property (SARIF v2.1.0
686 section 3.14.14) when we have any relative paths. */
689 sarif_builder::make_artifact_location_object_for_pwd () const
691 json::object
*artifact_loc_obj
= new json::object ();
693 /* "uri" property (SARIF v2.1.0 section 3.4.3). */
694 if (char *pwd
= make_pwd_uri_str ())
696 gcc_assert (strlen (pwd
) > 0);
697 gcc_assert (pwd
[strlen (pwd
) - 1] == '/');
698 artifact_loc_obj
->set ("uri", new json::string (pwd
));
702 return artifact_loc_obj
;
705 /* Get the column number within EXPLOC. */
708 sarif_builder::get_sarif_column (expanded_location exploc
) const
710 cpp_char_column_policy
policy (m_tabstop
, cpp_wcwidth
);
711 return location_compute_display_column (exploc
, policy
);
714 /* Make a region object (SARIF v2.1.0 section 3.30) for LOC,
718 sarif_builder::maybe_make_region_object (location_t loc
) const
720 location_t caret_loc
= get_pure_location (loc
);
722 if (caret_loc
<= BUILTINS_LOCATION
)
725 location_t start_loc
= get_start (loc
);
726 location_t finish_loc
= get_finish (loc
);
728 expanded_location exploc_caret
= expand_location (caret_loc
);
729 expanded_location exploc_start
= expand_location (start_loc
);
730 expanded_location exploc_finish
= expand_location (finish_loc
);
732 if (exploc_start
.file
!=exploc_caret
.file
)
734 if (exploc_finish
.file
!=exploc_caret
.file
)
737 json::object
*region_obj
= new json::object ();
739 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
740 region_obj
->set ("startLine", new json::integer_number (exploc_start
.line
));
742 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
743 region_obj
->set ("startColumn",
744 new json::integer_number (get_sarif_column (exploc_start
)));
746 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
747 if (exploc_finish
.line
!= exploc_start
.line
)
748 region_obj
->set ("endLine", new json::integer_number (exploc_finish
.line
));
750 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
751 This expresses the column immediately beyond the range. */
753 int next_column
= sarif_builder::get_sarif_column (exploc_finish
) + 1;
754 region_obj
->set ("endColumn", new json::integer_number (next_column
));
760 /* Make a region object (SARIF v2.1.0 section 3.30) for the "contextRegion"
761 property (SARIF v2.1.0 section 3.29.5) of a physicalLocation.
763 This is similar to maybe_make_region_object, but ignores column numbers,
764 covering the line(s) as a whole, and including a "snippet" property
765 embedding those source lines, making it easier for consumers to show
766 the pertinent source. */
769 sarif_builder::maybe_make_region_object_for_context (location_t loc
) const
771 location_t caret_loc
= get_pure_location (loc
);
773 if (caret_loc
<= BUILTINS_LOCATION
)
776 location_t start_loc
= get_start (loc
);
777 location_t finish_loc
= get_finish (loc
);
779 expanded_location exploc_caret
= expand_location (caret_loc
);
780 expanded_location exploc_start
= expand_location (start_loc
);
781 expanded_location exploc_finish
= expand_location (finish_loc
);
783 if (exploc_start
.file
!=exploc_caret
.file
)
785 if (exploc_finish
.file
!=exploc_caret
.file
)
788 json::object
*region_obj
= new json::object ();
790 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
791 region_obj
->set ("startLine", new json::integer_number (exploc_start
.line
));
793 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
794 if (exploc_finish
.line
!= exploc_start
.line
)
795 region_obj
->set ("endLine", new json::integer_number (exploc_finish
.line
));
797 /* "snippet" property (SARIF v2.1.0 section 3.30.13). */
798 if (json::object
*artifact_content_obj
799 = maybe_make_artifact_content_object (exploc_start
.file
,
802 region_obj
->set ("snippet", artifact_content_obj
);
807 /* Make a region object (SARIF v2.1.0 section 3.30) for the deletion region
808 of HINT (as per SARIF v2.1.0 section 3.57.3). */
811 sarif_builder::make_region_object_for_hint (const fixit_hint
&hint
) const
813 location_t start_loc
= hint
.get_start_loc ();
814 location_t next_loc
= hint
.get_next_loc ();
816 expanded_location exploc_start
= expand_location (start_loc
);
817 expanded_location exploc_next
= expand_location (next_loc
);
819 json::object
*region_obj
= new json::object ();
821 /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
822 region_obj
->set ("startLine", new json::integer_number (exploc_start
.line
));
824 /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
825 int start_col
= get_sarif_column (exploc_start
);
826 region_obj
->set ("startColumn",
827 new json::integer_number (start_col
));
829 /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
830 if (exploc_next
.line
!= exploc_start
.line
)
831 region_obj
->set ("endLine", new json::integer_number (exploc_next
.line
));
833 /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
834 This expresses the column immediately beyond the range. */
835 int next_col
= get_sarif_column (exploc_next
);
836 region_obj
->set ("endColumn", new json::integer_number (next_col
));
841 /* Attempt to get a string for a logicalLocation's "kind" property
842 (SARIF v2.1.0 section 3.33.7).
843 Return NULL if unknown. */
846 maybe_get_sarif_kind (enum logical_location_kind kind
)
852 case LOGICAL_LOCATION_KIND_UNKNOWN
:
855 case LOGICAL_LOCATION_KIND_FUNCTION
:
857 case LOGICAL_LOCATION_KIND_MEMBER
:
859 case LOGICAL_LOCATION_KIND_MODULE
:
861 case LOGICAL_LOCATION_KIND_NAMESPACE
:
863 case LOGICAL_LOCATION_KIND_TYPE
:
865 case LOGICAL_LOCATION_KIND_RETURN_TYPE
:
867 case LOGICAL_LOCATION_KIND_PARAMETER
:
869 case LOGICAL_LOCATION_KIND_VARIABLE
:
874 /* Make a logicalLocation object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC,
879 make_logical_location_object (const logical_location
&logical_loc
) const
881 json::object
*logical_loc_obj
= new json::object ();
883 /* "name" property (SARIF v2.1.0 section 3.33.4). */
884 if (const char *short_name
= logical_loc
.get_short_name ())
885 logical_loc_obj
->set ("name", new json::string (short_name
));
887 /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
888 if (const char *name_with_scope
= logical_loc
.get_name_with_scope ())
889 logical_loc_obj
->set ("fullyQualifiedName",
890 new json::string (name_with_scope
));
892 /* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
893 if (const char *internal_name
= logical_loc
.get_internal_name ())
894 logical_loc_obj
->set ("decoratedName", new json::string (internal_name
));
896 /* "kind" property (SARIF v2.1.0 section 3.33.7). */
897 enum logical_location_kind kind
= logical_loc
.get_kind ();
898 if (const char *sarif_kind_str
= maybe_get_sarif_kind (kind
))
899 logical_loc_obj
->set ("kind", new json::string (sarif_kind_str
));
901 return logical_loc_obj
;
904 /* Make a codeFlow object (SARIF v2.1.0 section 3.36) for PATH. */
907 sarif_builder::make_code_flow_object (const diagnostic_path
&path
)
909 json::object
*code_flow_obj
= new json::object ();
911 /* "threadFlows" property (SARIF v2.1.0 section 3.36.3).
912 Currently we only support one thread per result. */
913 json::array
*thread_flows_arr
= new json::array ();
914 json::object
*thread_flow_obj
= make_thread_flow_object (path
);
915 thread_flows_arr
->append (thread_flow_obj
);
916 code_flow_obj
->set ("threadFlows", thread_flows_arr
);
918 return code_flow_obj
;
921 /* Make a threadFlow object (SARIF v2.1.0 section 3.37) for PATH. */
924 sarif_builder::make_thread_flow_object (const diagnostic_path
&path
)
926 json::object
*thread_flow_obj
= new json::object ();
928 /* "locations" property (SARIF v2.1.0 section 3.37.6). */
929 json::array
*locations_arr
= new json::array ();
930 for (unsigned i
= 0; i
< path
.num_events (); i
++)
932 const diagnostic_event
&event
= path
.get_event (i
);
933 json::object
*thread_flow_loc_obj
934 = make_thread_flow_location_object (event
);
935 locations_arr
->append (thread_flow_loc_obj
);
937 thread_flow_obj
->set ("locations", locations_arr
);
939 return thread_flow_obj
;
942 /* Make a threadFlowLocation object (SARIF v2.1.0 section 3.38) for EVENT. */
945 sarif_builder::make_thread_flow_location_object (const diagnostic_event
&ev
)
947 json::object
*thread_flow_loc_obj
= new json::object ();
949 /* "location" property (SARIF v2.1.0 section 3.38.3). */
950 json::object
*location_obj
= make_location_object (ev
);
951 thread_flow_loc_obj
->set ("location", location_obj
);
953 /* "kinds" property (SARIF v2.1.0 section 3.38.8). */
954 diagnostic_event::meaning m
= ev
.get_meaning ();
955 if (json::array
*kinds_arr
= maybe_make_kinds_array (m
))
956 thread_flow_loc_obj
->set ("kinds", kinds_arr
);
958 /* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */
959 thread_flow_loc_obj
->set ("nestingLevel",
960 new json::integer_number (ev
.get_stack_depth ()));
962 /* It might be nice to eventually implement the following for -fanalyzer:
963 - the "stack" property (SARIF v2.1.0 section 3.38.5)
964 - the "state" property (SARIF v2.1.0 section 3.38.9)
965 - the "importance" property (SARIF v2.1.0 section 3.38.13). */
967 return thread_flow_loc_obj
;
970 /* If M has any known meaning, make a json array suitable for the "kinds"
971 property of a threadFlowLocation object (SARIF v2.1.0 section 3.38.8).
973 Otherwise, return NULL. */
976 sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m
) const
978 if (m
.m_verb
== diagnostic_event::VERB_unknown
979 && m
.m_noun
== diagnostic_event::NOUN_unknown
980 && m
.m_property
== diagnostic_event::PROPERTY_unknown
)
983 json::array
*kinds_arr
= new json::array ();
984 if (const char *verb_str
985 = diagnostic_event::meaning::maybe_get_verb_str (m
.m_verb
))
986 kinds_arr
->append (new json::string (verb_str
));
987 if (const char *noun_str
988 = diagnostic_event::meaning::maybe_get_noun_str (m
.m_noun
))
989 kinds_arr
->append (new json::string (noun_str
));
990 if (const char *property_str
991 = diagnostic_event::meaning::maybe_get_property_str (m
.m_property
))
992 kinds_arr
->append (new json::string (property_str
));
996 /* Make a message object (SARIF v2.1.0 section 3.11) for MSG. */
999 sarif_builder::make_message_object (const char *msg
) const
1001 json::object
*message_obj
= new json::object ();
1003 /* "text" property (SARIF v2.1.0 section 3.11.8). */
1004 message_obj
->set ("text", new json::string (msg
));
1009 /* Make a multiformatMessageString object (SARIF v2.1.0 section 3.12)
1013 sarif_builder::make_multiformat_message_string (const char *msg
) const
1015 json::object
*message_obj
= new json::object ();
1017 /* "text" property (SARIF v2.1.0 section 3.12.3). */
1018 message_obj
->set ("text", new json::string (msg
));
1023 #define SARIF_SCHEMA "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"
1024 #define SARIF_VERSION "2.1.0"
1026 /* Make a top-level sarifLog object (SARIF v2.1.0 section 3.13).
1027 Take ownership of RESULTS. */
1030 sarif_builder::make_top_level_object (json::array
*results
)
1032 json::object
*log_obj
= new json::object ();
1034 /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */
1035 log_obj
->set ("$schema", new json::string (SARIF_SCHEMA
));
1037 /* "version" property (SARIF v2.1.0 section 3.13.2). */
1038 log_obj
->set ("version", new json::string (SARIF_VERSION
));
1040 /* "runs" property (SARIF v2.1.0 section 3.13.4). */
1041 json::array
*run_arr
= new json::array ();
1042 json::object
*run_obj
= make_run_object (results
);
1043 run_arr
->append (run_obj
);
1044 log_obj
->set ("runs", run_arr
);
1049 /* Make a run object (SARIF v2.1.0 section 3.14).
1050 Take ownership of RESULTS. */
1053 sarif_builder::make_run_object (json::array
*results
)
1055 json::object
*run_obj
= new json::object ();
1057 /* "tool" property (SARIF v2.1.0 section 3.14.6). */
1058 json::object
*tool_obj
= make_tool_object ();
1059 run_obj
->set ("tool", tool_obj
);
1061 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1062 if (json::array
*taxonomies_arr
= maybe_make_taxonomies_array ())
1063 run_obj
->set ("taxonomies", taxonomies_arr
);
1065 /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */
1066 if (m_seen_any_relative_paths
)
1068 json::object
*orig_uri_base_ids
= new json::object ();
1069 run_obj
->set ("originalUriBaseIds", orig_uri_base_ids
);
1070 json::object
*pwd_art_loc_obj
= make_artifact_location_object_for_pwd ();
1071 orig_uri_base_ids
->set (PWD_PROPERTY_NAME
, pwd_art_loc_obj
);
1074 /* "artifacts" property (SARIF v2.1.0 section 3.14.15). */
1075 json::array
*artifacts_arr
= new json::array ();
1076 for (auto iter
: m_filenames
)
1078 json::object
*artifact_obj
= make_artifact_object (iter
);
1079 artifacts_arr
->append (artifact_obj
);
1081 run_obj
->set ("artifacts", artifacts_arr
);
1083 /* "results" property (SARIF v2.1.0 section 3.14.23). */
1084 run_obj
->set ("results", results
);
1089 /* Make a tool object (SARIF v2.1.0 section 3.18). */
1092 sarif_builder::make_tool_object () const
1094 json::object
*tool_obj
= new json::object ();
1096 /* "driver" property (SARIF v2.1.0 section 3.18.2). */
1097 json::object
*driver_obj
= make_driver_tool_component_object ();
1098 tool_obj
->set ("driver", driver_obj
);
1100 /* Report plugins via the "extensions" property
1101 (SARIF v2.1.0 section 3.18.3). */
1102 if (m_context
->m_client_data_hooks
)
1103 if (const client_version_info
*vinfo
1104 = m_context
->m_client_data_hooks
->get_any_version_info ())
1106 class my_plugin_visitor
: public client_version_info :: plugin_visitor
1109 void on_plugin (const diagnostic_client_plugin_info
&p
) final override
1111 /* Create a toolComponent object (SARIF v2.1.0 section 3.19)
1113 json::object
*plugin_obj
= new json::object ();
1114 m_plugin_objs
.safe_push (plugin_obj
);
1116 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1117 if (const char *short_name
= p
.get_short_name ())
1118 plugin_obj
->set ("name", new json::string (short_name
));
1120 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1121 if (const char *full_name
= p
.get_full_name ())
1122 plugin_obj
->set ("fullName", new json::string (full_name
));
1124 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1125 if (const char *version
= p
.get_version ())
1126 plugin_obj
->set ("version", new json::string (version
));
1128 auto_vec
<json::object
*> m_plugin_objs
;
1130 my_plugin_visitor v
;
1131 vinfo
->for_each_plugin (v
);
1132 if (v
.m_plugin_objs
.length () > 0)
1134 json::array
*extensions_arr
= new json::array ();
1135 tool_obj
->set ("extensions", extensions_arr
);
1136 for (auto iter
: v
.m_plugin_objs
)
1137 extensions_arr
->append (iter
);
1141 /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other
1142 "extensions" (see toplev.cc: print_version). */
1147 /* Make a toolComponent object (SARIF v2.1.0 section 3.19) for what SARIF
1148 calls the "driver" (see SARIF v2.1.0 section 3.18.1). */
1151 sarif_builder::make_driver_tool_component_object () const
1153 json::object
*driver_obj
= new json::object ();
1155 if (m_context
->m_client_data_hooks
)
1156 if (const client_version_info
*vinfo
1157 = m_context
->m_client_data_hooks
->get_any_version_info ())
1159 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1160 if (const char *name
= vinfo
->get_tool_name ())
1161 driver_obj
->set ("name", new json::string (name
));
1163 /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
1164 if (char *full_name
= vinfo
->maybe_make_full_name ())
1166 driver_obj
->set ("fullName", new json::string (full_name
));
1170 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1171 if (const char *version
= vinfo
->get_version_string ())
1172 driver_obj
->set ("version", new json::string (version
));
1174 /* "informationUri" property (SARIF v2.1.0 section 3.19.17). */
1175 if (char *version_url
= vinfo
->maybe_make_version_url ())
1177 driver_obj
->set ("informationUri", new json::string (version_url
));
1182 /* "rules" property (SARIF v2.1.0 section 3.19.23). */
1183 driver_obj
->set ("rules", m_rules_arr
);
1188 /* If we've seen any CWE IDs, make an array for the "taxonomies" property
1189 (SARIF v2.1.0 section 3.14.8) of a run object, containting a singl
1190 toolComponent (3.19) as per 3.19.3, representing the CWE.
1192 Otherwise return NULL. */
1195 sarif_builder::maybe_make_taxonomies_array () const
1197 json::object
*cwe_obj
= maybe_make_cwe_taxonomy_object ();
1201 /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
1202 json::array
*taxonomies_arr
= new json::array ();
1203 taxonomies_arr
->append (cwe_obj
);
1204 return taxonomies_arr
;
1207 /* If we've seen any CWE IDs, make a toolComponent object
1208 (SARIF v2.1.0 section 3.19) representing the CWE taxonomy, as per 3.19.3.
1209 Populate the "taxa" property with all of the CWE IDs in m_cwe_id_set.
1211 Otherwise return NULL. */
1214 sarif_builder::maybe_make_cwe_taxonomy_object () const
1216 if (m_cwe_id_set
.is_empty ())
1219 json::object
*taxonomy_obj
= new json::object ();
1221 /* "name" property (SARIF v2.1.0 section 3.19.8). */
1222 taxonomy_obj
->set ("name", new json::string ("CWE"));
1224 /* "version" property (SARIF v2.1.0 section 3.19.13). */
1225 taxonomy_obj
->set ("version", new json::string ("4.7"));
1227 /* "organization" property (SARIF v2.1.0 section 3.19.18). */
1228 taxonomy_obj
->set ("organization", new json::string ("MITRE"));
1230 /* "shortDescription" property (SARIF v2.1.0 section 3.19.19). */
1231 json::object
*short_desc
1232 = make_multiformat_message_string ("The MITRE"
1233 " Common Weakness Enumeration");
1234 taxonomy_obj
->set ("shortDescription", short_desc
);
1236 /* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */
1237 json::array
*taxa_arr
= new json::array ();
1238 for (auto cwe_id
: m_cwe_id_set
)
1240 json::object
*cwe_taxon
1241 = make_reporting_descriptor_object_for_cwe_id (cwe_id
);
1242 taxa_arr
->append (cwe_taxon
);
1244 taxonomy_obj
->set ("taxa", taxa_arr
);
1246 return taxonomy_obj
;
1249 /* Make an artifact object (SARIF v2.1.0 section 3.24). */
1252 sarif_builder::make_artifact_object (const char *filename
)
1254 json::object
*artifact_obj
= new json::object ();
1256 /* "location" property (SARIF v2.1.0 section 3.24.2). */
1257 json::object
*artifact_loc_obj
= make_artifact_location_object (filename
);
1258 artifact_obj
->set ("location", artifact_loc_obj
);
1260 /* "contents" property (SARIF v2.1.0 section 3.24.8). */
1261 if (json::object
*artifact_content_obj
1262 = maybe_make_artifact_content_object (filename
))
1263 artifact_obj
->set ("contents", artifact_content_obj
);
1265 /* "sourceLanguage" property (SARIF v2.1.0 section 3.24.10). */
1266 if (m_context
->m_client_data_hooks
)
1267 if (const char *source_lang
1268 = m_context
->m_client_data_hooks
->maybe_get_sarif_source_language
1270 artifact_obj
->set ("sourceLanguage", new json::string (source_lang
));
1272 return artifact_obj
;
1275 /* Read all data from F_IN until EOF.
1276 Return a NULL-terminated buffer containing the data, which must be
1277 freed by the caller.
1278 Return NULL on errors. */
1281 read_until_eof (FILE *f_in
)
1283 /* Read content, allocating a buffer for it. */
1284 char *result
= NULL
;
1285 size_t total_sz
= 0;
1286 size_t alloc_sz
= 0;
1290 while ( (iter_sz_in
= fread (buf
, 1, sizeof (buf
), f_in
)) )
1292 gcc_assert (alloc_sz
>= total_sz
);
1293 size_t old_total_sz
= total_sz
;
1294 total_sz
+= iter_sz_in
;
1295 /* Allow 1 extra byte for 0-termination. */
1296 if (alloc_sz
< (total_sz
+ 1))
1298 size_t new_alloc_sz
= alloc_sz
? alloc_sz
* 2: total_sz
+ 1;
1299 result
= (char *)xrealloc (result
, new_alloc_sz
);
1300 alloc_sz
= new_alloc_sz
;
1302 memcpy (result
+ old_total_sz
, buf
, iter_sz_in
);
1308 /* 0-terminate the buffer. */
1309 gcc_assert (total_sz
< alloc_sz
);
1310 result
[total_sz
] = '\0';
1315 /* Read all data from FILENAME until EOF.
1316 Return a NULL-terminated buffer containing the data, which must be
1317 freed by the caller.
1318 Return NULL on errors. */
1321 maybe_read_file (const char *filename
)
1323 FILE *f_in
= fopen (filename
, "r");
1326 char *result
= read_until_eof (f_in
);
1331 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the
1332 full contents of FILENAME. */
1335 sarif_builder::maybe_make_artifact_content_object (const char *filename
) const
1337 char *text_utf8
= maybe_read_file (filename
);
1341 json::object
*artifact_content_obj
= new json::object ();
1342 artifact_content_obj
->set ("text", new json::string (text_utf8
));
1345 return artifact_content_obj
;
1348 /* Attempt to read the given range of lines from FILENAME; return
1349 a freshly-allocated 0-terminated buffer containing them, or NULL. */
1352 get_source_lines (const char *filename
,
1356 auto_vec
<char> result
;
1358 for (int line
= start_line
; line
<= end_line
; line
++)
1360 char_span line_content
= location_get_source_line (filename
, line
);
1361 if (!line_content
.get_buffer ())
1363 result
.reserve (line_content
.length () + 1);
1364 for (size_t i
= 0; i
< line_content
.length (); i
++)
1365 result
.quick_push (line_content
[i
]);
1366 result
.quick_push ('\n');
1368 result
.safe_push ('\0');
1370 return xstrdup (result
.address ());
1373 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the given
1374 run of lines within FILENAME (including the endpoints). */
1377 sarif_builder::maybe_make_artifact_content_object (const char *filename
,
1381 char *text_utf8
= get_source_lines (filename
, start_line
, end_line
);
1386 json::object
*artifact_content_obj
= new json::object ();
1387 artifact_content_obj
->set ("text", new json::string (text_utf8
));
1390 return artifact_content_obj
;
1393 /* Make a fix object (SARIF v2.1.0 section 3.55) for RICHLOC. */
1396 sarif_builder::make_fix_object (const rich_location
&richloc
)
1398 json::object
*fix_obj
= new json::object ();
1400 /* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */
1401 /* We assume that all fix-it hints in RICHLOC affect the same file. */
1402 json::array
*artifact_change_arr
= new json::array ();
1403 json::object
*artifact_change_obj
= make_artifact_change_object (richloc
);
1404 artifact_change_arr
->append (artifact_change_obj
);
1405 fix_obj
->set ("artifactChanges", artifact_change_arr
);
1410 /* Make an artifactChange object (SARIF v2.1.0 section 3.56) for RICHLOC. */
1413 sarif_builder::make_artifact_change_object (const rich_location
&richloc
)
1415 json::object
*artifact_change_obj
= new json::object ();
1417 /* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */
1418 json::object
*artifact_location_obj
1419 = make_artifact_location_object (richloc
.get_loc ());
1420 artifact_change_obj
->set ("artifactLocation", artifact_location_obj
);
1422 /* "replacements" property (SARIF v2.1.0 section 3.56.3). */
1423 json::array
*replacement_arr
= new json::array ();
1424 for (unsigned int i
= 0; i
< richloc
.get_num_fixit_hints (); i
++)
1426 const fixit_hint
*hint
= richloc
.get_fixit_hint (i
);
1427 json::object
*replacement_obj
= make_replacement_object (*hint
);
1428 replacement_arr
->append (replacement_obj
);
1430 artifact_change_obj
->set ("replacements", replacement_arr
);
1432 return artifact_change_obj
;
1435 /* Make a replacement object (SARIF v2.1.0 section 3.57) for HINT. */
1438 sarif_builder::make_replacement_object (const fixit_hint
&hint
) const
1440 json::object
*replacement_obj
= new json::object ();
1442 /* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */
1443 json::object
*region_obj
= make_region_object_for_hint (hint
);
1444 replacement_obj
->set ("deletedRegion", region_obj
);
1446 /* "insertedContent" property (SARIF v2.1.0 section 3.57.4). */
1447 json::object
*content_obj
= make_artifact_content_object (hint
.get_string ());
1448 replacement_obj
->set ("insertedContent", content_obj
);
1450 return replacement_obj
;
1453 /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for TEXT. */
1456 sarif_builder::make_artifact_content_object (const char *text
) const
1458 json::object
*content_obj
= new json::object ();
1460 /* "text" property (SARIF v2.1.0 section 3.3.2). */
1461 content_obj
->set ("text", new json::string (text
));
1466 /* No-op implementation of "begin_diagnostic" for SARIF output. */
1469 sarif_begin_diagnostic (diagnostic_context
*, diagnostic_info
*)
1473 /* Implementation of "end_diagnostic" for SARIF output. */
1476 sarif_end_diagnostic (diagnostic_context
*context
, diagnostic_info
*diagnostic
,
1477 diagnostic_t orig_diag_kind
)
1479 gcc_assert (the_builder
);
1480 the_builder
->end_diagnostic (context
, diagnostic
, orig_diag_kind
);
1483 /* No-op implementation of "begin_group_cb" for SARIF output. */
1486 sarif_begin_group (diagnostic_context
*)
1490 /* Implementation of "end_group_cb" for SARIF output. */
1493 sarif_end_group (diagnostic_context
*)
1495 gcc_assert (the_builder
);
1496 the_builder
->end_group ();
1499 /* Flush the top-level array to OUTF. */
1502 sarif_flush_to_file (FILE *outf
)
1504 gcc_assert (the_builder
);
1505 the_builder
->flush_to_file (outf
);
1510 /* Callback for final cleanup for SARIF output to stderr. */
1513 sarif_stderr_final_cb (diagnostic_context
*)
1515 gcc_assert (the_builder
);
1516 sarif_flush_to_file (stderr
);
1519 static char *sarif_output_base_file_name
;
1521 /* Callback for final cleanup for SARIF output to a file. */
1524 sarif_file_final_cb (diagnostic_context
*)
1526 char *filename
= concat (sarif_output_base_file_name
, ".sarif", NULL
);
1527 FILE *outf
= fopen (filename
, "w");
1530 const char *errstr
= xstrerror (errno
);
1531 fnotice (stderr
, "error: unable to open '%s' for writing: %s\n",
1536 gcc_assert (the_builder
);
1537 sarif_flush_to_file (outf
);
1542 /* Populate CONTEXT in preparation for SARIF output (either to stderr, or
1546 diagnostic_output_format_init_sarif (diagnostic_context
*context
)
1548 the_builder
= new sarif_builder (context
);
1550 /* Override callbacks. */
1551 context
->begin_diagnostic
= sarif_begin_diagnostic
;
1552 context
->end_diagnostic
= sarif_end_diagnostic
;
1553 context
->begin_group_cb
= sarif_begin_group
;
1554 context
->end_group_cb
= sarif_end_group
;
1555 context
->print_path
= NULL
; /* handled in sarif_end_diagnostic. */
1557 /* The metadata is handled in SARIF format, rather than as text. */
1558 context
->show_cwe
= false;
1559 context
->show_rules
= false;
1561 /* The option is handled in SARIF format, rather than as text. */
1562 context
->show_option_requested
= false;
1564 /* Don't colorize the text. */
1565 pp_show_color (context
->printer
) = false;
1568 /* Populate CONTEXT in preparation for SARIF output to stderr. */
1571 diagnostic_output_format_init_sarif_stderr (diagnostic_context
*context
)
1573 diagnostic_output_format_init_sarif (context
);
1574 context
->final_cb
= sarif_stderr_final_cb
;
1577 /* Populate CONTEXT in preparation for SARIF output to a file named
1578 BASE_FILE_NAME.sarif. */
1581 diagnostic_output_format_init_sarif_file (diagnostic_context
*context
,
1582 const char *base_file_name
)
1584 diagnostic_output_format_init_sarif (context
);
1585 context
->final_cb
= sarif_file_final_cb
;
1586 sarif_output_base_file_name
= xstrdup (base_file_name
);