Branch data Line data Source code
1 : : /* SARIF output for diagnostics
2 : : Copyright (C) 2018-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
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/>. */
20 : :
21 : : #ifdef __MINGW32__
22 : : #include <winsock2.h>
23 : : #include <afunix.h>
24 : : #else
25 : : #include <sys/un.h>
26 : : #include <sys/socket.h>
27 : : #endif
28 : :
29 : : #include "config.h"
30 : : #define INCLUDE_LIST
31 : : #define INCLUDE_MAP
32 : : #define INCLUDE_STRING
33 : : #define INCLUDE_VECTOR
34 : : #include "system.h"
35 : : #include "coretypes.h"
36 : : #include "diagnostics/metadata.h"
37 : : #include "diagnostics/digraphs.h"
38 : : #include "diagnostics/state-graphs.h"
39 : : #include "diagnostics/paths.h"
40 : : #include "diagnostics/sink.h"
41 : : #include "diagnostics/buffering.h"
42 : : #include "diagnostics/dumping.h"
43 : : #include "diagnostics/logging.h"
44 : : #include "json.h"
45 : : #include "cpplib.h"
46 : : #include "diagnostics/logical-locations.h"
47 : : #include "diagnostics/client-data-hooks.h"
48 : : #include "diagnostics/diagram.h"
49 : : #include "text-art/canvas.h"
50 : : #include "diagnostics/sarif-sink.h"
51 : : #include "diagnostics/text-sink.h"
52 : : #include "ordered-hash-map.h"
53 : : #include "sbitmap.h"
54 : : #include "selftest.h"
55 : : #include "diagnostics/selftest-context.h"
56 : : #include "diagnostics/selftest-source-printing.h"
57 : : #include "selftest-json.h"
58 : : #include "text-range-label.h"
59 : : #include "pretty-print-format-impl.h"
60 : : #include "pretty-print-urlifier.h"
61 : : #include "demangle.h"
62 : : #include "backtrace.h"
63 : : #include "xml.h"
64 : : #include "intl.h"
65 : :
66 : : namespace diagnostics {
67 : :
68 : : /* A json::array where the values are "unique" as per
69 : : SARIF v2.1.0 section 3.7.3 ("Array properties with unique values"). */
70 : :
71 : : template <typename JsonElementType>
72 : : class sarif_array_of_unique : public json::array
73 : : {
74 : : public:
75 : 540 : size_t append_uniquely (std::unique_ptr<JsonElementType> val)
76 : : {
77 : : /* This should be O(log(n)) due to the std::map. */
78 : 540 : auto search = m_index_by_value.find (val.get ());
79 : 540 : if (search != m_index_by_value.end())
80 : 229 : return (*search).second;
81 : :
82 : 311 : const size_t insertion_idx = size ();
83 : 311 : m_index_by_value.insert ({val.get (), insertion_idx});
84 : 311 : append (std::move (val));
85 : 311 : return insertion_idx;
86 : : }
87 : :
88 : : /* For ease of reading output, add "index": idx to all
89 : : objects in the array.
90 : : We don't do this until we've added everything, since
91 : : the "index" property would otherwise confuse the
92 : : comparison against new elements. */
93 : 65 : void add_explicit_index_values ()
94 : : {
95 : 368 : for (size_t idx = 0; idx < length (); ++idx)
96 : 303 : if (json::object *obj = get (idx)->dyn_cast_object ())
97 : 303 : obj->set_integer ("index", idx);
98 : 65 : }
99 : :
100 : : private:
101 : : struct comparator_t {
102 : 5282 : bool operator () (const json::value *a, const json::value *b) const
103 : : {
104 : 5282 : gcc_assert (a);
105 : 5282 : gcc_assert (b);
106 : 5282 : return json::value::compare (*a, *b) < 0;
107 : : }
108 : : };
109 : :
110 : : // json::value * here is borrowed from m_elements
111 : : std::map<json::value *, int, comparator_t> m_index_by_value;
112 : : };
113 : :
114 : : /* Forward decls. */
115 : : class sarif_builder;
116 : : class content_renderer;
117 : : class escape_nonascii_renderer;
118 : :
119 : : /* Subclasses of sarif_object.
120 : : Keep these in order of their descriptions in the specification. */
121 : : class sarif_artifact_content; // 3.3
122 : : class sarif_artifact_location; // 3.4
123 : : class sarif_message; // 3.11
124 : : class sarif_multiformat_message_string; // 3.12
125 : : class sarif_log; // 3.13
126 : : class sarif_run; // 3.14
127 : : class sarif_tool; // 3.18
128 : : class sarif_tool_component; // 3.19
129 : : class sarif_invocation; // 3.20
130 : : class sarif_artifact; // 3.24
131 : : class sarif_location_manager; // not in the spec
132 : : class sarif_result; // 3.27
133 : : class sarif_location; // 3.28
134 : : class sarif_physical_location; // 3.29
135 : : class sarif_region; // 3.30
136 : : class sarif_logical_location; // 3.33
137 : : class sarif_location_relationship; // 3.34
138 : : class sarif_code_flow; // 3.36
139 : : class sarif_thread_flow; // 3.37
140 : : class sarif_thread_flow_location; // 3.38
141 : : class sarif_reporting_descriptor; // 3.49
142 : : class sarif_reporting_descriptor_reference; // 3.53
143 : : class sarif_tool_component_reference; // 3.54
144 : : class sarif_fix; // 3.55
145 : : class sarif_artifact_change; // 3.56
146 : : class sarif_replacement; // 3.57
147 : : class sarif_ice_notification; // 3.58
148 : :
149 : : // Valid values for locationRelationship's "kinds" property (3.34.3)
150 : :
151 : : enum class location_relationship_kind
152 : : {
153 : : includes,
154 : : is_included_by,
155 : : relevant,
156 : :
157 : : NUM_KINDS
158 : : };
159 : :
160 : : /* Declarations of subclasses of sarif_object.
161 : : Keep these in order of their descriptions in the specification. */
162 : :
163 : : /* Subclass of sarif_object for SARIF "artifactContent" objects
164 : : (SARIF v2.1.0 section 3.3). */
165 : :
166 : 907 : class sarif_artifact_content : public sarif_object {};
167 : :
168 : : /* Subclass of sarif_object for SARIF "artifactLocation" objects
169 : : (SARIF v2.1.0 section 3.4). */
170 : :
171 : 1753 : class sarif_artifact_location : public sarif_object {};
172 : :
173 : : /* Subclass of sarif_object for SARIF "message" objects
174 : : (SARIF v2.1.0 section 3.11). */
175 : :
176 : 1981 : class sarif_message : public sarif_object {};
177 : :
178 : : /* Subclass of sarif_object for SARIF "multiformatMessageString" objects
179 : : (SARIF v2.1.0 section 3.12). */
180 : :
181 : 158 : class sarif_multiformat_message_string : public sarif_object {};
182 : :
183 : : /* Subclass of sarif_object for SARIF "log" objects
184 : : (SARIF v2.1.0 section 3.13). */
185 : :
186 : 280 : class sarif_log : public sarif_object {};
187 : :
188 : : /* Subclass of sarif_object for SARIF "run" objects
189 : : (SARIF v2.1.0 section 3.14). */
190 : :
191 : 280 : class sarif_run : public sarif_object {};
192 : :
193 : : /* Subclass of sarif_object for SARIF "tool" objects
194 : : (SARIF v2.1.0 section 3.18). */
195 : :
196 : 280 : class sarif_tool : public sarif_object {};
197 : :
198 : : /* Subclass of sarif_object for SARIF "toolComponent" objects
199 : : (SARIF v2.1.0 section 3.19). */
200 : :
201 : 313 : class sarif_tool_component : public sarif_object {};
202 : :
203 : : /* Make a JSON string for the current date and time.
204 : : See SARIF v2.1.0 section 3.9 "Date/time properties".
205 : : Given that we don't run at the very beginning/end of the
206 : : process, it doesn't make sense to be more accurate than
207 : : the current second. */
208 : :
209 : : static std::unique_ptr<json::string>
210 : 696 : make_date_time_string_for_current_time ()
211 : : {
212 : 696 : time_t t = time (nullptr);
213 : 696 : struct tm *tm = gmtime (&t);
214 : 696 : char buf[256];
215 : 696 : snprintf (buf, sizeof (buf) - 1,
216 : : ("%04i-%02i-%02iT"
217 : : "%02i:%02i:%02iZ"),
218 : 696 : tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
219 : : tm->tm_hour, tm->tm_min, tm->tm_sec);
220 : 696 : return std::make_unique<json::string> (buf);
221 : : }
222 : :
223 : : /* Subclass of sarif_object for SARIF "invocation" objects
224 : : (SARIF v2.1.0 section 3.20). */
225 : :
226 : : class sarif_invocation : public sarif_object
227 : : {
228 : : public:
229 : : sarif_invocation (sarif_builder &builder,
230 : : const char * const *original_argv);
231 : :
232 : : void add_notification_for_ice (const diagnostic_info &diagnostic,
233 : : sarif_builder &builder,
234 : : std::unique_ptr<json::object> backtrace);
235 : : void prepare_to_flush (sarif_builder &builder);
236 : :
237 : : private:
238 : : std::unique_ptr<json::array> m_notifications_arr;
239 : : bool m_success;
240 : : };
241 : :
242 : : /* Corresponds to values for the SARIF artifact objects "roles" property.
243 : : (SARIF v2.1.0 section 3.24.6). */
244 : :
245 : : enum class diagnostic_artifact_role
246 : : {
247 : : analysis_target, /* "analysisTarget". */
248 : : debug_output_file, /* "debugOutputFile". */
249 : : result_file, /* "resultFile". */
250 : :
251 : : /* "scannedFile" added in 2.2;
252 : : see https://github.com/oasis-tcs/sarif-spec/issues/459 */
253 : : scanned_file,
254 : :
255 : : traced_file, /* "tracedFile". */
256 : :
257 : : NUM_ROLES
258 : : };
259 : :
260 : : /* Subclass of sarif_object for SARIF artifact objects
261 : : (SARIF v2.1.0 section 3.24). */
262 : :
263 : : class sarif_artifact : public sarif_object
264 : : {
265 : : public:
266 : 434 : sarif_artifact (const char *filename)
267 : 868 : : m_filename (filename),
268 : 868 : m_roles ((unsigned)diagnostic_artifact_role::NUM_ROLES),
269 : 434 : m_embed_contents (false)
270 : : {
271 : 434 : bitmap_clear (m_roles);
272 : 434 : }
273 : :
274 : : void add_role (enum diagnostic_artifact_role role,
275 : : bool embed_contents);
276 : :
277 : 298 : bool embed_contents_p () const { return m_embed_contents; }
278 : : void populate_contents (sarif_builder &builder);
279 : : void populate_roles ();
280 : :
281 : : private:
282 : : const char *m_filename;
283 : : auto_sbitmap m_roles;
284 : :
285 : : /* Flag to track whether this artifact should have a "contents" property
286 : : (SARIF v2.1.0 section 3.24.8).
287 : : We only add the contents for those artifacts that have a location
288 : : referencing them (so that a consumer might want to quote the source). */
289 : : bool m_embed_contents;
290 : : };
291 : :
292 : : /* A class for sarif_objects that own a "namespace" of numeric IDs for
293 : : managing location objects within them. Currently (SARIF v2.1.0)
294 : : this is just for sarif_result (section 3.28.2), but it will likely
295 : : eventually also be for notification objects; see
296 : : https://github.com/oasis-tcs/sarif-spec/issues/540
297 : :
298 : : Consider locations with chains of include information e.g.
299 : :
300 : : > include-chain-1.c:
301 : : > #include "include-chain-1.h"
302 : :
303 : : include-chain-1.h:
304 : : | // First set of decls, which will be referenced in notes
305 : : | #include "include-chain-1-1.h"
306 : : |
307 : : | // Second set of decls, which will trigger the errors
308 : : | #include "include-chain-1-2.h"
309 : :
310 : : include-chain-1-1.h:
311 : : | int p;
312 : : | int q;
313 : :
314 : : include-chain-1-1.h:
315 : : | char p;
316 : : | char q;
317 : :
318 : : GCC's textual output emits:
319 : : | In file included from PATH/include-chain-1.h:5,
320 : : | from PATH/include-chain-1.c:30:
321 : : | PATH/include-chain-1-2.h:1:6: error: conflicting types for 'p'; have 'char'
322 : : | 1 | char p;
323 : : | | ^
324 : : | In file included from PATH/include-chain-1.h:2:
325 : : | PATH/include-chain-1-1.h:1:5: note: previous declaration of 'p' with type 'int'
326 : : | 1 | int p;
327 : : | | ^
328 : : | PATH/include-chain-1-2.h:2:6: error: conflicting types for 'q'; have 'char'
329 : : | 2 | char q;
330 : : | | ^
331 : : | PATH/include-chain-1-1.h:2:5: note: previous declaration of 'q' with type 'int'
332 : : | 2 | int q;
333 : : | | ^
334 : :
335 : : Whenever a SARIF location is added for a location_t that
336 : : was #included from somewhere, we queue up the creation of a SARIF
337 : : location for the location of the #include. The worklist of queued
338 : : locations is flushed when the result is finished, which lazily creates
339 : : any additional related locations for the include chain, and the
340 : : relationships between the locations. Doing so can lead to further
341 : : include locations being processed. The worklist approach allows us
342 : : to lazily explore the relevant part of the directed graph of location_t
343 : : values implicit in our line_maps structure, replicating it as a directed
344 : : graph of SARIF locations within the SARIF result object, like this:
345 : :
346 : : [0]: error in include-chain-1-2.h ("conflicting types for 'p'; have 'char'")
347 : : [1]: #include "include-chain-1-2.h" in include-chain-1.h
348 : : [2]: note in include-chain-1-2.h ("previous declaration of 'p' with type 'int'")
349 : : [3]: #include "include-chain-1-1.h" in include-chain-1.h
350 : : [4]: #include "include-chain-1.h" in include-chain-1.c
351 : :
352 : : where we want to capture this "includes" graph in SARIF form:
353 : : . +-----------------------------------+ +----------------------------------+
354 : : . |"id": 0 | |"id": 2 |
355 : : . | error: "conflicting types for 'p';| | note: previous declaration of 'p'|
356 : : . | have 'char'"| | | with type 'int'") |
357 : : . | in include-chain-1-2.h | | in include-chain-1-1.h |
358 : : . +-----------------------------------+ +----------------------------------+
359 : : . ^ | ^ |
360 : : . includes | | included-by includes | | included-by
361 : : . | V | V
362 : : . +--------------------------------+ +--------------------------------+
363 : : . |"id": 1 | |"id": 3 |
364 : : . | #include "include-chain-1-2.h" | | #include "include-chain-1-1.h" |
365 : : . | in include-chain-1.h | | in include-chain-1.h |
366 : : . +--------------------------------+ +--------------------------------+
367 : : . ^ | ^ |
368 : : . includes | | included-by includes | | included-by
369 : : . | V | V
370 : : . +------------------------------------+
371 : : . |"id": 4 |
372 : : . | The #include "include-chain-1.h" |
373 : : . | in include-chain-1.c |
374 : : . +------------------------------------+
375 : : */
376 : :
377 : : class sarif_location_manager : public sarif_object
378 : : {
379 : : public:
380 : : /* A worklist of pending actions needed to fully process this object.
381 : :
382 : : This lets us lazily walk our data structures to build the
383 : : directed graph of locations, whilst keeping "notes" at the top
384 : : of the "relatedLocations" array, and avoiding the need for
385 : : recursion. */
386 : : struct worklist_item
387 : : {
388 : : enum class kind
389 : : {
390 : : /* Process a #include relationship where m_location_obj
391 : : was #included-d at m_where. */
392 : : included_from,
393 : :
394 : : /* Process a location_t that was added as a secondary location
395 : : to a rich_location without a label. */
396 : : unlabelled_secondary_location
397 : : };
398 : :
399 : 27 : worklist_item (sarif_location &location_obj,
400 : : enum kind kind,
401 : : location_t where)
402 : 27 : : m_location_obj (location_obj),
403 : 27 : m_kind (kind),
404 : 27 : m_where (where)
405 : : {
406 : : }
407 : :
408 : : sarif_location &m_location_obj;
409 : : enum kind m_kind;
410 : : location_t m_where;
411 : : };
412 : :
413 : 612 : sarif_location_manager ()
414 : 1224 : : m_related_locations_arr (nullptr),
415 : 612 : m_next_location_id (0)
416 : : {
417 : 612 : }
418 : :
419 : 39 : unsigned allocate_location_id ()
420 : : {
421 : 39 : return m_next_location_id++;
422 : : }
423 : :
424 : : virtual void
425 : : add_related_location (std::unique_ptr<sarif_location> location_obj,
426 : : sarif_builder &builder);
427 : :
428 : : void
429 : : add_relationship_to_worklist (sarif_location &location_obj,
430 : : enum worklist_item::kind kind,
431 : : location_t where);
432 : :
433 : : void
434 : : process_worklist (sarif_builder &builder);
435 : :
436 : : void
437 : : process_worklist_item (sarif_builder &builder,
438 : : const worklist_item &item);
439 : : private:
440 : : json::array *m_related_locations_arr; // borrowed
441 : : unsigned m_next_location_id;
442 : :
443 : : std::list<worklist_item> m_worklist;
444 : : std::map<location_t, sarif_location *> m_included_from_locations;
445 : : std::map<location_t, sarif_location *> m_unlabelled_secondary_locations;
446 : : };
447 : :
448 : : /* Subclass of sarif_object for SARIF "result" objects
449 : : (SARIF v2.1.0 section 3.27).
450 : : Each SARIF result object has its own "namespace" of numeric IDs for
451 : : managing location objects (SARIF v2.1.0 section 3.28.2). */
452 : :
453 : 256 : class sarif_result : public sarif_location_manager
454 : : {
455 : : public:
456 : 606 : sarif_result (unsigned idx_within_parent)
457 : 478 : : m_idx_within_parent (idx_within_parent)
458 : : {}
459 : :
460 : 17 : unsigned get_index_within_parent () const { return m_idx_within_parent; }
461 : :
462 : : void
463 : : on_nested_diagnostic (const diagnostic_info &diagnostic,
464 : : enum kind orig_diag_kind,
465 : : sarif_builder &builder);
466 : : void on_diagram (const diagram &d,
467 : : sarif_builder &builder);
468 : :
469 : : private:
470 : : const unsigned m_idx_within_parent;
471 : : };
472 : :
473 : : /* Subclass of sarif_object for SARIF "location" objects
474 : : (SARIF v2.1.0 section 3.28).
475 : : A location object can have an "id" which must be unique within
476 : : the enclosing result, if any (see SARIF v2.1.0 section 3.28.2). */
477 : :
478 : 956 : class sarif_location : public sarif_object
479 : : {
480 : : public:
481 : : long lazily_add_id (sarif_location_manager &loc_mgr);
482 : : long get_id () const;
483 : :
484 : : void lazily_add_relationship (sarif_location &target,
485 : : enum location_relationship_kind kind,
486 : : sarif_location_manager &loc_mgr);
487 : :
488 : : private:
489 : : sarif_location_relationship &
490 : : lazily_add_relationship_object (sarif_location &target,
491 : : sarif_location_manager &loc_mgr);
492 : :
493 : : json::array &lazily_add_relationships_array ();
494 : :
495 : : std::map<sarif_location *,
496 : : sarif_location_relationship *> m_relationships_map;
497 : : };
498 : :
499 : : /* Subclass of sarif_object for SARIF "physicalLocation" objects
500 : : (SARIF v2.1.0 section 3.29). */
501 : :
502 : 850 : class sarif_physical_location : public sarif_object {};
503 : :
504 : : /* Subclass of sarif_object for SARIF "region" objects
505 : : (SARIF v2.1.0 section 3.30). */
506 : :
507 : 2111 : class sarif_region : public sarif_object {};
508 : :
509 : : /* Subclass of sarif_object for SARIF "logicalLocation" objects
510 : : (SARIF v2.1.0 section 3.33). */
511 : :
512 : 781 : class sarif_logical_location : public sarif_object
513 : : {
514 : : };
515 : :
516 : : /* Subclass of sarif_object for SARIF "locationRelationship" objects
517 : : (SARIF v2.1.0 section 3.34). */
518 : :
519 : : class sarif_location_relationship : public sarif_object
520 : : {
521 : : public:
522 : : sarif_location_relationship (sarif_location &target,
523 : : sarif_location_manager &loc_mgr);
524 : :
525 : : long get_target_id () const;
526 : :
527 : : void lazily_add_kind (enum location_relationship_kind kind);
528 : :
529 : : private:
530 : : auto_sbitmap m_kinds;
531 : : };
532 : :
533 : : /* Subclass of sarif_object for SARIF "codeFlow" objects
534 : : (SARIF v2.1.0 section 3.36). */
535 : :
536 : : class sarif_code_flow : public sarif_object
537 : : {
538 : : public:
539 : : sarif_code_flow (sarif_result &parent,
540 : : unsigned idx_within_parent);
541 : :
542 : 17 : sarif_result &get_parent () const { return m_parent; }
543 : 17 : unsigned get_index_within_parent () const { return m_idx_within_parent; }
544 : :
545 : : sarif_thread_flow &
546 : : get_or_append_thread_flow (const paths::thread &thread,
547 : : paths::thread_id_t thread_id);
548 : :
549 : : sarif_thread_flow &
550 : : get_thread_flow (paths::thread_id_t thread_id);
551 : :
552 : : void add_location (sarif_thread_flow_location &);
553 : :
554 : : sarif_thread_flow_location &
555 : : get_thread_flow_loc_obj (paths::event_id_t event_id) const;
556 : :
557 : : private:
558 : : sarif_result &m_parent;
559 : : const unsigned m_idx_within_parent;
560 : :
561 : : hash_map<int_hash<paths::thread_id_t, -1, -2>,
562 : : sarif_thread_flow *> m_thread_id_map; // borrowed ptr
563 : : json::array *m_thread_flows_arr; // borrowed
564 : :
565 : : /* Vec of borrowed ptr, allowing for going easily from
566 : : an event_id to the corresponding threadFlowLocation object. */
567 : : std::vector<sarif_thread_flow_location *> m_all_tfl_objs;
568 : : };
569 : :
570 : : /* Subclass of sarif_object for SARIF "threadFlow" objects
571 : : (SARIF v2.1.0 section 3.37). */
572 : :
573 : : class sarif_thread_flow : public sarif_object
574 : : {
575 : : public:
576 : : sarif_thread_flow (sarif_code_flow &parent,
577 : : const paths::thread &thread,
578 : : unsigned idx_within_parent);
579 : :
580 : 17 : sarif_code_flow &get_parent () const { return m_parent; }
581 : 17 : unsigned get_index_within_parent () const { return m_idx_within_parent; }
582 : :
583 : : sarif_thread_flow_location &add_location ();
584 : :
585 : : private:
586 : : sarif_code_flow &m_parent;
587 : : json::array *m_locations_arr; // borrowed
588 : : const unsigned m_idx_within_parent;
589 : : };
590 : :
591 : : /* Subclass of sarif_object for SARIF "threadFlowLocation" objects
592 : : (SARIF v2.1.0 section 3.38). */
593 : :
594 : : class sarif_thread_flow_location : public sarif_object
595 : : {
596 : : public:
597 : 164 : sarif_thread_flow_location (sarif_thread_flow &parent,
598 : : unsigned idx_within_parent)
599 : 328 : : m_parent (parent),
600 : 328 : m_idx_within_parent (idx_within_parent)
601 : : {
602 : : }
603 : :
604 : 17 : sarif_thread_flow &get_parent () const { return m_parent; }
605 : 17 : unsigned get_index_within_parent () const { return m_idx_within_parent; }
606 : :
607 : : private:
608 : : sarif_thread_flow &m_parent;
609 : : const unsigned m_idx_within_parent;
610 : : };
611 : :
612 : : /* Subclass of sarif_object for SARIF "reportingDescriptor" objects
613 : : (SARIF v2.1.0 section 3.49). */
614 : :
615 : 88 : class sarif_reporting_descriptor : public sarif_object {};
616 : :
617 : : /* Subclass of sarif_object for SARIF "reportingDescriptorReference" objects
618 : : (SARIF v2.1.0 section 3.53). */
619 : :
620 : 25 : class sarif_reporting_descriptor_reference : public sarif_object {};
621 : :
622 : : /* Subclass of sarif_object for SARIF "toolComponentReference" objects
623 : : (SARIF v2.1.0 section 3.54). */
624 : :
625 : 25 : class sarif_tool_component_reference : public sarif_object {};
626 : :
627 : : /* Subclass of sarif_object for SARIF "fix" objects
628 : : (SARIF v2.1.0 section 3.55). */
629 : :
630 : 9 : class sarif_fix : public sarif_object {};
631 : :
632 : : /* Subclass of sarif_object for SARIF "artifactChange" objects
633 : : (SARIF v2.1.0 section 3.56). */
634 : :
635 : 9 : class sarif_artifact_change : public sarif_object {};
636 : :
637 : : /* Subclass of sarif_object for SARIF "replacement" objects
638 : : (SARIF v2.1.0 section 3.57). */
639 : :
640 : 9 : class sarif_replacement : public sarif_object {};
641 : :
642 : : /* Subclass of sarif_object for SARIF "notification" objects
643 : : (SARIF v2.1.0 section 3.58).
644 : :
645 : : This subclass is specifically for notifying when an
646 : : internal compiler error occurs. */
647 : :
648 : : class sarif_ice_notification : public sarif_location_manager
649 : : {
650 : : public:
651 : : sarif_ice_notification (const diagnostic_info &diagnostic,
652 : : sarif_builder &builder,
653 : : std::unique_ptr<json::object> backtrace);
654 : :
655 : : void
656 : : add_related_location (std::unique_ptr<sarif_location> location_obj,
657 : : sarif_builder &builder) final override;
658 : : };
659 : :
660 : : /* Abstract base class for use when making an "artifactContent"
661 : : object (SARIF v2.1.0 section 3.3): generate a value for the
662 : : 3.3.4 "rendered" property.
663 : : Can return nullptr, for "no property". */
664 : :
665 : 767 : class content_renderer
666 : : {
667 : : public:
668 : 767 : virtual ~content_renderer () {}
669 : :
670 : : virtual std::unique_ptr<sarif_multiformat_message_string>
671 : : render (const sarif_builder &builder) const = 0;
672 : : };
673 : :
674 : : /* Concrete buffering implementation subclass for SARIF output. */
675 : :
676 : : class sarif_sink_buffer : public per_sink_buffer
677 : : {
678 : : public:
679 : : friend class sarif_sink;
680 : :
681 : 17 : sarif_sink_buffer (sarif_builder &builder)
682 : 17 : : m_builder (builder)
683 : : {}
684 : :
685 : : void dump (FILE *out, int indent) const final override;
686 : : bool empty_p () const final override;
687 : : void move_to (per_sink_buffer &dest) final override;
688 : : void clear () final override;
689 : : void flush () final override;
690 : :
691 : 21 : void add_result (std::unique_ptr<sarif_result> result)
692 : : {
693 : 42 : m_results.push_back (std::move (result));
694 : : }
695 : :
696 : : size_t num_results () const { return m_results.size (); }
697 : : sarif_result &get_result (size_t idx) { return *m_results[idx]; }
698 : :
699 : : private:
700 : : sarif_builder &m_builder;
701 : : std::vector<std::unique_ptr<sarif_result>> m_results;
702 : : };
703 : :
704 : : /* Classes for abstracting away JSON vs other serialization formats. */
705 : :
706 : : // class sarif_serialization_format_json : public sarif_serialization_format
707 : :
708 : : void
709 : 112 : sarif_serialization_format_json::write_to_file (FILE *outf,
710 : : const json::value &top)
711 : : {
712 : 112 : top.dump (outf, m_formatted);
713 : 112 : fprintf (outf, "\n");
714 : 112 : }
715 : :
716 : : void
717 : 0 : sarif_serialization_format_json::dump (FILE *outfile, int indent) const
718 : : {
719 : 0 : dumping::emit_indent (outfile, indent);
720 : 0 : fprintf (outfile, "json\n");
721 : 0 : DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_formatted);
722 : 0 : }
723 : :
724 : : /* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
725 : : and -fdiagnostics-format=sarif-file).
726 : :
727 : : As diagnostics occur, we build "result" JSON objects, and
728 : : accumulate state:
729 : : - which source files are referenced
730 : : - which warnings are emitted
731 : : - which CWEs are used
732 : :
733 : : At the end of the compile, we use the above to build the full SARIF
734 : : object tree, adding the result objects to the correct place, and
735 : : creating objects for the various source files, warnings and CWEs
736 : : referenced.
737 : :
738 : : Implemented:
739 : : - fix-it hints
740 : : - CWE metadata
741 : : - diagnostic groups (see limitations below)
742 : : - logical locations (e.g. cfun)
743 : : - labelled ranges (as annotations)
744 : : - secondary ranges without labels (as related locations)
745 : :
746 : : Known limitations:
747 : : - GCC supports nesting of diagnostics (one-deep nesting via
748 : : auto_diagnostic_group, and arbitrary nesting via
749 : : auto_diagnostic_nesting_level). These are captured in the SARIF
750 : : as related locations, and so we only capture location and message
751 : : information from such nested diagnostics (e.g. we ignore fix-it
752 : : hints on them). Diagnostics within an auto_diagnostic_nesting_level
753 : : have their nesting level captured as a property.
754 : : - although we capture command-line arguments (section 3.20.2), we don't
755 : : yet capture response files.
756 : : - doesn't capture "artifact.encoding" property
757 : : (SARIF v2.1.0 section 3.24.9).
758 : : - doesn't capture hashes of the source files
759 : : ("artifact.hashes" property (SARIF v2.1.0 section 3.24.11).
760 : : - doesn't capture the "analysisTarget" property
761 : : (SARIF v2.1.0 section 3.27.13).
762 : : - doesn't capture -Werror cleanly
763 : : - doesn't capture inlining information (can SARIF handle this?)
764 : : - doesn't capture macro expansion information (can SARIF handle this?).
765 : : - doesn't capture any diagnostics::metadata::rules associated with
766 : : a diagnostic. */
767 : :
768 : : class sarif_builder
769 : : {
770 : : public:
771 : : friend class sarif_sink_buffer;
772 : :
773 : : sarif_builder (diagnostics::context &dc,
774 : : pretty_printer &printer,
775 : : const line_maps *line_maps,
776 : : std::unique_ptr<sarif_serialization_format> serialization_format,
777 : : const sarif_generation_options &sarif_gen_opts);
778 : : ~sarif_builder ();
779 : :
780 : : void dump (FILE *out, int indent) const;
781 : :
782 : 288 : void set_printer (pretty_printer &printer)
783 : : {
784 : 288 : m_printer = &printer;
785 : : }
786 : :
787 : : const logical_locations::manager *
788 : : get_logical_location_manager () const
789 : : {
790 : : return m_logical_loc_mgr;
791 : : }
792 : :
793 : : void
794 : : set_main_input_filename (const char *name);
795 : :
796 : : void on_report_diagnostic (const diagnostic_info &diagnostic,
797 : : enum kind orig_diag_kind,
798 : : sarif_sink_buffer *buffer);
799 : : void emit_diagram (const diagram &d);
800 : : void end_group ();
801 : :
802 : : void
803 : : report_global_digraph (const lazily_created<digraphs::digraph> &);
804 : :
805 : 288 : std::unique_ptr<sarif_result> take_current_result ()
806 : : {
807 : 288 : return std::move (m_cur_group_result);
808 : : }
809 : :
810 : : std::unique_ptr<sarif_log> flush_to_object ();
811 : : void flush_to_file (FILE *outf);
812 : :
813 : : std::unique_ptr<json::array>
814 : : make_locations_arr (sarif_location_manager &loc_mgr,
815 : : const diagnostic_info &diagnostic,
816 : : enum diagnostic_artifact_role role);
817 : : std::unique_ptr<sarif_location>
818 : : make_location_object (sarif_location_manager *loc_mgr,
819 : : const rich_location &rich_loc,
820 : : logical_locations::key logical_loc,
821 : : enum diagnostic_artifact_role role);
822 : : std::unique_ptr<sarif_location>
823 : : make_location_object (sarif_location_manager &loc_mgr,
824 : : location_t where,
825 : : enum diagnostic_artifact_role role);
826 : : std::unique_ptr<sarif_message>
827 : : make_message_object (const char *msg) const;
828 : : std::unique_ptr<sarif_message>
829 : : make_message_object_for_diagram (const diagram &d);
830 : : std::unique_ptr<sarif_artifact_content>
831 : : maybe_make_artifact_content_object (const char *filename) const;
832 : :
833 : : std::unique_ptr<sarif_artifact_location>
834 : : make_artifact_location_object (const char *filename);
835 : :
836 : : const sarif_code_flow *
837 : 114 : get_code_flow_for_event_ids () const
838 : : {
839 : 114 : return m_current_code_flow;
840 : : }
841 : :
842 : 402 : diagnostics::context &get_context () const { return m_context; }
843 : 410 : pretty_printer *get_printer () const { return m_printer; }
844 : 288 : token_printer &get_token_printer () { return m_token_printer; }
845 : 560 : enum sarif_version get_version () const { return m_sarif_gen_opts.m_version; }
846 : :
847 : 96 : size_t num_results () const { return m_results_array->size (); }
848 : 16 : sarif_result &get_result (size_t idx)
849 : : {
850 : 16 : auto element = (*m_results_array)[idx];
851 : 16 : gcc_assert (element);
852 : 16 : return *static_cast<sarif_result *> (element);
853 : : }
854 : :
855 : : const sarif_generation_options &get_opts () const { return m_sarif_gen_opts; }
856 : :
857 : : std::unique_ptr<sarif_logical_location>
858 : : make_minimal_sarif_logical_location (logical_locations::key);
859 : :
860 : : private:
861 : 416 : class sarif_token_printer : public token_printer
862 : : {
863 : : public:
864 : 416 : sarif_token_printer (sarif_builder &builder)
865 : 416 : : m_builder (builder)
866 : : {
867 : : }
868 : : void print_tokens (pretty_printer *pp,
869 : : const pp_token_list &tokens) final override;
870 : : private:
871 : : sarif_builder &m_builder;
872 : : };
873 : :
874 : : std::unique_ptr<sarif_result>
875 : : make_result_object (const diagnostic_info &diagnostic,
876 : : enum kind orig_diag_kind,
877 : : unsigned idx_within_parent);
878 : : void
879 : : add_any_include_chain (sarif_location_manager &loc_mgr,
880 : : sarif_location &location_obj,
881 : : location_t where);
882 : : void
883 : : set_any_logical_locs_arr (sarif_location &location_obj,
884 : : logical_locations::key logical_loc);
885 : : std::unique_ptr<sarif_location>
886 : : make_location_object (sarif_location_manager &loc_mgr,
887 : : const paths::event &event,
888 : : enum diagnostic_artifact_role role);
889 : : std::unique_ptr<sarif_code_flow>
890 : : make_code_flow_object (sarif_result &result,
891 : : unsigned idx_within_parent,
892 : : const paths::path &path);
893 : : void
894 : : populate_thread_flow_location_object (sarif_result &result,
895 : : sarif_thread_flow_location &thread_flow_loc_obj,
896 : : const paths::event &event,
897 : : int event_execution_idx);
898 : : std::unique_ptr<json::array>
899 : : maybe_make_kinds_array (paths::event::meaning m) const;
900 : : std::unique_ptr<sarif_physical_location>
901 : : maybe_make_physical_location_object (location_t loc,
902 : : enum diagnostic_artifact_role role,
903 : : int column_override,
904 : : const content_renderer *snippet_renderer);
905 : : std::unique_ptr<sarif_artifact_location>
906 : : make_artifact_location_object (location_t loc);
907 : : std::unique_ptr<sarif_artifact_location>
908 : : make_artifact_location_object_for_pwd () const;
909 : : std::unique_ptr<sarif_region>
910 : : maybe_make_region_object (location_t loc,
911 : : int column_override) const;
912 : : std::unique_ptr<sarif_region>
913 : : maybe_make_region_object_for_context (location_t loc,
914 : : const content_renderer *snippet_renderer) const;
915 : : std::unique_ptr<sarif_region>
916 : : make_region_object_for_hint (const fixit_hint &hint) const;
917 : :
918 : : int
919 : : ensure_sarif_logical_location_for (logical_locations::key k);
920 : :
921 : : std::unique_ptr<sarif_multiformat_message_string>
922 : : make_multiformat_message_string (const char *msg) const;
923 : : std::unique_ptr<sarif_log>
924 : : make_top_level_object (std::unique_ptr<sarif_invocation> invocation_obj,
925 : : std::unique_ptr<json::array> results);
926 : : std::unique_ptr<sarif_run>
927 : : make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
928 : : std::unique_ptr<json::array> results);
929 : : std::unique_ptr<sarif_tool>
930 : : make_tool_object ();
931 : : std::unique_ptr<sarif_tool_component>
932 : : make_driver_tool_component_object ();
933 : : std::unique_ptr<json::array> maybe_make_taxonomies_array () const;
934 : : std::unique_ptr<sarif_tool_component>
935 : : maybe_make_cwe_taxonomy_object () const;
936 : : std::unique_ptr<sarif_tool_component_reference>
937 : : make_tool_component_reference_object_for_cwe () const;
938 : : std::unique_ptr<sarif_reporting_descriptor>
939 : : make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic,
940 : : enum kind orig_diag_kind,
941 : : const char *option_text);
942 : : std::unique_ptr<sarif_reporting_descriptor>
943 : : make_reporting_descriptor_object_for_cwe_id (int cwe_id) const;
944 : : std::unique_ptr<sarif_reporting_descriptor_reference>
945 : : make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id);
946 : : sarif_artifact &
947 : : get_or_create_artifact (const char *filename,
948 : : enum diagnostic_artifact_role role,
949 : : bool embed_contents);
950 : : char *
951 : : get_source_lines (const char *filename,
952 : : int start_line,
953 : : int end_line) const;
954 : : std::unique_ptr<sarif_artifact_content>
955 : : maybe_make_artifact_content_object (const char *filename,
956 : : int start_line,
957 : : int end_line,
958 : : const content_renderer *r) const;
959 : : std::unique_ptr<sarif_message>
960 : : make_message_describing_fix_it_hint (const fixit_hint &hint) const;
961 : : std::unique_ptr<sarif_fix>
962 : : make_fix_object (const rich_location &rich_loc);
963 : : std::unique_ptr<sarif_artifact_change>
964 : : make_artifact_change_object (const rich_location &richloc);
965 : : std::unique_ptr<sarif_replacement>
966 : : make_replacement_object (const fixit_hint &hint) const;
967 : : std::unique_ptr<sarif_artifact_content>
968 : : make_artifact_content_object (const char *text) const;
969 : : int get_sarif_column (expanded_location exploc) const;
970 : :
971 : : std::unique_ptr<json::object>
972 : : make_stack_from_backtrace ();
973 : :
974 : : diagnostics::context &m_context;
975 : : pretty_printer *m_printer;
976 : : const line_maps *m_line_maps;
977 : : sarif_token_printer m_token_printer;
978 : :
979 : : const logical_locations::manager *m_logical_loc_mgr;
980 : :
981 : : /* The JSON object for the invocation object. */
982 : : std::unique_ptr<sarif_invocation> m_invocation_obj;
983 : :
984 : : /* The JSON array of pending diagnostics. */
985 : : std::unique_ptr<json::array> m_results_array;
986 : :
987 : : /* The JSON object for the result object (if any) in the current
988 : : diagnostic group. */
989 : : std::unique_ptr<sarif_result> m_cur_group_result;
990 : :
991 : : /* Ideally we'd use std::unique_ptr<sarif_artifact> here, but I had
992 : : trouble getting this to work when building with GCC 4.8. */
993 : : ordered_hash_map <nofree_string_hash,
994 : : sarif_artifact *> m_filename_to_artifact_map;
995 : :
996 : : bool m_seen_any_relative_paths;
997 : : hash_set <free_string_hash> m_rule_id_set;
998 : : std::unique_ptr<json::array> m_rules_arr;
999 : :
1000 : : /* The set of all CWE IDs we've seen, if any. */
1001 : : hash_set <int_hash <int, 0, 1> > m_cwe_id_set;
1002 : :
1003 : : std::unique_ptr<sarif_array_of_unique<sarif_logical_location>> m_cached_logical_locs;
1004 : :
1005 : : std::unique_ptr<sarif_array_of_unique<sarif_graph>> m_run_graphs;
1006 : :
1007 : : int m_tabstop;
1008 : :
1009 : : std::unique_ptr<sarif_serialization_format> m_serialization_format;
1010 : : const sarif_generation_options m_sarif_gen_opts;
1011 : :
1012 : : unsigned m_next_result_idx;
1013 : : sarif_code_flow *m_current_code_flow;
1014 : : };
1015 : :
1016 : : /* class sarif_object : public json::object. */
1017 : :
1018 : : sarif_property_bag &
1019 : 1128 : sarif_object::get_or_create_properties ()
1020 : : {
1021 : 1128 : json::value *properties_val = get ("properties");
1022 : 1128 : if (properties_val)
1023 : : {
1024 : 99 : if (properties_val->get_kind () == json::JSON_OBJECT)
1025 : : return *static_cast <sarif_property_bag *> (properties_val);
1026 : : }
1027 : :
1028 : 1029 : sarif_property_bag *bag = new sarif_property_bag ();
1029 : 1029 : set ("properties", bag);
1030 : 1029 : return *bag;
1031 : : }
1032 : :
1033 : : /* class sarif_invocation : public sarif_object. */
1034 : :
1035 : 416 : sarif_invocation::sarif_invocation (sarif_builder &builder,
1036 : 416 : const char * const *original_argv)
1037 : 416 : : m_notifications_arr (std::make_unique<json::array> ()),
1038 : 416 : m_success (true)
1039 : : {
1040 : : // "arguments" property (SARIF v2.1.0 section 3.20.2)
1041 : 416 : if (original_argv)
1042 : : {
1043 : 112 : auto arguments_arr = std::make_unique<json::array> ();
1044 : 4282 : for (size_t i = 0; original_argv[i]; ++i)
1045 : 4170 : arguments_arr->append_string (original_argv[i]);
1046 : 112 : set<json::array> ("arguments", std::move (arguments_arr));
1047 : 112 : }
1048 : :
1049 : : // "workingDirectory" property (SARIF v2.1.0 section 3.20.19)
1050 : 416 : if (const char *pwd = getpwd ())
1051 : 832 : set<sarif_artifact_location> ("workingDirectory",
1052 : 416 : builder.make_artifact_location_object (pwd));
1053 : :
1054 : : // "startTimeUtc" property (SARIF v2.1.0 section 3.20.7)
1055 : 832 : set<json::string> ("startTimeUtc",
1056 : 416 : make_date_time_string_for_current_time ());
1057 : 416 : }
1058 : :
1059 : : /* Handle an internal compiler error DIAGNOSTIC.
1060 : : Add an object representing the ICE to the notifications array. */
1061 : :
1062 : : void
1063 : 6 : sarif_invocation::add_notification_for_ice (const diagnostic_info &diagnostic,
1064 : : sarif_builder &builder,
1065 : : std::unique_ptr<json::object> backtrace)
1066 : : {
1067 : 6 : m_success = false;
1068 : :
1069 : 6 : auto notification
1070 : : = std::make_unique<sarif_ice_notification> (diagnostic,
1071 : : builder,
1072 : 6 : std::move (backtrace));
1073 : :
1074 : : /* Support for related locations within a notification was added
1075 : : in SARIF 2.2; see https://github.com/oasis-tcs/sarif-spec/issues/540 */
1076 : 6 : if (builder.get_version () >= sarif_version::v2_2_prerelease_2024_08_08)
1077 : 1 : notification->process_worklist (builder);
1078 : :
1079 : 6 : m_notifications_arr->append<sarif_ice_notification>
1080 : 6 : (std::move (notification));
1081 : 6 : }
1082 : :
1083 : : void
1084 : 280 : sarif_invocation::prepare_to_flush (sarif_builder &builder)
1085 : : {
1086 : 280 : const context &dc = builder.get_context ();
1087 : :
1088 : : /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */
1089 : 280 : if (dc.execution_failed_p ())
1090 : 201 : m_success = false;
1091 : 280 : set_bool ("executionSuccessful", m_success);
1092 : :
1093 : : /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */
1094 : 280 : set ("toolExecutionNotifications", std::move (m_notifications_arr));
1095 : :
1096 : : /* Call client hook, allowing it to create a custom property bag for
1097 : : this object (SARIF v2.1.0 section 3.8) e.g. for recording time vars. */
1098 : 280 : if (auto client_data_hooks = dc.get_client_data_hooks ())
1099 : 112 : client_data_hooks->add_sarif_invocation_properties (*this);
1100 : :
1101 : : // "endTimeUtc" property (SARIF v2.1.0 section 3.20.8);
1102 : 560 : set<json::string> ("endTimeUtc",
1103 : 280 : make_date_time_string_for_current_time ());
1104 : 280 : }
1105 : :
1106 : : /* class sarif_artifact : public sarif_object. */
1107 : :
1108 : : /* Add ROLE to this artifact's roles.
1109 : : If EMBED_CONTENTS is true, then flag that we will attempt to embed the
1110 : : contents of this artifact when writing it out. */
1111 : :
1112 : : void
1113 : 1138 : sarif_artifact::add_role (enum diagnostic_artifact_role role,
1114 : : bool embed_contents)
1115 : : {
1116 : : /* TODO(SARIF 2.2): "scannedFile" is to be added as a role in SARIF 2.2;
1117 : : see https://github.com/oasis-tcs/sarif-spec/issues/459
1118 : :
1119 : : For now, skip them.
1120 : : Ultimately, we probably shouldn't bother embedding the contents
1121 : : of such artifacts, just the snippets. */
1122 : 1138 : if (role == diagnostic_artifact_role::scanned_file)
1123 : : return;
1124 : :
1125 : 1117 : if (embed_contents)
1126 : 829 : m_embed_contents = true;
1127 : :
1128 : : /* In SARIF v2.1.0 section 3.24.6 "roles" property:
1129 : : "resultFile" is for an artifact
1130 : : "which the analysis tool was not explicitly instructed to scan",
1131 : : whereas "analysisTarget" is for one where the
1132 : : "analysis tool was instructed to scan this artifact".
1133 : : Hence the latter excludes the former. */
1134 : 1117 : if (role == diagnostic_artifact_role::result_file)
1135 : 537 : if (bitmap_bit_p (m_roles, (int)diagnostic_artifact_role::analysis_target))
1136 : : return;
1137 : :
1138 : 595 : bitmap_set_bit (m_roles, (int)role);
1139 : : }
1140 : :
1141 : : /* Populate the "contents" property (SARIF v2.1.0 section 3.24.8).
1142 : : We do this after initialization to
1143 : : (a) ensure that any charset options have been set
1144 : : (b) only populate it for artifacts that are referenced by a location. */
1145 : :
1146 : : void
1147 : 240 : sarif_artifact::populate_contents (sarif_builder &builder)
1148 : : {
1149 : 240 : if (auto artifact_content_obj
1150 : 240 : = builder.maybe_make_artifact_content_object (m_filename))
1151 : 240 : set<sarif_artifact_content> ("contents", std::move (artifact_content_obj));
1152 : 240 : }
1153 : :
1154 : : /* Get a string for ROLE corresponding to the
1155 : : SARIF v2.1.0 section 3.24.6 "roles" property. */
1156 : :
1157 : : static const char *
1158 : 328 : get_artifact_role_string (enum diagnostic_artifact_role role)
1159 : : {
1160 : 328 : switch (role)
1161 : : {
1162 : 0 : default:
1163 : 0 : gcc_unreachable ();
1164 : : case diagnostic_artifact_role::analysis_target:
1165 : : return "analysisTarget";
1166 : 0 : case diagnostic_artifact_role::debug_output_file:
1167 : 0 : return "debugOutputFile";
1168 : 13 : case diagnostic_artifact_role::result_file:
1169 : 13 : return "resultFile";
1170 : 0 : case diagnostic_artifact_role::scanned_file:
1171 : 0 : return "scannedFile";
1172 : 35 : case diagnostic_artifact_role::traced_file:
1173 : 35 : return "tracedFile";
1174 : : }
1175 : : }
1176 : :
1177 : : /* Populate the "roles" property of this sarif_artifact with a new
1178 : : json::array for the artifact.roles property (SARIF v2.1.0 section 3.24.6)
1179 : : containing strings such as "analysisTarget", "resultFile"
1180 : : and/or "tracedFile". */
1181 : :
1182 : : void
1183 : 298 : sarif_artifact::populate_roles ()
1184 : : {
1185 : 298 : if (bitmap_empty_p (m_roles))
1186 : 1 : return;
1187 : 297 : auto roles_arr (std::make_unique<json::array> ());
1188 : 1782 : for (int i = 0; i < (int)diagnostic_artifact_role::NUM_ROLES; i++)
1189 : 1485 : if (bitmap_bit_p (m_roles, i))
1190 : : {
1191 : 328 : enum diagnostic_artifact_role role = (enum diagnostic_artifact_role)i;
1192 : 328 : roles_arr->append_string (get_artifact_role_string (role));
1193 : : }
1194 : 297 : set<json::array> ("roles", std::move (roles_arr));
1195 : 297 : }
1196 : :
1197 : : /* class sarif_location_manager : public sarif_object. */
1198 : :
1199 : : /* Base implementation of sarif_location_manager::add_related_location vfunc.
1200 : :
1201 : : Add LOCATION_OBJ to this object's "relatedLocations" array,
1202 : : creating it if it doesn't yet exist. */
1203 : :
1204 : : void
1205 : 142 : sarif_location_manager::
1206 : : add_related_location (std::unique_ptr<sarif_location> location_obj,
1207 : : sarif_builder &)
1208 : : {
1209 : 142 : if (!m_related_locations_arr)
1210 : : {
1211 : 41 : m_related_locations_arr = new json::array ();
1212 : : /* Give ownership of m_related_locations_arr to json::object;
1213 : : keep a borrowed ptr. */
1214 : 41 : set ("relatedLocations", m_related_locations_arr);
1215 : : }
1216 : 142 : m_related_locations_arr->append (std::move (location_obj));
1217 : 142 : }
1218 : :
1219 : : void
1220 : 27 : sarif_location_manager::
1221 : : add_relationship_to_worklist (sarif_location &location_obj,
1222 : : enum worklist_item::kind kind,
1223 : : location_t where)
1224 : : {
1225 : 54 : m_worklist.push_back (worklist_item (location_obj,
1226 : : kind,
1227 : 27 : where));
1228 : 27 : }
1229 : :
1230 : : /* Process all items in this result's worklist.
1231 : : Doing so may temporarily add new items to the end
1232 : : of the worklist.
1233 : : Handling any item should be "lazy", and thus we should
1234 : : eventually drain the queue and terminate. */
1235 : :
1236 : : void
1237 : 466 : sarif_location_manager::process_worklist (sarif_builder &builder)
1238 : : {
1239 : 492 : while (!m_worklist.empty ())
1240 : : {
1241 : 26 : const worklist_item &item = m_worklist.front ();
1242 : 26 : process_worklist_item (builder, item);
1243 : 26 : m_worklist.pop_front ();
1244 : : }
1245 : 466 : }
1246 : :
1247 : : /* Process one item in this result's worklist, potentially
1248 : : adding new items to the end of the worklist. */
1249 : :
1250 : : void
1251 : 26 : sarif_location_manager::process_worklist_item (sarif_builder &builder,
1252 : : const worklist_item &item)
1253 : : {
1254 : 26 : switch (item.m_kind)
1255 : : {
1256 : 0 : default:
1257 : 0 : gcc_unreachable ();
1258 : 22 : case worklist_item::kind::included_from:
1259 : 22 : {
1260 : 22 : sarif_location &included_loc_obj = item.m_location_obj;
1261 : 22 : sarif_location *includer_loc_obj = nullptr;
1262 : 22 : auto iter = m_included_from_locations.find (item.m_where);
1263 : 22 : if (iter != m_included_from_locations.end ())
1264 : 5 : includer_loc_obj = iter->second;
1265 : : else
1266 : : {
1267 : 17 : std::unique_ptr<sarif_location> new_loc_obj
1268 : : = builder.make_location_object
1269 : : (*this,
1270 : 17 : item.m_where,
1271 : 17 : diagnostic_artifact_role::scanned_file);
1272 : 17 : includer_loc_obj = new_loc_obj.get ();
1273 : 17 : add_related_location (std::move (new_loc_obj), builder);
1274 : 17 : auto kv
1275 : 17 : = std::pair<location_t, sarif_location *> (item.m_where,
1276 : 17 : includer_loc_obj);
1277 : 17 : m_included_from_locations.insert (kv);
1278 : 17 : }
1279 : :
1280 : 22 : includer_loc_obj->lazily_add_relationship
1281 : 22 : (included_loc_obj,
1282 : : location_relationship_kind::includes,
1283 : : *this);
1284 : 22 : included_loc_obj.lazily_add_relationship
1285 : 22 : (*includer_loc_obj,
1286 : : location_relationship_kind::is_included_by,
1287 : : *this);
1288 : : }
1289 : 22 : break;
1290 : 4 : case worklist_item::kind::unlabelled_secondary_location:
1291 : 4 : {
1292 : 4 : sarif_location &primary_loc_obj = item.m_location_obj;
1293 : 4 : sarif_location *secondary_loc_obj = nullptr;
1294 : 4 : auto iter = m_unlabelled_secondary_locations.find (item.m_where);
1295 : 4 : if (iter != m_unlabelled_secondary_locations.end ())
1296 : 0 : secondary_loc_obj = iter->second;
1297 : : else
1298 : : {
1299 : 4 : std::unique_ptr<sarif_location> new_loc_obj
1300 : : = builder.make_location_object
1301 : : (*this,
1302 : 4 : item.m_where,
1303 : 4 : diagnostic_artifact_role::scanned_file);
1304 : 4 : secondary_loc_obj = new_loc_obj.get ();
1305 : 4 : add_related_location (std::move (new_loc_obj), builder);
1306 : 4 : auto kv
1307 : 4 : = std::pair<location_t, sarif_location *> (item.m_where,
1308 : 4 : secondary_loc_obj);
1309 : 4 : m_unlabelled_secondary_locations.insert (kv);
1310 : 4 : }
1311 : 4 : gcc_assert (secondary_loc_obj);
1312 : 4 : primary_loc_obj.lazily_add_relationship
1313 : 4 : (*secondary_loc_obj,
1314 : : location_relationship_kind::relevant,
1315 : : *this);
1316 : : }
1317 : 4 : break;
1318 : : }
1319 : 26 : }
1320 : :
1321 : : /* class sarif_result : public sarif_location_manager. */
1322 : :
1323 : : /* Handle secondary diagnostics that occur within a diagnostic group.
1324 : : The closest SARIF seems to have to nested diagnostics is the
1325 : : "relatedLocations" property of result objects (SARIF v2.1.0 section 3.27.22),
1326 : : so we lazily set this property and populate the array if and when
1327 : : secondary diagnostics occur (such as notes to a warning). */
1328 : :
1329 : : void
1330 : 117 : sarif_result::on_nested_diagnostic (const diagnostic_info &diagnostic,
1331 : : enum kind /*orig_diag_kind*/,
1332 : : sarif_builder &builder)
1333 : : {
1334 : : /* We don't yet generate meaningful logical locations for notes;
1335 : : sometimes these will related to current_function_decl, but
1336 : : often they won't. */
1337 : 117 : auto location_obj
1338 : 117 : = builder.make_location_object (this, *diagnostic.m_richloc,
1339 : 117 : logical_locations::key (),
1340 : 117 : diagnostic_artifact_role::result_file);
1341 : 117 : auto message_obj
1342 : 117 : = builder.make_message_object (pp_formatted_text (builder.get_printer ()));
1343 : 117 : pp_clear_output_area (builder.get_printer ());
1344 : 117 : location_obj->set<sarif_message> ("message", std::move (message_obj));
1345 : :
1346 : : /* Add nesting level, as per "P3358R0 SARIF for Structured Diagnostics"
1347 : : https://wg21.link/P3358R0 */
1348 : 117 : sarif_property_bag &bag = location_obj->get_or_create_properties ();
1349 : 117 : bag.set_integer ("nestingLevel",
1350 : 117 : builder.get_context ().get_diagnostic_nesting_level ());
1351 : :
1352 : 117 : add_related_location (std::move (location_obj), builder);
1353 : 117 : }
1354 : :
1355 : : /* Handle diagrams that occur within a diagnostic group.
1356 : : The closest thing in SARIF seems to be to add a location to the
1357 : : "releatedLocations" property (SARIF v2.1.0 section 3.27.22),
1358 : : and to put the diagram into the "message" property of that location
1359 : : (SARIF v2.1.0 section 3.28.5). */
1360 : :
1361 : : void
1362 : 4 : sarif_result::on_diagram (const diagram &d,
1363 : : sarif_builder &builder)
1364 : : {
1365 : 4 : auto location_obj = std::make_unique<sarif_location> ();
1366 : 4 : auto message_obj = builder.make_message_object_for_diagram (d);
1367 : 4 : location_obj->set<sarif_message> ("message", std::move (message_obj));
1368 : :
1369 : 4 : add_related_location (std::move (location_obj), builder);
1370 : 4 : }
1371 : :
1372 : : /* class sarif_location : public sarif_object. */
1373 : :
1374 : : /* Ensure this location has an "id" and return it.
1375 : : Use LOC_MGR if an id needs to be allocated.
1376 : :
1377 : : See the "id" property (3.28.2).
1378 : :
1379 : : We use this to only assign ids to locations that are
1380 : : referenced by another sarif object; others have no "id". */
1381 : :
1382 : : long
1383 : 48 : sarif_location::lazily_add_id (sarif_location_manager &loc_mgr)
1384 : : {
1385 : 48 : long id = get_id ();
1386 : 48 : if (id != -1)
1387 : : return id;
1388 : 39 : id = loc_mgr.allocate_location_id ();
1389 : 39 : set_integer ("id", id);
1390 : 39 : gcc_assert (id != -1);
1391 : 39 : return id;
1392 : : }
1393 : :
1394 : : /* Get the id of this location, or -1 if it doesn't have one. */
1395 : :
1396 : : long
1397 : 48 : sarif_location::get_id () const
1398 : : {
1399 : 48 : json::value *id = get ("id");
1400 : 48 : if (!id)
1401 : : return -1;
1402 : 9 : gcc_assert (id->get_kind () == json::JSON_INTEGER);
1403 : 9 : return static_cast <json::integer_number *> (id)->get ();
1404 : : }
1405 : :
1406 : : // 3.34.3 kinds property
1407 : : static const char *
1408 : 48 : get_string_for_location_relationship_kind (enum location_relationship_kind kind)
1409 : : {
1410 : 48 : switch (kind)
1411 : : {
1412 : 0 : default:
1413 : 0 : gcc_unreachable ();
1414 : : case location_relationship_kind::includes:
1415 : : return "includes";
1416 : 22 : case location_relationship_kind::is_included_by:
1417 : 22 : return "isIncludedBy";
1418 : 4 : case location_relationship_kind::relevant:
1419 : 4 : return "relevant";
1420 : : }
1421 : : }
1422 : :
1423 : : /* Lazily populate this location's "relationships" property (3.28.7)
1424 : : with the relationship of KIND to TARGET, creating objects
1425 : : as necessary.
1426 : : Use LOC_MGR for any locations that need "id" values. */
1427 : :
1428 : : void
1429 : 48 : sarif_location::lazily_add_relationship (sarif_location &target,
1430 : : enum location_relationship_kind kind,
1431 : : sarif_location_manager &loc_mgr)
1432 : : {
1433 : 48 : sarif_location_relationship &relationship_obj
1434 : 48 : = lazily_add_relationship_object (target, loc_mgr);
1435 : :
1436 : 48 : relationship_obj.lazily_add_kind (kind);
1437 : 48 : }
1438 : :
1439 : : /* Lazily populate this location's "relationships" property (3.28.7)
1440 : : with a location_relationship to TARGET, creating objects
1441 : : as necessary.
1442 : : Use LOC_MGR for any locations that need "id" values. */
1443 : :
1444 : : sarif_location_relationship &
1445 : 48 : sarif_location::lazily_add_relationship_object (sarif_location &target,
1446 : : sarif_location_manager &loc_mgr)
1447 : : {
1448 : : /* See if THIS already has a locationRelationship referencing TARGET. */
1449 : 48 : auto iter = m_relationships_map.find (&target);
1450 : 48 : if (iter != m_relationships_map.end ())
1451 : : {
1452 : : /* We already have a locationRelationship from THIS to TARGET. */
1453 : 0 : sarif_location_relationship *relationship = iter->second;
1454 : 0 : gcc_assert (relationship->get_target_id() == target.get_id ());
1455 : : return *relationship;
1456 : : }
1457 : :
1458 : : // Ensure that THIS has a "relationships" property (3.28.7).
1459 : 48 : json::array &relationships_arr = lazily_add_relationships_array ();
1460 : :
1461 : : /* No existing locationRelationship from THIS to TARGET; make one,
1462 : : record it, and add it to the "relationships" array. */
1463 : 48 : auto relationship_obj
1464 : 48 : = std::make_unique<sarif_location_relationship> (target, loc_mgr);
1465 : 48 : sarif_location_relationship *relationship = relationship_obj.get ();
1466 : 48 : auto kv
1467 : : = std::pair<sarif_location *,
1468 : 48 : sarif_location_relationship *> (&target, relationship);
1469 : 48 : m_relationships_map.insert (kv);
1470 : :
1471 : 48 : relationships_arr.append (std::move (relationship_obj));
1472 : :
1473 : 48 : return *relationship;
1474 : 48 : }
1475 : :
1476 : : /* Ensure this location has a "relationships" array (3.28.7). */
1477 : :
1478 : : json::array &
1479 : 48 : sarif_location::lazily_add_relationships_array ()
1480 : : {
1481 : 48 : const char *const property_name = "relationships";
1482 : 48 : if (json::value *relationships = get (property_name))
1483 : : {
1484 : 9 : gcc_assert (relationships->get_kind () == json::JSON_ARRAY);
1485 : : return *static_cast <json::array *> (relationships);
1486 : : }
1487 : 39 : json::array *relationships_arr = new json::array ();
1488 : 39 : set (property_name, relationships_arr);
1489 : 39 : return *relationships_arr;
1490 : : }
1491 : :
1492 : : /* class sarif_ice_notification : public sarif_location_manager. */
1493 : :
1494 : : /* sarif_ice_notification's ctor.
1495 : : DIAGNOSTIC is an internal compiler error. */
1496 : :
1497 : 6 : sarif_ice_notification::
1498 : : sarif_ice_notification (const diagnostic_info &diagnostic,
1499 : : sarif_builder &builder,
1500 : 6 : std::unique_ptr<json::object> backtrace)
1501 : : {
1502 : : /* "locations" property (SARIF v2.1.0 section 3.58.4). */
1503 : 6 : auto locations_arr
1504 : : = builder.make_locations_arr (*this,
1505 : : diagnostic,
1506 : 6 : diagnostic_artifact_role::result_file);
1507 : 6 : set<json::array> ("locations", std::move (locations_arr));
1508 : :
1509 : : /* "message" property (SARIF v2.1.0 section 3.85.5). */
1510 : 6 : auto message_obj
1511 : 6 : = builder.make_message_object (pp_formatted_text (builder.get_printer ()));
1512 : 6 : pp_clear_output_area (builder.get_printer ());
1513 : 6 : set<sarif_message> ("message", std::move (message_obj));
1514 : :
1515 : : /* "level" property (SARIF v2.1.0 section 3.58.6). */
1516 : 6 : set_string ("level", "error");
1517 : :
1518 : : /* If we have backtrace information, add it as part of a property bag. */
1519 : 6 : if (backtrace)
1520 : : {
1521 : 6 : sarif_property_bag &bag = get_or_create_properties ();
1522 : 6 : bag.set ("gcc/backtrace", std::move (backtrace));
1523 : : }
1524 : 6 : }
1525 : :
1526 : : /* Implementation of sarif_location_manager::add_related_location vfunc
1527 : : for notifications. */
1528 : :
1529 : : void
1530 : 1 : sarif_ice_notification::
1531 : : add_related_location (std::unique_ptr<sarif_location> location_obj,
1532 : : sarif_builder &builder)
1533 : : {
1534 : : /* Support for related locations within a notification was added
1535 : : in SARIF 2.2; see https://github.com/oasis-tcs/sarif-spec/issues/540 */
1536 : 1 : if (builder.get_version () >= sarif_version::v2_2_prerelease_2024_08_08)
1537 : 1 : sarif_location_manager::add_related_location (std::move (location_obj),
1538 : : builder);
1539 : : /* Otherwise implicitly discard LOCATION_OBJ. */
1540 : 1 : }
1541 : :
1542 : : /* class sarif_location_relationship : public sarif_object. */
1543 : :
1544 : 48 : sarif_location_relationship::
1545 : : sarif_location_relationship (sarif_location &target,
1546 : 48 : sarif_location_manager &loc_mgr)
1547 : 48 : : m_kinds ((unsigned)location_relationship_kind::NUM_KINDS)
1548 : : {
1549 : 48 : bitmap_clear (m_kinds);
1550 : 48 : set_integer ("target", target.lazily_add_id (loc_mgr));
1551 : 48 : }
1552 : :
1553 : : long
1554 : 0 : sarif_location_relationship::get_target_id () const
1555 : : {
1556 : 0 : json::value *id = get ("id");
1557 : 0 : gcc_assert (id);
1558 : 0 : return static_cast <json::integer_number *> (id)->get ();
1559 : : }
1560 : :
1561 : : void
1562 : 48 : sarif_location_relationship::
1563 : : lazily_add_kind (enum location_relationship_kind kind)
1564 : : {
1565 : 48 : if (bitmap_bit_p (m_kinds, (int)kind))
1566 : : return; // already have this kind
1567 : 48 : bitmap_set_bit (m_kinds, (int)kind);
1568 : :
1569 : : // 3.34.3 kinds property
1570 : 48 : json::array *kinds_arr = nullptr;
1571 : 48 : if (json::value *kinds_val = get ("kinds"))
1572 : : {
1573 : 0 : gcc_assert (kinds_val->get_kind () == json::JSON_ARRAY);
1574 : : }
1575 : : else
1576 : : {
1577 : 48 : kinds_arr = new json::array ();
1578 : 48 : set ("kinds", kinds_arr);
1579 : : }
1580 : 48 : const char *kind_str = get_string_for_location_relationship_kind (kind);
1581 : 48 : kinds_arr->append_string (kind_str);
1582 : : }
1583 : :
1584 : : /* class sarif_code_flow : public sarif_object. */
1585 : :
1586 : 34 : sarif_code_flow::sarif_code_flow (sarif_result &parent,
1587 : 34 : unsigned idx_within_parent)
1588 : 34 : : m_parent (parent),
1589 : 34 : m_idx_within_parent (idx_within_parent)
1590 : : {
1591 : : /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
1592 : 34 : auto thread_flows_arr = std::make_unique<json::array> ();
1593 : 34 : m_thread_flows_arr = thread_flows_arr.get (); // borrowed
1594 : 34 : set<json::array> ("threadFlows", std::move (thread_flows_arr));
1595 : 34 : }
1596 : :
1597 : : sarif_thread_flow &
1598 : 164 : sarif_code_flow::get_or_append_thread_flow (const paths::thread &thread,
1599 : : paths::thread_id_t thread_id)
1600 : : {
1601 : 164 : sarif_thread_flow **slot = m_thread_id_map.get (thread_id);
1602 : 164 : if (slot)
1603 : 129 : return **slot;
1604 : :
1605 : 35 : unsigned next_thread_flow_idx = m_thread_flows_arr->size ();
1606 : 35 : auto thread_flow_obj
1607 : 35 : = std::make_unique<sarif_thread_flow> (*this, thread, next_thread_flow_idx);
1608 : 35 : m_thread_id_map.put (thread_id, thread_flow_obj.get ()); // borrowed
1609 : 35 : sarif_thread_flow *result = thread_flow_obj.get ();
1610 : 35 : m_thread_flows_arr->append<sarif_thread_flow> (std::move (thread_flow_obj));
1611 : 35 : return *result;
1612 : 35 : }
1613 : :
1614 : : sarif_thread_flow &
1615 : 0 : sarif_code_flow::get_thread_flow (paths::thread_id_t thread_id)
1616 : : {
1617 : 0 : sarif_thread_flow **slot = m_thread_id_map.get (thread_id);
1618 : 0 : gcc_assert (slot); // it must already have one
1619 : 0 : return **slot;
1620 : : }
1621 : :
1622 : : void
1623 : 164 : sarif_code_flow::add_location (sarif_thread_flow_location &tfl_obj)
1624 : : {
1625 : 164 : m_all_tfl_objs.push_back (&tfl_obj);
1626 : 164 : }
1627 : :
1628 : : sarif_thread_flow_location &
1629 : 181 : sarif_code_flow::get_thread_flow_loc_obj (paths::event_id_t event_id) const
1630 : : {
1631 : 181 : gcc_assert (event_id.known_p ());
1632 : 181 : gcc_assert ((size_t)event_id.zero_based () < m_all_tfl_objs.size ());
1633 : 181 : sarif_thread_flow_location *tfl_obj = m_all_tfl_objs[event_id.zero_based ()];
1634 : 181 : gcc_assert (tfl_obj);
1635 : 181 : return *tfl_obj;
1636 : : }
1637 : :
1638 : : /* class sarif_thread_flow : public sarif_object. */
1639 : :
1640 : 35 : sarif_thread_flow::sarif_thread_flow (sarif_code_flow &parent,
1641 : : const paths::thread &thread,
1642 : 35 : unsigned idx_within_parent)
1643 : 35 : : m_parent (parent),
1644 : 35 : m_idx_within_parent (idx_within_parent)
1645 : : {
1646 : : /* "id" property (SARIF v2.1.0 section 3.37.2). */
1647 : 35 : label_text name (thread.get_name (false));
1648 : 35 : set_string ("id", name.get ());
1649 : :
1650 : : /* "locations" property (SARIF v2.1.0 section 3.37.6). */
1651 : 35 : m_locations_arr = new json::array ();
1652 : :
1653 : : /* Give ownership of m_locations_arr to json::object;
1654 : : keep a borrowed ptr. */
1655 : 35 : set ("locations", m_locations_arr);
1656 : 35 : }
1657 : :
1658 : : /* Add a sarif_thread_flow_location to this threadFlow object, but
1659 : : don't populate it yet. */
1660 : :
1661 : : sarif_thread_flow_location &
1662 : 164 : sarif_thread_flow::add_location ()
1663 : : {
1664 : 164 : const unsigned thread_flow_location_idx = m_locations_arr->size ();
1665 : 164 : sarif_thread_flow_location *thread_flow_loc_obj
1666 : 164 : = new sarif_thread_flow_location (*this, thread_flow_location_idx);
1667 : 164 : m_locations_arr->append (thread_flow_loc_obj);
1668 : 164 : m_parent.add_location (*thread_flow_loc_obj);
1669 : 164 : return *thread_flow_loc_obj;
1670 : : }
1671 : :
1672 : : /* class sarif_builder. */
1673 : :
1674 : : /* sarif_builder's ctor. */
1675 : :
1676 : 416 : sarif_builder::sarif_builder (diagnostics::context &dc,
1677 : : pretty_printer &printer,
1678 : : const line_maps *line_maps,
1679 : : std::unique_ptr<sarif_serialization_format> serialization_format,
1680 : 416 : const sarif_generation_options &sarif_gen_opts)
1681 : 416 : : m_context (dc),
1682 : 416 : m_printer (&printer),
1683 : 416 : m_line_maps (line_maps),
1684 : 416 : m_token_printer (*this),
1685 : 416 : m_logical_loc_mgr (nullptr),
1686 : 416 : m_invocation_obj
1687 : : (std::make_unique<sarif_invocation> (*this,
1688 : 416 : dc.get_original_argv ())),
1689 : 416 : m_results_array (new json::array ()),
1690 : 416 : m_cur_group_result (nullptr),
1691 : 416 : m_seen_any_relative_paths (false),
1692 : 416 : m_rule_id_set (),
1693 : 416 : m_rules_arr (new json::array ()),
1694 : 416 : m_cached_logical_locs
1695 : : (std::make_unique<sarif_array_of_unique<sarif_logical_location>> ()),
1696 : 416 : m_run_graphs
1697 : : (std::make_unique<sarif_array_of_unique<sarif_graph>> ()),
1698 : 416 : m_tabstop (dc.get_column_options ().m_tabstop),
1699 : 416 : m_serialization_format (std::move (serialization_format)),
1700 : 416 : m_sarif_gen_opts (sarif_gen_opts),
1701 : 416 : m_next_result_idx (0),
1702 : 832 : m_current_code_flow (nullptr)
1703 : : {
1704 : 416 : gcc_assert (m_line_maps);
1705 : 416 : gcc_assert (m_serialization_format);
1706 : :
1707 : 416 : if (auto client_data_hooks = dc.get_client_data_hooks ())
1708 : 112 : m_logical_loc_mgr = client_data_hooks->get_logical_location_manager ();
1709 : 416 : }
1710 : :
1711 : 416 : sarif_builder::~sarif_builder ()
1712 : : {
1713 : : /* Normally m_filename_to_artifact_map will have been emptied as part
1714 : : of make_run_object, but this isn't run by all the selftests.
1715 : : Ensure the artifact objects are cleaned up for such cases. */
1716 : 968 : for (auto iter : m_filename_to_artifact_map)
1717 : : {
1718 : 136 : sarif_artifact *artifact_obj = iter.second;
1719 : 136 : delete artifact_obj;
1720 : : }
1721 : 416 : }
1722 : :
1723 : : void
1724 : 0 : sarif_builder::dump (FILE *out, int indent) const
1725 : : {
1726 : 0 : dumping::emit_heading (out, indent, "serialization format");
1727 : 0 : m_serialization_format->dump (out, indent + 2);
1728 : 0 : dumping::emit_heading (out, indent, "SARIF generation options");
1729 : 0 : m_sarif_gen_opts.dump (out, indent + 2);
1730 : 0 : }
1731 : :
1732 : : /* Functions at which to stop the backtrace print. It's not
1733 : : particularly helpful to print the callers of these functions. */
1734 : :
1735 : : static const char * const bt_stop[] =
1736 : : {
1737 : : "main",
1738 : : "toplev::main",
1739 : : "execute_one_pass",
1740 : : "compile_file",
1741 : : };
1742 : :
1743 : : struct bt_closure
1744 : : {
1745 : 6 : bt_closure (sarif_builder &builder,
1746 : : json::array *frames_arr)
1747 : 6 : : m_builder (builder),
1748 : 6 : m_frames_arr (frames_arr)
1749 : : {
1750 : : }
1751 : :
1752 : : sarif_builder &m_builder;
1753 : : json::array *m_frames_arr;
1754 : : };
1755 : :
1756 : : /* A callback function passed to the backtrace_full function. */
1757 : :
1758 : : static int
1759 : 22 : bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
1760 : : const char *function)
1761 : : {
1762 : 22 : bt_closure *closure = (bt_closure *)data;
1763 : :
1764 : : /* If we don't have any useful information, don't print
1765 : : anything. */
1766 : 22 : if (filename == nullptr && function == nullptr)
1767 : : return 0;
1768 : :
1769 : : /* Skip functions in context.cc or diagnostic-global-context.cc. */
1770 : 20 : if (closure->m_frames_arr->size () == 0
1771 : 12 : && filename != nullptr
1772 : 20 : && (strcmp (lbasename (filename), "context.cc") == 0
1773 : 12 : || strcmp (lbasename (filename),
1774 : : "diagnostic-global-context.cc") == 0))
1775 : 6 : return 0;
1776 : :
1777 : : /* Print up to 20 functions. We could make this a --param, but
1778 : : since this is only for debugging just use a constant for now. */
1779 : 14 : if (closure->m_frames_arr->size () >= 20)
1780 : : {
1781 : : /* Returning a non-zero value stops the backtrace. */
1782 : : return 1;
1783 : : }
1784 : :
1785 : 14 : char *alc = nullptr;
1786 : 14 : if (function != nullptr)
1787 : : {
1788 : 14 : char *str = cplus_demangle_v3 (function,
1789 : : (DMGL_VERBOSE | DMGL_ANSI
1790 : : | DMGL_GNU_V3 | DMGL_PARAMS));
1791 : 14 : if (str != nullptr)
1792 : : {
1793 : 12 : alc = str;
1794 : 12 : function = str;
1795 : : }
1796 : :
1797 : 58 : for (size_t i = 0; i < ARRAY_SIZE (bt_stop); ++i)
1798 : : {
1799 : 50 : size_t len = strlen (bt_stop[i]);
1800 : 50 : if (strncmp (function, bt_stop[i], len) == 0
1801 : 6 : && (function[len] == '\0' || function[len] == '('))
1802 : : {
1803 : 6 : if (alc != nullptr)
1804 : 6 : free (alc);
1805 : : /* Returning a non-zero value stops the backtrace. */
1806 : 6 : return 1;
1807 : : }
1808 : : }
1809 : : }
1810 : :
1811 : 8 : auto frame_obj = std::make_unique<json::object> ();
1812 : :
1813 : : /* I tried using sarifStack and sarifStackFrame for this
1814 : : but it's not a good fit e.g. PC information. */
1815 : 8 : char buf[128];
1816 : 8 : snprintf (buf, sizeof (buf) - 1, "0x%lx", (unsigned long)pc);
1817 : 8 : frame_obj->set_string ("pc", buf);
1818 : 8 : if (function)
1819 : 8 : frame_obj->set_string ("function", function);
1820 : 8 : if (filename)
1821 : 8 : frame_obj->set_string ("filename", filename);
1822 : 8 : frame_obj->set_integer ("lineno", lineno);
1823 : 8 : closure->m_frames_arr->append (std::move (frame_obj));
1824 : :
1825 : 8 : if (alc != nullptr)
1826 : 6 : free (alc);
1827 : :
1828 : 8 : return 0;
1829 : 8 : }
1830 : :
1831 : : /* Attempt to generate a JSON object representing a backtrace,
1832 : : for adding to ICE notifications. */
1833 : :
1834 : : std::unique_ptr<json::object>
1835 : 6 : sarif_builder::make_stack_from_backtrace ()
1836 : : {
1837 : 6 : auto frames_arr = std::make_unique<json::array> ();
1838 : :
1839 : 6 : backtrace_state *state = nullptr;
1840 : 6 : state = backtrace_create_state (nullptr, 0, nullptr, nullptr);
1841 : 6 : bt_closure closure (*this, frames_arr.get ());
1842 : 6 : const int frames_to_skip = 5;
1843 : 6 : if (state != nullptr)
1844 : 6 : backtrace_full (state, frames_to_skip, bt_callback, nullptr,
1845 : : (void *) &closure);
1846 : :
1847 : 6 : if (frames_arr->size () == 0)
1848 : 0 : return nullptr;
1849 : :
1850 : 6 : auto stack = std::make_unique<json::object> ();
1851 : 6 : stack->set ("frames", std::move (frames_arr));
1852 : 6 : return stack;
1853 : 6 : }
1854 : :
1855 : : void
1856 : 288 : sarif_builder::set_main_input_filename (const char *name)
1857 : : {
1858 : : /* Mark NAME as the artifact that the tool was instructed to scan.
1859 : : Only quote the contents if it gets referenced by physical locations,
1860 : : since otherwise the "no diagnostics" case would quote the main input
1861 : : file, and doing so noticeably bloated the output seen in analyzer
1862 : : integration testing (build directory went from 20G -> 21G). */
1863 : 288 : if (name)
1864 : 288 : get_or_create_artifact (name,
1865 : : diagnostic_artifact_role::analysis_target,
1866 : : false);
1867 : 288 : }
1868 : :
1869 : : /* Implementation of "on_report_diagnostic" for SARIF output. */
1870 : :
1871 : : void
1872 : 601 : sarif_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
1873 : : enum kind orig_diag_kind,
1874 : : sarif_sink_buffer *buffer)
1875 : : {
1876 : 601 : pp_output_formatted_text (m_printer, m_context.get_urlifier ());
1877 : :
1878 : 601 : if (diagnostic.m_kind == kind::ice || diagnostic.m_kind == kind::ice_nobt)
1879 : : {
1880 : 6 : std::unique_ptr<json::object> stack = make_stack_from_backtrace ();
1881 : 6 : m_invocation_obj->add_notification_for_ice (diagnostic, *this,
1882 : : std::move (stack));
1883 : :
1884 : : /* Print a header for the remaining output to stderr, and
1885 : : return, attempting to print the usual ICE messages to
1886 : : stderr. Hopefully this will be helpful to the user in
1887 : : indicating what's gone wrong (also for DejaGnu, for pruning
1888 : : those messages). */
1889 : 6 : fnotice (stderr, "Internal compiler error:\n");
1890 : :
1891 : 6 : return;
1892 : 6 : }
1893 : :
1894 : 595 : if (buffer)
1895 : : {
1896 : : /* When buffering, we can only handle top-level results. */
1897 : 21 : gcc_assert (!m_cur_group_result);
1898 : 21 : buffer->add_result (make_result_object (diagnostic, orig_diag_kind,
1899 : 21 : m_next_result_idx++));
1900 : 21 : return;
1901 : : }
1902 : :
1903 : 574 : if (m_cur_group_result)
1904 : : /* Nested diagnostic. */
1905 : 117 : m_cur_group_result->on_nested_diagnostic (diagnostic,
1906 : : orig_diag_kind,
1907 : : *this);
1908 : : else
1909 : : {
1910 : : /* Top-level diagnostic. */
1911 : 457 : m_cur_group_result = make_result_object (diagnostic, orig_diag_kind,
1912 : 457 : m_next_result_idx++);
1913 : : }
1914 : : }
1915 : :
1916 : : /* Implementation of diagnostics::context::m_diagrams.m_emission_cb
1917 : : for SARIF output. */
1918 : :
1919 : : void
1920 : 4 : sarif_builder::emit_diagram (const diagram &d)
1921 : : {
1922 : : /* We must be within the emission of a top-level diagnostic. */
1923 : 4 : gcc_assert (m_cur_group_result);
1924 : 4 : m_cur_group_result->on_diagram (d, *this);
1925 : 4 : }
1926 : :
1927 : : /* Implementation of "end_group_cb" for SARIF output.
1928 : : Append the current sarifResult to results, and set it to nullptr. */
1929 : :
1930 : : void
1931 : 482 : sarif_builder::end_group ()
1932 : : {
1933 : 482 : if (m_cur_group_result)
1934 : : {
1935 : 457 : m_cur_group_result->process_worklist (*this);
1936 : 457 : m_results_array->append<sarif_result> (std::move (m_cur_group_result));
1937 : : }
1938 : 482 : }
1939 : :
1940 : : void
1941 : 1 : sarif_builder::
1942 : : report_global_digraph (const lazily_created<digraphs::digraph> &ldg)
1943 : : {
1944 : 1 : auto &dg = ldg.get_or_create ();
1945 : :
1946 : : /* Presumably the location manager must be nullptr; see
1947 : : https://github.com/oasis-tcs/sarif-spec/issues/712 */
1948 : 1 : m_run_graphs->append (make_sarif_graph (dg, this, nullptr));
1949 : 1 : }
1950 : :
1951 : : /* Create a top-level object, and add it to all the results
1952 : : (and other entities) we've seen so far, moving ownership
1953 : : to the object. */
1954 : :
1955 : : std::unique_ptr<sarif_log>
1956 : 280 : sarif_builder::flush_to_object ()
1957 : : {
1958 : 280 : DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
1959 : 280 : "diagnostics::sarif_builder::flush_to_object");
1960 : 280 : m_invocation_obj->prepare_to_flush (*this);
1961 : 280 : std::unique_ptr<sarif_log> top
1962 : 280 : = make_top_level_object (std::move (m_invocation_obj),
1963 : 280 : std::move (m_results_array));
1964 : 280 : return top;
1965 : 280 : }
1966 : :
1967 : : /* Create a top-level object, and add it to all the results
1968 : : (and other entities) we've seen so far.
1969 : :
1970 : : Flush it all to OUTF. */
1971 : :
1972 : : void
1973 : 112 : sarif_builder::flush_to_file (FILE *outf)
1974 : : {
1975 : 112 : DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
1976 : 112 : "diagnostics::sarif_builder::flush_to_file");
1977 : 112 : std::unique_ptr<sarif_log> top = flush_to_object ();
1978 : 112 : m_serialization_format->write_to_file (outf, *top);
1979 : 112 : }
1980 : :
1981 : : /* Attempt to convert DIAG_KIND to a suitable value for the "level"
1982 : : property (SARIF v2.1.0 section 3.27.10).
1983 : :
1984 : : Return nullptr if there isn't one. */
1985 : :
1986 : : static const char *
1987 : 478 : maybe_get_sarif_level (enum kind diag_kind)
1988 : : {
1989 : 478 : switch (diag_kind)
1990 : : {
1991 : : case kind::warning:
1992 : : return "warning";
1993 : 238 : case kind::fatal:
1994 : 238 : case kind::error:
1995 : 238 : return "error";
1996 : 8 : case kind::note:
1997 : 8 : case kind::anachronism:
1998 : 8 : return "note";
1999 : 0 : default:
2000 : 0 : return nullptr;
2001 : : }
2002 : : }
2003 : :
2004 : : /* Make a string for DIAG_KIND suitable for use a ruleId
2005 : : (SARIF v2.1.0 section 3.27.5) as a fallback for when we don't
2006 : : have anything better to use. */
2007 : :
2008 : : static char *
2009 : 238 : make_rule_id_for_diagnostic_kind (enum kind diag_kind)
2010 : : {
2011 : : /* Lose the trailing ": ". */
2012 : 238 : const char *kind_text = get_text_for_kind (diag_kind);
2013 : 238 : size_t len = strlen (kind_text);
2014 : 238 : gcc_assert (len > 2);
2015 : 238 : gcc_assert (kind_text[len - 2] == ':');
2016 : 238 : gcc_assert (kind_text[len - 1] == ' ');
2017 : 238 : char *rstrip = xstrdup (kind_text);
2018 : 238 : rstrip[len - 2] = '\0';
2019 : 238 : return rstrip;
2020 : : }
2021 : :
2022 : : /* Make a "result" object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */
2023 : :
2024 : : std::unique_ptr<sarif_result>
2025 : 478 : sarif_builder::make_result_object (const diagnostic_info &diagnostic,
2026 : : enum kind orig_diag_kind,
2027 : : unsigned idx_within_parent)
2028 : : {
2029 : 478 : auto result_obj = std::make_unique<sarif_result> (idx_within_parent);
2030 : :
2031 : : /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
2032 : : /* Ideally we'd have an option_name for these. */
2033 : 956 : if (char *option_text
2034 : 478 : = m_context.make_option_name (diagnostic.m_option_id,
2035 : 478 : orig_diag_kind, diagnostic.m_kind))
2036 : : {
2037 : : /* Lazily create reportingDescriptor objects for and add to m_rules_arr.
2038 : : Set ruleId referencing them. */
2039 : 240 : result_obj->set_string ("ruleId", option_text);
2040 : 240 : if (m_rule_id_set.contains (option_text))
2041 : 174 : free (option_text);
2042 : : else
2043 : : {
2044 : : /* This is the first time we've seen this ruleId. */
2045 : : /* Add to set, taking ownership. */
2046 : 66 : m_rule_id_set.add (option_text);
2047 : :
2048 : 66 : m_rules_arr->append<sarif_reporting_descriptor>
2049 : 66 : (make_reporting_descriptor_object_for_warning (diagnostic,
2050 : : orig_diag_kind,
2051 : : option_text));
2052 : : }
2053 : : }
2054 : : else
2055 : : {
2056 : : /* Otherwise, we have an "error" or a stray "note"; use the
2057 : : diagnostic kind as the ruleId, so that the result object at least
2058 : : has a ruleId.
2059 : : We don't bother creating reportingDescriptor objects for these. */
2060 : 238 : char *rule_id = make_rule_id_for_diagnostic_kind (orig_diag_kind);
2061 : 238 : result_obj->set_string ("ruleId", rule_id);
2062 : 238 : free (rule_id);
2063 : : }
2064 : :
2065 : 478 : if (diagnostic.m_metadata)
2066 : : {
2067 : : /* "taxa" property (SARIF v2.1.0 section 3.27.8). */
2068 : 35 : if (int cwe_id = diagnostic.m_metadata->get_cwe ())
2069 : : {
2070 : 25 : auto taxa_arr = std::make_unique<json::array> ();
2071 : 25 : taxa_arr->append<sarif_reporting_descriptor_reference>
2072 : 25 : (make_reporting_descriptor_reference_object_for_cwe_id (cwe_id));
2073 : 25 : result_obj->set<json::array> ("taxa", std::move (taxa_arr));
2074 : 25 : }
2075 : :
2076 : 35 : diagnostic.m_metadata->maybe_add_sarif_properties (*result_obj);
2077 : :
2078 : : /* We don't yet support diagnostics::metadata::rule. */
2079 : : }
2080 : :
2081 : : /* "level" property (SARIF v2.1.0 section 3.27.10). */
2082 : 478 : if (const char *sarif_level = maybe_get_sarif_level (diagnostic.m_kind))
2083 : 478 : result_obj->set_string ("level", sarif_level);
2084 : :
2085 : : /* "message" property (SARIF v2.1.0 section 3.27.11). */
2086 : 478 : auto message_obj
2087 : 478 : = make_message_object (pp_formatted_text (m_printer));
2088 : 478 : pp_clear_output_area (m_printer);
2089 : 478 : result_obj->set<sarif_message> ("message", std::move (message_obj));
2090 : :
2091 : : /* "locations" property (SARIF v2.1.0 section 3.27.12). */
2092 : 478 : result_obj->set<json::array>
2093 : 956 : ("locations",
2094 : 478 : make_locations_arr (*result_obj.get (),
2095 : : diagnostic,
2096 : : diagnostic_artifact_role::result_file));
2097 : :
2098 : : /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
2099 : 478 : if (const paths::path *path = diagnostic.m_richloc->get_path ())
2100 : : {
2101 : 34 : auto code_flows_arr = std::make_unique<json::array> ();
2102 : 34 : const unsigned code_flow_index = 0;
2103 : 34 : code_flows_arr->append<sarif_code_flow>
2104 : 34 : (make_code_flow_object (*result_obj.get (),
2105 : : code_flow_index,
2106 : : *path));
2107 : 34 : result_obj->set<json::array> ("codeFlows", std::move (code_flows_arr));
2108 : 34 : }
2109 : :
2110 : : // "graphs" property (SARIF v2.1.0 section 3.27.19). */
2111 : 478 : if (diagnostic.m_metadata)
2112 : 35 : if (auto ldg = diagnostic.m_metadata->get_lazy_digraphs ())
2113 : : {
2114 : 1 : auto &digraphs = ldg->get_or_create ();
2115 : 1 : auto graphs_arr = std::make_unique<json::array> ();
2116 : 3 : for (auto &iter : digraphs)
2117 : 2 : graphs_arr->append (make_sarif_graph (*iter, this,
2118 : 2 : result_obj.get ()));
2119 : 1 : if (graphs_arr->size () > 0)
2120 : 1 : result_obj->set<json::array> ("graphs", std::move (graphs_arr));
2121 : 1 : }
2122 : :
2123 : : /* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is
2124 : : set up later, if any nested diagnostics occur within this diagnostic
2125 : : group. */
2126 : :
2127 : : /* "fixes" property (SARIF v2.1.0 section 3.27.30). */
2128 : 478 : const rich_location *richloc = diagnostic.m_richloc;
2129 : 478 : if (richloc->get_num_fixit_hints ())
2130 : : {
2131 : 9 : auto fix_arr = std::make_unique<json::array> ();
2132 : 9 : fix_arr->append<sarif_fix> (make_fix_object (*richloc));
2133 : 9 : result_obj->set<json::array> ("fixes", std::move (fix_arr));
2134 : 9 : }
2135 : :
2136 : 956 : return result_obj;
2137 : 478 : }
2138 : :
2139 : : /* Make a "reportingDescriptor" object (SARIF v2.1.0 section 3.49)
2140 : : for a GCC warning. */
2141 : :
2142 : : std::unique_ptr<sarif_reporting_descriptor>
2143 : 66 : sarif_builder::
2144 : : make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic,
2145 : : enum kind /*orig_diag_kind*/,
2146 : : const char *option_text)
2147 : : {
2148 : 66 : auto reporting_desc = std::make_unique<sarif_reporting_descriptor> ();
2149 : :
2150 : : /* "id" property (SARIF v2.1.0 section 3.49.3). */
2151 : 66 : reporting_desc->set_string ("id", option_text);
2152 : :
2153 : : /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since
2154 : : it seems redundant compared to "id". */
2155 : :
2156 : : /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
2157 : 66 : if (char *option_url = m_context.make_option_url (diagnostic.m_option_id))
2158 : : {
2159 : 66 : reporting_desc->set_string ("helpUri", option_url);
2160 : 66 : free (option_url);
2161 : : }
2162 : :
2163 : 66 : return reporting_desc;
2164 : : }
2165 : :
2166 : : /* Make a "reportingDescriptor" object (SARIF v2.1.0 section 3.49)
2167 : : for CWE_ID, for use within the CWE taxa array. */
2168 : :
2169 : : std::unique_ptr<sarif_reporting_descriptor>
2170 : 22 : sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id) const
2171 : : {
2172 : 22 : auto reporting_desc = std::make_unique<sarif_reporting_descriptor> ();
2173 : :
2174 : : /* "id" property (SARIF v2.1.0 section 3.49.3). */
2175 : 22 : {
2176 : 22 : pretty_printer pp;
2177 : 22 : pp_printf (&pp, "%i", cwe_id);
2178 : 22 : reporting_desc->set_string ("id", pp_formatted_text (&pp));
2179 : 22 : }
2180 : :
2181 : : /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
2182 : 22 : {
2183 : 22 : char *url = get_cwe_url (cwe_id);
2184 : 22 : reporting_desc->set_string ("helpUri", url);
2185 : 22 : free (url);
2186 : : }
2187 : :
2188 : 22 : return reporting_desc;
2189 : : }
2190 : :
2191 : : /* Make a "reportingDescriptorReference" object (SARIF v2.1.0 section 3.52)
2192 : : referencing CWE_ID, for use within a result object.
2193 : : Also, add CWE_ID to m_cwe_id_set. */
2194 : :
2195 : : std::unique_ptr<sarif_reporting_descriptor_reference>
2196 : 25 : sarif_builder::
2197 : : make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id)
2198 : : {
2199 : 25 : auto desc_ref_obj = std::make_unique<sarif_reporting_descriptor_reference> ();
2200 : :
2201 : : /* "id" property (SARIF v2.1.0 section 3.52.4). */
2202 : 25 : {
2203 : 25 : pretty_printer pp;
2204 : 25 : pp_printf (&pp, "%i", cwe_id);
2205 : 25 : desc_ref_obj->set_string ("id", pp_formatted_text (&pp));
2206 : 25 : }
2207 : :
2208 : : /* "toolComponent" property (SARIF v2.1.0 section 3.52.7). */
2209 : 25 : desc_ref_obj->set<sarif_tool_component_reference>
2210 : 25 : ("toolComponent", make_tool_component_reference_object_for_cwe ());
2211 : :
2212 : : /* Add CWE_ID to our set. */
2213 : 25 : gcc_assert (cwe_id > 0);
2214 : 25 : m_cwe_id_set.add (cwe_id);
2215 : :
2216 : 25 : return desc_ref_obj;
2217 : : }
2218 : :
2219 : : /* Make a "toolComponentReference" object (SARIF v2.1.0 section 3.54) that
2220 : : references the CWE taxonomy. */
2221 : :
2222 : : std::unique_ptr<sarif_tool_component_reference>
2223 : 25 : sarif_builder::
2224 : : make_tool_component_reference_object_for_cwe () const
2225 : : {
2226 : 25 : auto comp_ref_obj = std::make_unique<sarif_tool_component_reference> ();
2227 : :
2228 : : /* "name" property (SARIF v2.1.0 section 3.54.3). */
2229 : 25 : comp_ref_obj->set_string ("name", "cwe");
2230 : :
2231 : 25 : return comp_ref_obj;
2232 : : }
2233 : :
2234 : : /* Make an array suitable for use as the "locations" property of:
2235 : : - a "result" object (SARIF v2.1.0 section 3.27.12), or
2236 : : - a "notification" object (SARIF v2.1.0 section 3.58.4).
2237 : : Use LOC_MGR for any locations that need "id" values. */
2238 : :
2239 : : std::unique_ptr<json::array>
2240 : 484 : sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
2241 : : const diagnostic_info &diagnostic,
2242 : : enum diagnostic_artifact_role role)
2243 : : {
2244 : 484 : auto locations_arr = std::make_unique<json::array> ();
2245 : 484 : logical_locations::key logical_loc;
2246 : 484 : if (auto client_data_hooks = m_context.get_client_data_hooks ())
2247 : 292 : logical_loc = client_data_hooks->get_current_logical_location ();
2248 : :
2249 : 484 : auto location_obj
2250 : 484 : = make_location_object (&loc_mgr, *diagnostic.m_richloc, logical_loc, role);
2251 : : /* Don't add entirely empty location objects to the array. */
2252 : 484 : if (!location_obj->is_empty ())
2253 : 420 : locations_arr->append<sarif_location> (std::move (location_obj));
2254 : :
2255 : 968 : return locations_arr;
2256 : 484 : }
2257 : :
2258 : : /* If LOGICAL_LOC is non-null, use it to create a "logicalLocations" property
2259 : : within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4) with a minimal logical
2260 : : location object referencing theRuns.logicalLocations (3.33.3). */
2261 : :
2262 : : void
2263 : 931 : sarif_builder::
2264 : : set_any_logical_locs_arr (sarif_location &location_obj,
2265 : : logical_locations::key logical_loc)
2266 : : {
2267 : 931 : if (!logical_loc)
2268 : 658 : return;
2269 : 273 : gcc_assert (m_logical_loc_mgr);
2270 : 273 : auto location_locs_arr = std::make_unique<json::array> ();
2271 : :
2272 : 273 : auto logical_loc_obj = make_minimal_sarif_logical_location (logical_loc);
2273 : :
2274 : 273 : location_locs_arr->append<sarif_logical_location>
2275 : 273 : (std::move (logical_loc_obj));
2276 : :
2277 : 273 : location_obj.set<json::array> ("logicalLocations",
2278 : : std::move (location_locs_arr));
2279 : 273 : }
2280 : :
2281 : : /* Make a "location" object (SARIF v2.1.0 section 3.28) for RICH_LOC
2282 : : and LOGICAL_LOC.
2283 : : Use LOC_MGR for any locations that need "id" values, and for
2284 : : any worklist items.
2285 : : Note that we might not always have a LOC_MGR; see
2286 : : https://github.com/oasis-tcs/sarif-spec/issues/712 */
2287 : :
2288 : : std::unique_ptr<sarif_location>
2289 : 767 : sarif_builder::make_location_object (sarif_location_manager *loc_mgr,
2290 : : const rich_location &rich_loc,
2291 : : logical_locations::key logical_loc,
2292 : : enum diagnostic_artifact_role role)
2293 : : {
2294 : 1534 : class escape_nonascii_renderer : public content_renderer
2295 : : {
2296 : : public:
2297 : 767 : escape_nonascii_renderer (const rich_location &richloc,
2298 : : enum diagnostics_escape_format escape_format)
2299 : 767 : : m_richloc (richloc),
2300 : 767 : m_escape_format (escape_format)
2301 : : {}
2302 : :
2303 : : std::unique_ptr<sarif_multiformat_message_string>
2304 : 136 : render (const sarif_builder &builder) const final override
2305 : : {
2306 : 136 : diagnostics::context dc;
2307 : 136 : diagnostic_initialize (&dc, 0);
2308 : 136 : auto &source_printing_opts = dc.get_source_printing_options ();
2309 : 136 : source_printing_opts.enabled = true;
2310 : 136 : source_printing_opts.colorize_source_p = false;
2311 : 136 : source_printing_opts.show_labels_p = true;
2312 : 136 : source_printing_opts.show_line_numbers_p = true;
2313 : :
2314 : 136 : rich_location my_rich_loc (m_richloc);
2315 : 136 : my_rich_loc.set_escape_on_output (true);
2316 : :
2317 : 136 : source_print_policy source_policy (dc);
2318 : 136 : dc.set_escape_format (m_escape_format);
2319 : 136 : text_sink text_output (dc);
2320 : 136 : source_policy.print (*text_output.get_printer (),
2321 : : my_rich_loc, kind::error, nullptr);
2322 : :
2323 : 136 : const char *buf = pp_formatted_text (text_output.get_printer ());
2324 : 136 : std::unique_ptr<sarif_multiformat_message_string> result
2325 : 136 : = builder.make_multiformat_message_string (buf);
2326 : :
2327 : 136 : diagnostic_finish (&dc);
2328 : :
2329 : 272 : return result;
2330 : 136 : }
2331 : : private:
2332 : : const rich_location &m_richloc;
2333 : : enum diagnostics_escape_format m_escape_format;
2334 : : } the_renderer (rich_loc,
2335 : 767 : m_context.get_escape_format ());
2336 : :
2337 : 767 : auto location_obj = std::make_unique<sarif_location> ();
2338 : :
2339 : : /* Get primary loc from RICH_LOC. */
2340 : 767 : location_t loc = rich_loc.get_loc ();
2341 : :
2342 : : /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
2343 : 767 : const content_renderer *snippet_renderer
2344 : 767 : = rich_loc.escape_on_output_p () ? &the_renderer : nullptr;
2345 : 767 : if (auto phs_loc_obj
2346 : : = maybe_make_physical_location_object (loc, role,
2347 : : rich_loc.get_column_override (),
2348 : 767 : snippet_renderer))
2349 : 665 : location_obj->set<sarif_physical_location> ("physicalLocation",
2350 : 767 : std::move (phs_loc_obj));
2351 : :
2352 : : /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
2353 : 767 : set_any_logical_locs_arr (*location_obj, logical_loc);
2354 : :
2355 : : /* Handle labelled ranges and/or secondary locations. */
2356 : 767 : {
2357 : 767 : std::unique_ptr<json::array> annotations_arr = nullptr;
2358 : 1812 : for (unsigned int i = 0; i < rich_loc.get_num_locations (); i++)
2359 : : {
2360 : 1045 : const location_range *range = rich_loc.get_range (i);
2361 : 1045 : bool handled = false;
2362 : 1045 : if (const range_label *label = range->m_label)
2363 : : {
2364 : 410 : label_text text = label->get_text (i);
2365 : 410 : if (text.get ())
2366 : : {
2367 : : /* Create annotations for any labelled ranges. */
2368 : 410 : location_t range_loc = rich_loc.get_loc (i);
2369 : 410 : auto region
2370 : : = maybe_make_region_object (range_loc,
2371 : 410 : rich_loc.get_column_override ());
2372 : 410 : if (region)
2373 : : {
2374 : 410 : if (!annotations_arr)
2375 : 137 : annotations_arr = std::make_unique<json::array> ();
2376 : 410 : region->set<sarif_message>
2377 : 410 : ("message", make_message_object (text.get ()));
2378 : 410 : annotations_arr->append<sarif_region> (std::move (region));
2379 : 410 : handled = true;
2380 : : }
2381 : 410 : }
2382 : 410 : }
2383 : :
2384 : : /* Add related locations for any secondary locations in RICH_LOC
2385 : : that don't have labels (and thus aren't added to "annotations"). */
2386 : 1045 : if (loc_mgr && i > 0 && !handled)
2387 : 4 : loc_mgr->add_relationship_to_worklist
2388 : 4 : (*location_obj.get (),
2389 : : sarif_location_manager::worklist_item::kind::unlabelled_secondary_location,
2390 : 4 : range->m_loc);
2391 : : }
2392 : 767 : if (annotations_arr)
2393 : : /* "annotations" property (SARIF v2.1.0 section 3.28.6). */
2394 : 137 : location_obj->set<json::array> ("annotations",
2395 : : std::move (annotations_arr));
2396 : 767 : }
2397 : :
2398 : 767 : if (loc_mgr)
2399 : 767 : add_any_include_chain (*loc_mgr, *location_obj.get (), loc);
2400 : :
2401 : : /* A flag for hinting that the diagnostic involves issues at the
2402 : : level of character encodings (such as homoglyphs, or misleading
2403 : : bidirectional control codes), and thus that it will be helpful
2404 : : to the user if we show some representation of
2405 : : how the characters in the pertinent source lines are encoded. */
2406 : 767 : if (rich_loc.escape_on_output_p ())
2407 : : {
2408 : 136 : sarif_property_bag &bag = location_obj->get_or_create_properties ();
2409 : 136 : bag.set_bool ("gcc/escapeNonAscii", rich_loc.escape_on_output_p ());
2410 : : }
2411 : :
2412 : 767 : return location_obj;
2413 : 767 : }
2414 : :
2415 : : /* If WHERE was #included from somewhere, add a worklist item
2416 : : to LOC_MGR to lazily add a location for the #include location,
2417 : : and relationships between it and the LOCATION_OBJ.
2418 : : Compare with diagnostics::context::report_current_module, but rather
2419 : : than iterating the current chain, we add the next edge and iterate
2420 : : in the worklist, so that edges are only added once. */
2421 : :
2422 : : void
2423 : 952 : sarif_builder::add_any_include_chain (sarif_location_manager &loc_mgr,
2424 : : sarif_location &location_obj,
2425 : : location_t where)
2426 : : {
2427 : 952 : if (where <= BUILTINS_LOCATION)
2428 : 929 : return;
2429 : :
2430 : 850 : const line_map_ordinary *map = nullptr;
2431 : 850 : linemap_resolve_location (m_line_maps, where,
2432 : : LRK_MACRO_DEFINITION_LOCATION,
2433 : : &map);
2434 : :
2435 : 850 : if (!map)
2436 : : return;
2437 : :
2438 : 850 : location_t include_loc = linemap_included_from (map);
2439 : 850 : map = linemap_included_from_linemap (m_line_maps, map);
2440 : 850 : if (!map)
2441 : : return;
2442 : 23 : loc_mgr.add_relationship_to_worklist
2443 : 23 : (location_obj,
2444 : : sarif_result::worklist_item::kind::included_from,
2445 : : include_loc);
2446 : : }
2447 : :
2448 : : /* Make a "location" object (SARIF v2.1.0 section 3.28) for WHERE
2449 : : within an include chain. */
2450 : :
2451 : : std::unique_ptr<sarif_location>
2452 : 21 : sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
2453 : : location_t loc,
2454 : : enum diagnostic_artifact_role role)
2455 : : {
2456 : 21 : auto location_obj = std::make_unique<sarif_location> ();
2457 : :
2458 : : /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
2459 : 21 : if (auto phs_loc_obj
2460 : 21 : = maybe_make_physical_location_object (loc, role, 0, nullptr))
2461 : 21 : location_obj->set<sarif_physical_location> ("physicalLocation",
2462 : 21 : std::move (phs_loc_obj));
2463 : :
2464 : 21 : add_any_include_chain (loc_mgr, *location_obj.get (), loc);
2465 : :
2466 : 21 : return location_obj;
2467 : : }
2468 : :
2469 : : /* Make a "location" object (SARIF v2.1.0 section 3.28) for EVENT
2470 : : within a paths::path. */
2471 : :
2472 : : std::unique_ptr<sarif_location>
2473 : 164 : sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
2474 : : const paths::event &event,
2475 : : enum diagnostic_artifact_role role)
2476 : : {
2477 : 164 : auto location_obj = std::make_unique<sarif_location> ();
2478 : :
2479 : : /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
2480 : 164 : location_t loc = event.get_location ();
2481 : 164 : if (auto phs_loc_obj
2482 : 164 : = maybe_make_physical_location_object (loc, role, 0, nullptr))
2483 : 164 : location_obj->set<sarif_physical_location> ("physicalLocation",
2484 : 164 : std::move (phs_loc_obj));
2485 : :
2486 : : /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
2487 : 164 : logical_locations::key logical_loc = event.get_logical_location ();
2488 : 164 : set_any_logical_locs_arr (*location_obj, logical_loc);
2489 : :
2490 : : /* "message" property (SARIF v2.1.0 section 3.28.5). */
2491 : 164 : std::unique_ptr<pretty_printer> pp = get_printer ()->clone ();
2492 : 164 : event.print_desc (*pp);
2493 : 164 : location_obj->set<sarif_message>
2494 : 328 : ("message",
2495 : 164 : make_message_object (pp_formatted_text (pp.get ())));
2496 : :
2497 : 164 : add_any_include_chain (loc_mgr, *location_obj.get (), loc);
2498 : :
2499 : 328 : return location_obj;
2500 : 164 : }
2501 : :
2502 : : /* Make a "physicalLocation" object (SARIF v2.1.0 section 3.29) for LOC.
2503 : :
2504 : : If COLUMN_OVERRIDE is non-zero, then use it as the column number
2505 : : if LOC has no column information.
2506 : :
2507 : : Ensure that we have an artifact object for the file, adding ROLE to it,
2508 : : and flagging that we will attempt to embed the contents of the artifact
2509 : : when writing it out. */
2510 : :
2511 : : std::unique_ptr<sarif_physical_location>
2512 : 952 : sarif_builder::
2513 : : maybe_make_physical_location_object (location_t loc,
2514 : : enum diagnostic_artifact_role role,
2515 : : int column_override,
2516 : : const content_renderer *snippet_renderer)
2517 : : {
2518 : 952 : if (loc <= BUILTINS_LOCATION || LOCATION_FILE (loc) == nullptr)
2519 : 102 : return nullptr;
2520 : :
2521 : 850 : auto phys_loc_obj = std::make_unique<sarif_physical_location> ();
2522 : :
2523 : : /* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */
2524 : 850 : phys_loc_obj->set<sarif_artifact_location>
2525 : 850 : ("artifactLocation", make_artifact_location_object (loc));
2526 : 850 : get_or_create_artifact (LOCATION_FILE (loc), role, true);
2527 : :
2528 : : /* "region" property (SARIF v2.1.0 section 3.29.4). */
2529 : 850 : if (auto region_obj = maybe_make_region_object (loc, column_override))
2530 : 850 : phys_loc_obj->set<sarif_region> ("region", std::move (region_obj));
2531 : :
2532 : : /* "contextRegion" property (SARIF v2.1.0 section 3.29.5). */
2533 : 850 : if (auto context_region_obj
2534 : 850 : = maybe_make_region_object_for_context (loc, snippet_renderer))
2535 : 846 : phys_loc_obj->set<sarif_region> ("contextRegion",
2536 : 850 : std::move (context_region_obj));
2537 : :
2538 : : /* Instead, we add artifacts to the run as a whole,
2539 : : with artifact.contents.
2540 : : Could do both, though. */
2541 : :
2542 : 850 : return phys_loc_obj;
2543 : 850 : }
2544 : :
2545 : : /* Make an "artifactLocation" object (SARIF v2.1.0 section 3.4) for LOC,
2546 : : or return nullptr. */
2547 : :
2548 : : std::unique_ptr<sarif_artifact_location>
2549 : 859 : sarif_builder::make_artifact_location_object (location_t loc)
2550 : : {
2551 : 859 : return make_artifact_location_object (LOCATION_FILE (loc));
2552 : : }
2553 : :
2554 : : /* The ID value for use in "uriBaseId" properties (SARIF v2.1.0 section 3.4.4)
2555 : : for when we need to express paths relative to PWD. */
2556 : :
2557 : : #define PWD_PROPERTY_NAME ("PWD")
2558 : :
2559 : : /* Make an "artifactLocation" object (SARIF v2.1.0 section 3.4) for FILENAME,
2560 : : or return nullptr. */
2561 : :
2562 : : std::unique_ptr<sarif_artifact_location>
2563 : 1709 : sarif_builder::make_artifact_location_object (const char *filename)
2564 : : {
2565 : 1709 : auto artifact_loc_obj = std::make_unique<sarif_artifact_location> ();
2566 : :
2567 : : /* "uri" property (SARIF v2.1.0 section 3.4.3). */
2568 : 1709 : artifact_loc_obj->set_string ("uri", filename);
2569 : :
2570 : 1709 : if (filename[0] != '/')
2571 : : {
2572 : : /* If we have a relative path, set the "uriBaseId" property
2573 : : (SARIF v2.1.0 section 3.4.4). */
2574 : 56 : artifact_loc_obj->set_string ("uriBaseId", PWD_PROPERTY_NAME);
2575 : 56 : m_seen_any_relative_paths = true;
2576 : : }
2577 : :
2578 : 1709 : return artifact_loc_obj;
2579 : : }
2580 : :
2581 : : /* Get the PWD, or nullptr, as an absolute file-based URI,
2582 : : adding a trailing forward slash (as required by SARIF v2.1.0
2583 : : section 3.14.14). */
2584 : :
2585 : : static char *
2586 : 44 : make_pwd_uri_str ()
2587 : : {
2588 : : /* The prefix of a file-based URI, up to, but not including the path. */
2589 : : #define FILE_PREFIX ("file://")
2590 : :
2591 : 44 : const char *pwd = getpwd ();
2592 : 44 : if (!pwd)
2593 : : return nullptr;
2594 : 44 : size_t len = strlen (pwd);
2595 : 44 : if (len == 0 || pwd[len - 1] != '/')
2596 : 44 : return concat (FILE_PREFIX, pwd, "/", nullptr);
2597 : : else
2598 : : {
2599 : 0 : gcc_assert (pwd[len - 1] == '/');
2600 : 0 : return concat (FILE_PREFIX, pwd, nullptr);
2601 : : }
2602 : : }
2603 : :
2604 : : /* Make an "artifactLocation" object (SARIF v2.1.0 section 3.4) for the pwd,
2605 : : for use in the "run.originalUriBaseIds" property (SARIF v2.1.0
2606 : : section 3.14.14) when we have any relative paths. */
2607 : :
2608 : : std::unique_ptr<sarif_artifact_location>
2609 : 44 : sarif_builder::make_artifact_location_object_for_pwd () const
2610 : : {
2611 : 44 : auto artifact_loc_obj = std::make_unique<sarif_artifact_location> ();
2612 : :
2613 : : /* "uri" property (SARIF v2.1.0 section 3.4.3). */
2614 : 44 : if (char *pwd = make_pwd_uri_str ())
2615 : : {
2616 : 44 : gcc_assert (strlen (pwd) > 0);
2617 : 44 : gcc_assert (pwd[strlen (pwd) - 1] == '/');
2618 : 44 : artifact_loc_obj->set_string ("uri", pwd);
2619 : 44 : free (pwd);
2620 : : }
2621 : :
2622 : 44 : return artifact_loc_obj;
2623 : : }
2624 : :
2625 : : /* Get the column number within EXPLOC. */
2626 : :
2627 : : int
2628 : 2328 : sarif_builder::get_sarif_column (expanded_location exploc) const
2629 : : {
2630 : 2328 : cpp_char_column_policy policy (m_tabstop, cpp_wcwidth);
2631 : 2328 : return location_compute_display_column (m_context.get_file_cache (),
2632 : 2328 : exploc, policy);
2633 : : }
2634 : :
2635 : : /* Make a "region" object (SARIF v2.1.0 section 3.30) for LOC,
2636 : : or return nullptr.
2637 : :
2638 : : If COLUMN_OVERRIDE is non-zero, then use it as the column number
2639 : : if LOC has no column information.
2640 : :
2641 : : We only support text properties of regions ("text regions"),
2642 : : not binary properties ("binary regions"); see 3.30.1. */
2643 : :
2644 : : std::unique_ptr<sarif_region>
2645 : 1260 : sarif_builder::maybe_make_region_object (location_t loc,
2646 : : int column_override) const
2647 : : {
2648 : 1260 : location_t caret_loc = get_pure_location (loc);
2649 : :
2650 : 1260 : if (caret_loc <= BUILTINS_LOCATION)
2651 : 0 : return nullptr;
2652 : :
2653 : 1260 : location_t start_loc = get_start (loc);
2654 : 1260 : location_t finish_loc = get_finish (loc);
2655 : :
2656 : 1260 : expanded_location exploc_caret = expand_location (caret_loc);
2657 : 1260 : expanded_location exploc_start = expand_location (start_loc);
2658 : 1260 : expanded_location exploc_finish = expand_location (finish_loc);
2659 : :
2660 : 1260 : if (exploc_start.file !=exploc_caret.file)
2661 : 0 : return nullptr;
2662 : 1260 : if (exploc_finish.file !=exploc_caret.file)
2663 : 0 : return nullptr;
2664 : :
2665 : : /* We can have line == 0 in the presence of "#" lines.
2666 : : SARIF requires lines > 0, so if we hit this case we don't have a
2667 : : way of validly representing the region as SARIF; bail out. */
2668 : 1260 : if (exploc_start.line <= 0)
2669 : 4 : return nullptr;
2670 : :
2671 : 1256 : auto region_obj = std::make_unique<sarif_region> ();
2672 : :
2673 : : /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
2674 : 1256 : region_obj->set_integer ("startLine", exploc_start.line);
2675 : :
2676 : : /* "startColumn" property (SARIF v2.1.0 section 3.30.6).
2677 : :
2678 : : We use column == 0 to mean the whole line, so omit the column
2679 : : information for this case, unless COLUMN_OVERRIDE is non-zero,
2680 : : (for handling certain awkward lexer diagnostics) */
2681 : :
2682 : 1256 : if (exploc_start.column == 0 && column_override)
2683 : : /* Use the provided column number. */
2684 : : exploc_start.column = column_override;
2685 : :
2686 : 1256 : if (exploc_start.column > 0)
2687 : : {
2688 : 1239 : int start_column = get_sarif_column (exploc_start);
2689 : 1239 : region_obj->set_integer ("startColumn", start_column);
2690 : : }
2691 : :
2692 : : /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
2693 : 1256 : if (exploc_finish.line != exploc_start.line
2694 : 0 : && exploc_finish.line > 0)
2695 : 0 : region_obj->set_integer ("endLine", exploc_finish.line);
2696 : :
2697 : : /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
2698 : : This expresses the column immediately beyond the range.
2699 : :
2700 : : We use column == 0 to mean the whole line, so omit the column
2701 : : information for this case. */
2702 : 1256 : if (exploc_finish.column > 0)
2703 : : {
2704 : 1071 : int next_column = get_sarif_column (exploc_finish) + 1;
2705 : 1071 : region_obj->set_integer ("endColumn", next_column);
2706 : : }
2707 : :
2708 : 1256 : return region_obj;
2709 : 1256 : }
2710 : :
2711 : : /* Make a "region" object (SARIF v2.1.0 section 3.30) for the "contextRegion"
2712 : : property (SARIF v2.1.0 section 3.29.5) of a "physicalLocation".
2713 : :
2714 : : This is similar to maybe_make_region_object, but ignores column numbers,
2715 : : covering the line(s) as a whole, and including a "snippet" property
2716 : : embedding those source lines, making it easier for consumers to show
2717 : : the pertinent source. */
2718 : :
2719 : : std::unique_ptr<sarif_region>
2720 : 850 : sarif_builder::
2721 : : maybe_make_region_object_for_context (location_t loc,
2722 : : const content_renderer *snippet_renderer)
2723 : : const
2724 : : {
2725 : 850 : location_t caret_loc = get_pure_location (loc);
2726 : :
2727 : 850 : if (caret_loc <= BUILTINS_LOCATION)
2728 : 0 : return nullptr;
2729 : :
2730 : 850 : location_t start_loc = get_start (loc);
2731 : 850 : location_t finish_loc = get_finish (loc);
2732 : :
2733 : 850 : expanded_location exploc_caret = expand_location (caret_loc);
2734 : 850 : expanded_location exploc_start = expand_location (start_loc);
2735 : 850 : expanded_location exploc_finish = expand_location (finish_loc);
2736 : :
2737 : 850 : if (exploc_start.file !=exploc_caret.file)
2738 : 0 : return nullptr;
2739 : 850 : if (exploc_finish.file !=exploc_caret.file)
2740 : 0 : return nullptr;
2741 : :
2742 : : /* We can have line == 0 in the presence of "#" lines.
2743 : : SARIF requires lines > 0, so if we hit this case we don't have a
2744 : : way of validly representing the region as SARIF; bail out. */
2745 : 850 : if (exploc_start.line <= 0)
2746 : 4 : return nullptr;
2747 : :
2748 : 846 : auto region_obj = std::make_unique<sarif_region> ();
2749 : :
2750 : : /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
2751 : 846 : region_obj->set_integer ("startLine", exploc_start.line);
2752 : :
2753 : : /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
2754 : 846 : if (exploc_finish.line != exploc_start.line
2755 : 0 : && exploc_finish.line > 0)
2756 : 0 : region_obj->set_integer ("endLine", exploc_finish.line);
2757 : :
2758 : : /* "snippet" property (SARIF v2.1.0 section 3.30.13). */
2759 : 846 : if (auto artifact_content_obj
2760 : : = maybe_make_artifact_content_object (exploc_start.file,
2761 : : exploc_start.line,
2762 : : exploc_finish.line,
2763 : 846 : snippet_renderer))
2764 : 674 : region_obj->set<sarif_artifact_content> ("snippet",
2765 : 846 : std::move (artifact_content_obj));
2766 : :
2767 : 846 : return region_obj;
2768 : 846 : }
2769 : :
2770 : : /* Make a "region" object (SARIF v2.1.0 section 3.30) for the deletion region
2771 : : of HINT (as per SARIF v2.1.0 section 3.57.3). */
2772 : :
2773 : : std::unique_ptr<sarif_region>
2774 : 9 : sarif_builder::make_region_object_for_hint (const fixit_hint &hint) const
2775 : : {
2776 : 9 : location_t start_loc = hint.get_start_loc ();
2777 : 9 : location_t next_loc = hint.get_next_loc ();
2778 : :
2779 : 9 : expanded_location exploc_start = expand_location (start_loc);
2780 : 9 : expanded_location exploc_next = expand_location (next_loc);
2781 : :
2782 : 9 : auto region_obj = std::make_unique<sarif_region> ();
2783 : :
2784 : : /* "startLine" property (SARIF v2.1.0 section 3.30.5) */
2785 : 9 : region_obj->set_integer ("startLine", exploc_start.line);
2786 : :
2787 : : /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */
2788 : 9 : int start_col = get_sarif_column (exploc_start);
2789 : 9 : region_obj->set_integer ("startColumn", start_col);
2790 : :
2791 : : /* "endLine" property (SARIF v2.1.0 section 3.30.7) */
2792 : 9 : if (exploc_next.line != exploc_start.line)
2793 : 0 : region_obj->set_integer ("endLine", exploc_next.line);
2794 : :
2795 : : /* "endColumn" property (SARIF v2.1.0 section 3.30.8).
2796 : : This expresses the column immediately beyond the range. */
2797 : 9 : int next_col = get_sarif_column (exploc_next);
2798 : 9 : region_obj->set_integer ("endColumn", next_col);
2799 : :
2800 : 9 : return region_obj;
2801 : : }
2802 : :
2803 : : /* Attempt to get a string for a logicalLocation's "kind" property
2804 : : (SARIF v2.1.0 section 3.33.7).
2805 : : Return nullptr if unknown. */
2806 : :
2807 : : static const char *
2808 : 508 : maybe_get_sarif_kind (enum logical_locations::kind kind)
2809 : : {
2810 : 508 : using namespace logical_locations;
2811 : :
2812 : 508 : switch (kind)
2813 : : {
2814 : 0 : default:
2815 : 0 : gcc_unreachable ();
2816 : : case logical_locations::kind::unknown:
2817 : : return nullptr;
2818 : :
2819 : : /* Kinds within executable code. */
2820 : 273 : case logical_locations::kind::function:
2821 : 273 : return "function";
2822 : 0 : case logical_locations::kind::member:
2823 : 0 : return "member";
2824 : 0 : case logical_locations::kind::module_:
2825 : 0 : return "module";
2826 : 217 : case logical_locations::kind::namespace_:
2827 : 217 : return "namespace";
2828 : 18 : case logical_locations::kind::type:
2829 : 18 : return "type";
2830 : 0 : case logical_locations::kind::return_type:
2831 : 0 : return "returnType";
2832 : 0 : case logical_locations::kind::parameter:
2833 : 0 : return "parameter";
2834 : 0 : case logical_locations::kind::variable:
2835 : 0 : return "variable";
2836 : :
2837 : : /* Kinds within XML or HTML documents. */
2838 : 0 : case logical_locations::kind::element:
2839 : 0 : return "element";
2840 : 0 : case logical_locations::kind::attribute:
2841 : 0 : return "attribute";
2842 : 0 : case logical_locations::kind::text:
2843 : 0 : return "text";
2844 : 0 : case logical_locations::kind::comment:
2845 : 0 : return "comment";
2846 : 0 : case logical_locations::kind::processing_instruction:
2847 : 0 : return "processingInstruction";
2848 : 0 : case logical_locations::kind::dtd:
2849 : 0 : return "dtd";
2850 : 0 : case logical_locations::kind::declaration:
2851 : 0 : return "declaration";
2852 : :
2853 : : /* Kinds within JSON documents. */
2854 : 0 : case logical_locations::kind::object:
2855 : 0 : return "object";
2856 : 0 : case logical_locations::kind::array:
2857 : 0 : return "array";
2858 : 0 : case logical_locations::kind::property:
2859 : 0 : return "property";
2860 : 0 : case logical_locations::kind::value:
2861 : 0 : return "value";
2862 : : }
2863 : : }
2864 : :
2865 : : /* Set PROPERTY_NAME within this bag to a "logicalLocation" object (SARIF v2.1.0
2866 : : section 3.33) for LOGICAL_LOC. The object has an "index" property to refer to
2867 : : theRuns.logicalLocations (3.33.3). */
2868 : :
2869 : : void
2870 : 0 : sarif_property_bag::set_logical_location (const char *property_name,
2871 : : sarif_builder &builder,
2872 : : logical_locations::key logical_loc)
2873 : : {
2874 : 0 : set<sarif_logical_location>
2875 : 0 : (property_name,
2876 : 0 : builder.make_minimal_sarif_logical_location (logical_loc));
2877 : 0 : }
2878 : :
2879 : : static void
2880 : 1425 : copy_any_property_bag (const digraphs::object &input_obj,
2881 : : sarif_object &output_obj)
2882 : : {
2883 : 1425 : if (input_obj.get_property_bag ())
2884 : : {
2885 : 571 : const json::object &old_bag = *input_obj.get_property_bag ();
2886 : 571 : sarif_property_bag &new_bag = output_obj.get_or_create_properties ();
2887 : 2435 : for (size_t i = 0; i < old_bag.get_num_keys (); ++i)
2888 : : {
2889 : 1864 : const char *key = old_bag.get_key (i);
2890 : 1864 : json::value *val = old_bag.get (key);
2891 : 1864 : new_bag.set (key, val->clone ());
2892 : : }
2893 : : }
2894 : 1425 : }
2895 : :
2896 : : std::unique_ptr<sarif_graph>
2897 : 38 : make_sarif_graph (const digraphs::digraph &g,
2898 : : sarif_builder *builder,
2899 : : sarif_location_manager *sarif_location_mgr)
2900 : : {
2901 : 38 : auto result = std::make_unique<sarif_graph> ();
2902 : :
2903 : : // 3.39.2 description property
2904 : 38 : if (const char *desc = g.get_description ())
2905 : 7 : if (builder)
2906 : 3 : result->set<sarif_message> ("description",
2907 : 3 : builder->make_message_object (desc));
2908 : :
2909 : 38 : copy_any_property_bag (g, *result);
2910 : :
2911 : : // 3.39.3 nodes property
2912 : 38 : auto nodes_arr = std::make_unique<json::array> ();
2913 : 38 : const int num_nodes = g.get_num_nodes ();
2914 : 124 : for (int i = 0; i < num_nodes; ++i)
2915 : 86 : nodes_arr->append (make_sarif_node (g.get_node (i),
2916 : : builder,
2917 : : sarif_location_mgr));
2918 : 38 : result->set ("nodes", std::move (nodes_arr));
2919 : :
2920 : : // 3.39.4 edges property
2921 : 38 : auto edges_arr = std::make_unique<json::array> ();
2922 : 38 : const int num_edges = g.get_num_edges ();
2923 : 479 : for (int i = 0; i < num_edges; ++i)
2924 : 441 : edges_arr->append (make_sarif_edge (g.get_edge (i), builder));
2925 : 38 : result->set ("edges", std::move (edges_arr));
2926 : :
2927 : 76 : return result;
2928 : 38 : }
2929 : :
2930 : : std::unique_ptr<sarif_node>
2931 : 946 : make_sarif_node (const digraphs::node &n,
2932 : : sarif_builder *builder,
2933 : : sarif_location_manager *sarif_location_mgr)
2934 : : {
2935 : 946 : auto result = std::make_unique<sarif_node> ();
2936 : :
2937 : : // 3.40.2 id property
2938 : 1892 : result->set_string ("id", n.get_id ().c_str ());
2939 : :
2940 : 946 : copy_any_property_bag (n, *result);
2941 : :
2942 : : // 3.40.3 label property
2943 : 946 : if (const char *label = n.get_label ())
2944 : 404 : if (builder)
2945 : 400 : result->set<sarif_message> ("label",
2946 : 400 : builder->make_message_object (label));
2947 : :
2948 : : // 3.40.4 location property
2949 : 946 : if (n.get_logical_loc ()
2950 : 946 : || n.get_physical_loc () != UNKNOWN_LOCATION)
2951 : 38 : if (builder)
2952 : : {
2953 : 38 : rich_location rich_loc
2954 : 38 : (line_table, n.get_physical_loc ());
2955 : 38 : auto loc_obj
2956 : : = builder->make_location_object
2957 : : (sarif_location_mgr,
2958 : : rich_loc,
2959 : : n.get_logical_loc (),
2960 : 38 : diagnostic_artifact_role::scanned_file);
2961 : 38 : result->set<sarif_location> ("location",
2962 : : std::move (loc_obj));
2963 : 38 : }
2964 : :
2965 : : // 3.40.5 children property
2966 : 946 : if (const int num_children = n.get_num_children ())
2967 : : {
2968 : 295 : auto children_arr = std::make_unique<json::array> ();
2969 : 1155 : for (int i = 0; i < num_children; ++i)
2970 : 860 : children_arr->append (make_sarif_node (n.get_child (i),
2971 : : builder,
2972 : : sarif_location_mgr));
2973 : 295 : result->set ("children", std::move (children_arr));
2974 : 295 : }
2975 : :
2976 : 946 : return result;
2977 : : }
2978 : :
2979 : : std::unique_ptr<sarif_edge>
2980 : 441 : make_sarif_edge (const digraphs::edge &e,
2981 : : sarif_builder *builder)
2982 : : {
2983 : 441 : auto result = std::make_unique<sarif_edge> ();
2984 : :
2985 : : // 3.41.2 id property
2986 : 882 : result->set_string ("id", e.get_id ().c_str ());
2987 : :
2988 : 441 : copy_any_property_bag (e, *result);
2989 : :
2990 : : // 3.41.3 label property
2991 : 441 : if (const char *label = e.get_label ())
2992 : 394 : if (builder)
2993 : 390 : result->set<sarif_message> ("label",
2994 : 390 : builder->make_message_object (label));
2995 : :
2996 : : // 3.41.4 sourceNodeId property
2997 : 882 : result->set_string ("sourceNodeId", e.get_src_node ().get_id ().c_str ());
2998 : :
2999 : : // 3.41.5 targetNodeId property
3000 : 882 : result->set_string ("targetNodeId", e.get_dst_node ().get_id ().c_str ());
3001 : :
3002 : 441 : return result;
3003 : : }
3004 : :
3005 : : void
3006 : 27 : sarif_property_bag::set_graph (const char *property_name,
3007 : : sarif_builder &builder,
3008 : : sarif_location_manager *sarif_location_mgr,
3009 : : const digraphs::digraph &g)
3010 : : {
3011 : 54 : set<sarif_graph> (property_name,
3012 : 27 : make_sarif_graph (g, &builder, sarif_location_mgr));
3013 : 27 : }
3014 : :
3015 : : /* Ensure that m_cached_logical_locs has a "logicalLocation" object
3016 : : (SARIF v2.1.0 section 3.33) for K, and return its index within the
3017 : : array. */
3018 : :
3019 : : int
3020 : 508 : sarif_builder::
3021 : : ensure_sarif_logical_location_for (logical_locations::key k)
3022 : : {
3023 : 508 : gcc_assert (m_logical_loc_mgr);
3024 : :
3025 : 508 : auto sarif_logical_loc = std::make_unique<sarif_logical_location> ();
3026 : :
3027 : 508 : if (const char *short_name = m_logical_loc_mgr->get_short_name (k))
3028 : 508 : sarif_logical_loc->set_string ("name", short_name);
3029 : :
3030 : : /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
3031 : 508 : if (const char *name_with_scope = m_logical_loc_mgr->get_name_with_scope (k))
3032 : 490 : sarif_logical_loc->set_string ("fullyQualifiedName", name_with_scope);
3033 : :
3034 : : /* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */
3035 : 508 : if (const char *internal_name = m_logical_loc_mgr->get_internal_name (k))
3036 : 273 : sarif_logical_loc->set_string ("decoratedName", internal_name);
3037 : :
3038 : : /* "kind" property (SARIF v2.1.0 section 3.33.7). */
3039 : 508 : enum logical_locations::kind kind = m_logical_loc_mgr->get_kind (k);
3040 : 508 : if (const char *sarif_kind_str = maybe_get_sarif_kind (kind))
3041 : 508 : sarif_logical_loc->set_string ("kind", sarif_kind_str);
3042 : :
3043 : : /* "parentIndex" property (SARIF v2.1.0 section 3.33.8). */
3044 : 508 : if (auto parent_key = m_logical_loc_mgr->get_parent (k))
3045 : : {
3046 : : /* Recurse upwards. */
3047 : 235 : int parent_index = ensure_sarif_logical_location_for (parent_key);
3048 : 235 : sarif_logical_loc->set_integer ("parentIndex", parent_index);
3049 : : }
3050 : :
3051 : : /* Consolidate if this logical location already exists. */
3052 : 508 : int index
3053 : 508 : = m_cached_logical_locs->append_uniquely (std::move (sarif_logical_loc));
3054 : :
3055 : 1016 : return index;
3056 : 508 : }
3057 : :
3058 : : /* Ensure that theRuns.logicalLocations (3.14.17) has a "logicalLocation" object
3059 : : (SARIF v2.1.0 section 3.33) for LOGICAL_LOC.
3060 : : Create and return a minimal logicalLocation object referring to the
3061 : : full object by index. */
3062 : :
3063 : : std::unique_ptr<sarif_logical_location>
3064 : 273 : sarif_builder::
3065 : : make_minimal_sarif_logical_location (logical_locations::key logical_loc)
3066 : : {
3067 : 273 : gcc_assert (m_logical_loc_mgr);
3068 : :
3069 : : /* Ensure that m_cached_logical_locs has a "logicalLocation" object
3070 : : (SARIF v2.1.0 section 3.33) for LOGICAL_LOC, and return its index within
3071 : : the array. */
3072 : :
3073 : 273 : auto sarif_logical_loc = std::make_unique <sarif_logical_location> ();
3074 : :
3075 : 273 : int index = ensure_sarif_logical_location_for (logical_loc);
3076 : :
3077 : : // 3.33.3 index property
3078 : 273 : sarif_logical_loc->set_integer ("index", index);
3079 : :
3080 : : /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
3081 : 546 : if (const char *name_with_scope
3082 : 273 : = m_logical_loc_mgr->get_name_with_scope (logical_loc))
3083 : 273 : sarif_logical_loc->set_string ("fullyQualifiedName", name_with_scope);
3084 : :
3085 : 273 : return sarif_logical_loc;
3086 : : }
3087 : :
3088 : : label_text
3089 : 114 : make_sarif_url_for_event (const sarif_code_flow *code_flow,
3090 : : paths::event_id_t event_id)
3091 : : {
3092 : 114 : gcc_assert (event_id.known_p ());
3093 : :
3094 : 114 : if (!code_flow)
3095 : 97 : return label_text ();
3096 : :
3097 : 17 : const sarif_thread_flow_location &tfl_obj
3098 : 17 : = code_flow->get_thread_flow_loc_obj (event_id);
3099 : 17 : const int location_idx = tfl_obj.get_index_within_parent ();
3100 : :
3101 : 17 : const sarif_thread_flow &thread_flow_obj = tfl_obj.get_parent ();
3102 : 17 : const int thread_flow_idx = thread_flow_obj.get_index_within_parent ();
3103 : :
3104 : 17 : const sarif_code_flow &code_flow_obj = thread_flow_obj.get_parent ();
3105 : 17 : const int code_flow_idx = code_flow_obj.get_index_within_parent ();
3106 : :
3107 : 17 : const sarif_result &result_obj = code_flow_obj.get_parent ();
3108 : 17 : const int result_idx = result_obj.get_index_within_parent ();
3109 : :
3110 : : /* We only support a single run object in the log. */
3111 : 17 : const int run_idx = 0;
3112 : :
3113 : 17 : char *buf = xasprintf
3114 : 17 : ("sarif:/runs/%i/results/%i/codeFlows/%i/threadFlows/%i/locations/%i",
3115 : : run_idx, result_idx, code_flow_idx, thread_flow_idx, location_idx);
3116 : 17 : return label_text::take (buf);
3117 : : }
3118 : :
3119 : : /* Make a "codeFlow" object (SARIF v2.1.0 section 3.36) for PATH. */
3120 : :
3121 : : std::unique_ptr<sarif_code_flow>
3122 : 34 : sarif_builder::make_code_flow_object (sarif_result &result,
3123 : : unsigned idx_within_parent,
3124 : : const paths::path &path)
3125 : : {
3126 : 34 : auto code_flow_obj
3127 : 34 : = std::make_unique <sarif_code_flow> (result, idx_within_parent);
3128 : :
3129 : : /* First pass:
3130 : : Create threadFlows and threadFlowLocation objects within them,
3131 : : effectively recording a mapping from event_id to threadFlowLocation
3132 : : so that we can later go from an event_id to a URI within the
3133 : : SARIF file. */
3134 : 198 : for (unsigned i = 0; i < path.num_events (); i++)
3135 : : {
3136 : 164 : const paths::event &event = path.get_event (i);
3137 : 164 : const paths::thread_id_t thread_id = event.get_thread_id ();
3138 : :
3139 : 164 : sarif_thread_flow &thread_flow_obj
3140 : 164 : = code_flow_obj->get_or_append_thread_flow (path.get_thread (thread_id),
3141 : : thread_id);
3142 : 164 : thread_flow_obj.add_location ();
3143 : : }
3144 : :
3145 : : /* Second pass: walk the events, populating the tfl objs. */
3146 : 34 : m_current_code_flow = code_flow_obj.get ();
3147 : 198 : for (unsigned i = 0; i < path.num_events (); i++)
3148 : : {
3149 : 164 : const paths::event &event = path.get_event (i);
3150 : 164 : sarif_thread_flow_location &thread_flow_loc_obj
3151 : 164 : = code_flow_obj->get_thread_flow_loc_obj (i);
3152 : 164 : populate_thread_flow_location_object (result,
3153 : : thread_flow_loc_obj,
3154 : : event,
3155 : : i);
3156 : : }
3157 : 34 : m_current_code_flow = nullptr;
3158 : :
3159 : 34 : return code_flow_obj;
3160 : : }
3161 : :
3162 : : /* Populate TFL_OBJ, a "threadFlowLocation" object (SARIF v2.1.0 section 3.38)
3163 : : based on EVENT. */
3164 : :
3165 : : void
3166 : 164 : sarif_builder::
3167 : : populate_thread_flow_location_object (sarif_result &result,
3168 : : sarif_thread_flow_location &tfl_obj,
3169 : : const paths::event &ev,
3170 : : int event_execution_idx)
3171 : : {
3172 : : /* Give paths::event subclasses a chance to add custom properties
3173 : : via a property bag. */
3174 : 164 : ev.maybe_add_sarif_properties (*this, tfl_obj);
3175 : :
3176 : 164 : if (get_opts ().m_state_graph)
3177 : 27 : if (auto state_graph = ev.maybe_make_diagnostic_state_graph (true))
3178 : : {
3179 : 27 : sarif_property_bag &props = tfl_obj.get_or_create_properties ();
3180 : :
3181 : : #define PROPERTY_PREFIX "gcc/diagnostics/paths/event/"
3182 : 27 : props.set_graph (PROPERTY_PREFIX "state_graph",
3183 : : *this,
3184 : : /* Use RESULT for any related locations in the graph's
3185 : : nodes.
3186 : : It's not clear if this is correct; see:
3187 : : https://github.com/oasis-tcs/sarif-spec/issues/712
3188 : : */
3189 : : &result,
3190 : 27 : *state_graph);
3191 : : #undef PROPERTY_PREFIX
3192 : 27 : }
3193 : :
3194 : : /* "location" property (SARIF v2.1.0 section 3.38.3). */
3195 : 164 : tfl_obj.set<sarif_location>
3196 : 328 : ("location",
3197 : 164 : make_location_object (result, ev, diagnostic_artifact_role::traced_file));
3198 : :
3199 : : /* "kinds" property (SARIF v2.1.0 section 3.38.8). */
3200 : 164 : paths::event::meaning m = ev.get_meaning ();
3201 : 164 : if (auto kinds_arr = maybe_make_kinds_array (m))
3202 : 164 : tfl_obj.set<json::array> ("kinds", std::move (kinds_arr));
3203 : :
3204 : : /* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */
3205 : 164 : tfl_obj.set_integer ("nestingLevel", ev.get_stack_depth ());
3206 : :
3207 : : /* "executionOrder" property (SARIF v2.1.0 3.38.11).
3208 : : Offset by 1 to match the human-readable values emitted by %@. */
3209 : 164 : tfl_obj.set_integer ("executionOrder", event_execution_idx + 1);
3210 : :
3211 : : /* It might be nice to eventually implement the following for -fanalyzer:
3212 : : - the "stack" property (SARIF v2.1.0 section 3.38.5)
3213 : : - the "state" property (SARIF v2.1.0 section 3.38.9)
3214 : : - the "importance" property (SARIF v2.1.0 section 3.38.13). */
3215 : 164 : }
3216 : :
3217 : : /* If M has any known meaning, make a json array suitable for the "kinds"
3218 : : property of a "threadFlowLocation" object (SARIF v2.1.0 section 3.38.8).
3219 : :
3220 : : Otherwise, return nullptr. */
3221 : :
3222 : : std::unique_ptr<json::array>
3223 : 164 : sarif_builder::
3224 : : maybe_make_kinds_array (paths::event::meaning m) const
3225 : : {
3226 : 164 : using namespace paths;
3227 : :
3228 : 164 : if (m.m_verb == event::verb::unknown
3229 : 22 : && m.m_noun == event::noun::unknown
3230 : 22 : && m.m_property == event::property::unknown)
3231 : 22 : return nullptr;
3232 : :
3233 : 142 : auto kinds_arr = std::make_unique<json::array> ();
3234 : 284 : if (const char *verb_str
3235 : 142 : = event::meaning::maybe_get_verb_str (m.m_verb))
3236 : 142 : kinds_arr->append_string (verb_str);
3237 : 284 : if (const char *noun_str
3238 : 142 : = event::meaning::maybe_get_noun_str (m.m_noun))
3239 : 62 : kinds_arr->append_string (noun_str);
3240 : 284 : if (const char *property_str
3241 : 142 : = event::meaning::maybe_get_property_str (m.m_property))
3242 : 30 : kinds_arr->append_string (property_str);
3243 : 142 : return kinds_arr;
3244 : 142 : }
3245 : :
3246 : : /* In "3.11.5 Messages with placeholders":
3247 : : "Within both plain text and formatted message strings, the characters
3248 : : "{" and "}" SHALL be represented by the character sequences
3249 : : "{{" and "}}" respectively." */
3250 : :
3251 : : static std::string
3252 : 2143 : escape_braces (const char *text)
3253 : : {
3254 : 2143 : std::string result;
3255 : 71485 : while (char ch = *text++)
3256 : 69342 : switch (ch)
3257 : : {
3258 : 36 : case '{':
3259 : 36 : case '}':
3260 : 36 : result += ch;
3261 : : /* Fall through. */
3262 : 69342 : default:
3263 : 69342 : result += ch;
3264 : 69342 : break;
3265 : : }
3266 : 2143 : return result;
3267 : : }
3268 : :
3269 : : static void
3270 : 2143 : set_string_property_escaping_braces (json::object &obj,
3271 : : const char *property_name,
3272 : : const char *value)
3273 : : {
3274 : 2143 : std::string escaped (escape_braces (value));
3275 : 2143 : obj.set_string (property_name, escaped.c_str ());
3276 : 2143 : }
3277 : :
3278 : : /* Make a "message" object (SARIF v2.1.0 section 3.11) for MSG. */
3279 : :
3280 : : std::unique_ptr<sarif_message>
3281 : 1977 : sarif_builder::make_message_object (const char *msg) const
3282 : : {
3283 : 1977 : auto message_obj = std::make_unique<sarif_message> ();
3284 : :
3285 : : /* "text" property (SARIF v2.1.0 section 3.11.8). */
3286 : 1977 : set_string_property_escaping_braces (*message_obj,
3287 : : "text", msg);
3288 : :
3289 : 1977 : return message_obj;
3290 : : }
3291 : :
3292 : : /* Make a "message" object (SARIF v2.1.0 section 3.11) for D.
3293 : : We emit the diagram as a code block within the Markdown part
3294 : : of the message. */
3295 : :
3296 : : std::unique_ptr<sarif_message>
3297 : 4 : sarif_builder::make_message_object_for_diagram (const diagram &d)
3298 : : {
3299 : 4 : auto message_obj = std::make_unique<sarif_message> ();
3300 : :
3301 : : /* "text" property (SARIF v2.1.0 section 3.11.8). */
3302 : 4 : set_string_property_escaping_braces (*message_obj,
3303 : : "text", d.get_alt_text ());
3304 : :
3305 : 4 : pretty_printer *const pp = m_printer;
3306 : 4 : char *saved_prefix = pp_take_prefix (pp);
3307 : 4 : pp_set_prefix (pp, nullptr);
3308 : :
3309 : : /* "To produce a code block in Markdown, simply indent every line of
3310 : : the block by at least 4 spaces or 1 tab."
3311 : : Here we use 4 spaces. */
3312 : 4 : d.get_canvas ().print_to_pp (pp, " ");
3313 : 4 : pp_set_prefix (pp, saved_prefix);
3314 : :
3315 : : /* "markdown" property (SARIF v2.1.0 section 3.11.9). */
3316 : 4 : set_string_property_escaping_braces (*message_obj,
3317 : : "markdown", pp_formatted_text (pp));
3318 : :
3319 : 4 : pp_clear_output_area (pp);
3320 : :
3321 : 4 : return message_obj;
3322 : : }
3323 : :
3324 : : /* Make a "multiformatMessageString object" (SARIF v2.1.0 section 3.12)
3325 : : for MSG. */
3326 : :
3327 : : std::unique_ptr<sarif_multiformat_message_string>
3328 : 158 : sarif_builder::make_multiformat_message_string (const char *msg) const
3329 : : {
3330 : 158 : auto message_obj = std::make_unique<sarif_multiformat_message_string> ();
3331 : :
3332 : : /* "text" property (SARIF v2.1.0 section 3.12.3). */
3333 : 158 : set_string_property_escaping_braces (*message_obj,
3334 : : "text", msg);
3335 : :
3336 : 158 : return message_obj;
3337 : : }
3338 : :
3339 : : /* Convert VERSION to a value for the "$schema" property
3340 : : of a "sarifLog" object (SARIF v2.1.0 section 3.13.3). */
3341 : :
3342 : : static const char *
3343 : 288 : sarif_version_to_url (enum sarif_version version)
3344 : : {
3345 : 288 : switch (version)
3346 : : {
3347 : 0 : default:
3348 : 0 : gcc_unreachable ();
3349 : : case sarif_version::v2_1_0:
3350 : : return "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json";
3351 : 90 : case sarif_version::v2_2_prerelease_2024_08_08:
3352 : 90 : return "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/refs/tags/2.2-prerelease-2024-08-08/sarif-2.2/schema/sarif-2-2.schema.json";
3353 : : }
3354 : : }
3355 : :
3356 : : /* Convert VERSION to a value for the "version" property
3357 : : of a "sarifLog" object (SARIF v2.1.0 section 3.13.2). */
3358 : :
3359 : : static const char *
3360 : 288 : sarif_version_to_property (enum sarif_version version)
3361 : : {
3362 : 288 : switch (version)
3363 : : {
3364 : 0 : default:
3365 : 0 : gcc_unreachable ();
3366 : : case sarif_version::v2_1_0:
3367 : : return "2.1.0";
3368 : 90 : case sarif_version::v2_2_prerelease_2024_08_08:
3369 : : /* I would have used "2.2-prerelease-2024-08-08",
3370 : : but the schema only accepts "2.2". */
3371 : 90 : return "2.2";
3372 : : }
3373 : : }
3374 : :
3375 : : /* Make a top-level "sarifLog" object (SARIF v2.1.0 section 3.13). */
3376 : :
3377 : : std::unique_ptr<sarif_log>
3378 : 280 : sarif_builder::
3379 : : make_top_level_object (std::unique_ptr<sarif_invocation> invocation_obj,
3380 : : std::unique_ptr<json::array> results)
3381 : : {
3382 : 280 : auto log_obj = std::make_unique<sarif_log> ();
3383 : :
3384 : : /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */
3385 : 280 : log_obj->set_string ("$schema", sarif_version_to_url (get_version ()));
3386 : :
3387 : : /* "version" property (SARIF v2.1.0 section 3.13.2). */
3388 : 280 : log_obj->set_string ("version", sarif_version_to_property (get_version ()));
3389 : :
3390 : : /* "runs" property (SARIF v2.1.0 section 3.13.4). */
3391 : 280 : auto run_arr = std::make_unique<json::array> ();
3392 : 280 : auto run_obj = make_run_object (std::move (invocation_obj),
3393 : 280 : std::move (results));
3394 : 280 : run_arr->append<sarif_run> (std::move (run_obj));
3395 : 280 : log_obj->set<json::array> ("runs", std::move (run_arr));
3396 : :
3397 : 560 : return log_obj;
3398 : 280 : }
3399 : :
3400 : : /* Make a "run" object (SARIF v2.1.0 section 3.14). */
3401 : :
3402 : : std::unique_ptr<sarif_run>
3403 : 280 : sarif_builder::
3404 : : make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
3405 : : std::unique_ptr<json::array> results)
3406 : : {
3407 : 280 : auto run_obj = std::make_unique<sarif_run> ();
3408 : :
3409 : : /* "tool" property (SARIF v2.1.0 section 3.14.6). */
3410 : 280 : run_obj->set<sarif_tool> ("tool", make_tool_object ());
3411 : :
3412 : : /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
3413 : 280 : if (auto taxonomies_arr = maybe_make_taxonomies_array ())
3414 : 280 : run_obj->set<json::array> ("taxonomies", std::move (taxonomies_arr));
3415 : :
3416 : : /* "invocations" property (SARIF v2.1.0 section 3.14.11). */
3417 : 280 : {
3418 : 280 : auto invocations_arr = std::make_unique<json::array> ();
3419 : 280 : invocations_arr->append (std::move (invocation_obj));
3420 : 280 : run_obj->set<json::array> ("invocations", std::move (invocations_arr));
3421 : 280 : }
3422 : :
3423 : : /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */
3424 : 280 : if (m_seen_any_relative_paths)
3425 : : {
3426 : 44 : auto orig_uri_base_ids = std::make_unique<json::object> ();
3427 : 44 : orig_uri_base_ids->set<sarif_artifact_location>
3428 : 44 : (PWD_PROPERTY_NAME, make_artifact_location_object_for_pwd ());
3429 : 44 : run_obj->set<json::object> ("originalUriBaseIds",
3430 : : std::move (orig_uri_base_ids));
3431 : 44 : }
3432 : :
3433 : : /* "artifacts" property (SARIF v2.1.0 section 3.14.15). */
3434 : 280 : auto artifacts_arr = std::make_unique<json::array> ();
3435 : 858 : for (auto iter : m_filename_to_artifact_map)
3436 : : {
3437 : 298 : sarif_artifact *artifact_obj = iter.second;
3438 : 298 : if (artifact_obj->embed_contents_p ())
3439 : 240 : artifact_obj->populate_contents (*this);
3440 : 298 : artifact_obj->populate_roles ();
3441 : 298 : artifacts_arr->append (artifact_obj);
3442 : : }
3443 : 280 : run_obj->set<json::array> ("artifacts", std::move (artifacts_arr));
3444 : 280 : m_filename_to_artifact_map.empty ();
3445 : :
3446 : : /* "results" property (SARIF v2.1.0 section 3.14.23). */
3447 : 280 : run_obj->set<json::array> ("results", std::move (results));
3448 : :
3449 : : /* "logicalLocations" property (SARIF v2.1.0 3.14.17). */
3450 : 280 : if (m_cached_logical_locs->size () > 0)
3451 : : {
3452 : 61 : m_cached_logical_locs->add_explicit_index_values ();
3453 : 61 : run_obj->set<json::array> ("logicalLocations",
3454 : 61 : std::move (m_cached_logical_locs));
3455 : : }
3456 : :
3457 : : // "graphs" property (SARIF v2.1.0 3.14.20)
3458 : 280 : if (m_run_graphs->size () > 0)
3459 : 1 : run_obj->set<json::array> ("graphs",
3460 : 1 : std::move (m_run_graphs));
3461 : :
3462 : 560 : return run_obj;
3463 : 280 : }
3464 : :
3465 : : /* Make a "tool" object (SARIF v2.1.0 section 3.18). */
3466 : :
3467 : : std::unique_ptr<sarif_tool>
3468 : 280 : sarif_builder::make_tool_object ()
3469 : : {
3470 : 280 : auto tool_obj = std::make_unique<sarif_tool> ();
3471 : :
3472 : : /* "driver" property (SARIF v2.1.0 section 3.18.2). */
3473 : 280 : tool_obj->set<sarif_tool_component> ("driver",
3474 : 280 : make_driver_tool_component_object ());
3475 : :
3476 : : /* Report plugins via the "extensions" property
3477 : : (SARIF v2.1.0 section 3.18.3). */
3478 : 280 : if (auto client_data_hooks = m_context.get_client_data_hooks ())
3479 : 224 : if (const client_version_info *vinfo
3480 : 112 : = client_data_hooks->get_any_version_info ())
3481 : : {
3482 : 112 : class my_plugin_visitor : public client_version_info :: plugin_visitor
3483 : : {
3484 : : public:
3485 : : void
3486 : 11 : on_plugin (const client_plugin_info &p) final override
3487 : : {
3488 : : /* Create a "toolComponent" object (SARIF v2.1.0 section 3.19)
3489 : : for the plugin. */
3490 : 11 : auto plugin_obj = std::make_unique<sarif_tool_component> ();
3491 : :
3492 : : /* "name" property (SARIF v2.1.0 section 3.19.8). */
3493 : 11 : if (const char *short_name = p.get_short_name ())
3494 : 11 : plugin_obj->set_string ("name", short_name);
3495 : :
3496 : : /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
3497 : 11 : if (const char *full_name = p.get_full_name ())
3498 : 11 : plugin_obj->set_string ("fullName", full_name);
3499 : :
3500 : : /* "version" property (SARIF v2.1.0 section 3.19.13). */
3501 : 11 : if (const char *version = p.get_version ())
3502 : 0 : plugin_obj->set_string ("version", version);
3503 : :
3504 : 11 : m_plugin_objs.push_back (std::move (plugin_obj));
3505 : 11 : }
3506 : : std::vector<std::unique_ptr<sarif_tool_component>> m_plugin_objs;
3507 : : };
3508 : 112 : my_plugin_visitor v;
3509 : 112 : vinfo->for_each_plugin (v);
3510 : 112 : if (v.m_plugin_objs.size () > 0)
3511 : : {
3512 : 11 : auto extensions_arr = std::make_unique<json::array> ();
3513 : 22 : for (auto &iter : v.m_plugin_objs)
3514 : 11 : extensions_arr->append<sarif_tool_component> (std::move (iter));
3515 : 11 : tool_obj->set<json::array> ("extensions",
3516 : : std::move (extensions_arr));
3517 : 11 : }
3518 : 112 : }
3519 : :
3520 : : /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other
3521 : : "extensions" (see toplev.cc: print_version). */
3522 : :
3523 : 280 : return tool_obj;
3524 : : }
3525 : :
3526 : : /* Make a "toolComponent" object (SARIF v2.1.0 section 3.19) for what SARIF
3527 : : calls the "driver" (see SARIF v2.1.0 section 3.18.1). */
3528 : :
3529 : : std::unique_ptr<sarif_tool_component>
3530 : 280 : sarif_builder::make_driver_tool_component_object ()
3531 : : {
3532 : 280 : auto driver_obj = std::make_unique<sarif_tool_component> ();
3533 : :
3534 : 280 : if (auto client_data_hooks = m_context.get_client_data_hooks ())
3535 : 224 : if (const client_version_info *vinfo
3536 : 112 : = client_data_hooks->get_any_version_info ())
3537 : : {
3538 : : /* "name" property (SARIF v2.1.0 section 3.19.8). */
3539 : 112 : if (const char *name = vinfo->get_tool_name ())
3540 : 112 : driver_obj->set_string ("name", name);
3541 : :
3542 : : /* "fullName" property (SARIF v2.1.0 section 3.19.9). */
3543 : 112 : if (char *full_name = vinfo->maybe_make_full_name ())
3544 : : {
3545 : 112 : driver_obj->set_string ("fullName", full_name);
3546 : 112 : free (full_name);
3547 : : }
3548 : :
3549 : : /* "version" property (SARIF v2.1.0 section 3.19.13). */
3550 : 112 : if (const char *version = vinfo->get_version_string ())
3551 : 112 : driver_obj->set_string ("version", version);
3552 : :
3553 : : /* "informationUri" property (SARIF v2.1.0 section 3.19.17). */
3554 : 112 : if (char *version_url = vinfo->maybe_make_version_url ())
3555 : : {
3556 : 112 : driver_obj->set_string ("informationUri", version_url);
3557 : 112 : free (version_url);
3558 : : }
3559 : : }
3560 : :
3561 : : /* "rules" property (SARIF v2.1.0 section 3.19.23). */
3562 : 280 : driver_obj->set<json::array> ("rules", std::move (m_rules_arr));
3563 : :
3564 : 280 : return driver_obj;
3565 : : }
3566 : :
3567 : : /* If we've seen any CWE IDs, make an array for the "taxonomies" property
3568 : : (SARIF v2.1.0 section 3.14.8) of a run object, containing a single
3569 : : "toolComponent" (3.19) as per 3.19.3, representing the CWE.
3570 : :
3571 : : Otherwise return nullptr. */
3572 : :
3573 : : std::unique_ptr<json::array>
3574 : 280 : sarif_builder::maybe_make_taxonomies_array () const
3575 : : {
3576 : 280 : auto cwe_obj = maybe_make_cwe_taxonomy_object ();
3577 : 280 : if (!cwe_obj)
3578 : 258 : return nullptr;
3579 : :
3580 : : /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
3581 : 22 : auto taxonomies_arr = std::make_unique<json::array> ();
3582 : 22 : taxonomies_arr->append<sarif_tool_component> (std::move (cwe_obj));
3583 : 22 : return taxonomies_arr;
3584 : 280 : }
3585 : :
3586 : : /* If we've seen any CWE IDs, make a "toolComponent" object
3587 : : (SARIF v2.1.0 section 3.19) representing the CWE taxonomy, as per 3.19.3.
3588 : : Populate the "taxa" property with all of the CWE IDs in m_cwe_id_set.
3589 : :
3590 : : Otherwise return nullptr. */
3591 : :
3592 : : std::unique_ptr<sarif_tool_component>
3593 : 280 : sarif_builder::maybe_make_cwe_taxonomy_object () const
3594 : : {
3595 : 280 : if (m_cwe_id_set.is_empty ())
3596 : 258 : return nullptr;
3597 : :
3598 : 22 : auto taxonomy_obj = std::make_unique<sarif_tool_component> ();
3599 : :
3600 : : /* "name" property (SARIF v2.1.0 section 3.19.8). */
3601 : 22 : taxonomy_obj->set_string ("name", "CWE");
3602 : :
3603 : : /* "version" property (SARIF v2.1.0 section 3.19.13). */
3604 : 22 : taxonomy_obj->set_string ("version", "4.7");
3605 : :
3606 : : /* "organization" property (SARIF v2.1.0 section 3.19.18). */
3607 : 22 : taxonomy_obj->set_string ("organization", "MITRE");
3608 : :
3609 : : /* "shortDescription" property (SARIF v2.1.0 section 3.19.19). */
3610 : 22 : taxonomy_obj->set<sarif_multiformat_message_string>
3611 : 22 : ("shortDescription",
3612 : 22 : make_multiformat_message_string ("The MITRE"
3613 : : " Common Weakness Enumeration"));
3614 : :
3615 : : /* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */
3616 : 22 : auto taxa_arr = std::make_unique<json::array> ();
3617 : 44 : for (auto cwe_id : m_cwe_id_set)
3618 : 22 : taxa_arr->append<sarif_reporting_descriptor>
3619 : 22 : (make_reporting_descriptor_object_for_cwe_id (cwe_id));
3620 : 22 : taxonomy_obj->set<json::array> ("taxa", std::move (taxa_arr));
3621 : :
3622 : 22 : return taxonomy_obj;
3623 : 22 : }
3624 : :
3625 : : /* Ensure that we have an "artifact" object (SARIF v2.1.0 section 3.24)
3626 : : for FILENAME, adding it to m_filename_to_artifact_map if not already
3627 : : found, and adding ROLE to it.
3628 : : If EMBED_CONTENTS is true, then flag that we will attempt to embed the
3629 : : contents of this artifact when writing it out. */
3630 : :
3631 : : sarif_artifact &
3632 : 1138 : sarif_builder::get_or_create_artifact (const char *filename,
3633 : : enum diagnostic_artifact_role role,
3634 : : bool embed_contents)
3635 : : {
3636 : 1138 : if (auto *slot = m_filename_to_artifact_map.get (filename))
3637 : : {
3638 : 704 : (*slot)->add_role (role, embed_contents);
3639 : 704 : return **slot;
3640 : : }
3641 : :
3642 : 434 : sarif_artifact *artifact_obj = new sarif_artifact (filename);
3643 : 434 : artifact_obj->add_role (role, embed_contents);
3644 : 434 : m_filename_to_artifact_map.put (filename, artifact_obj);
3645 : :
3646 : : /* "location" property (SARIF v2.1.0 section 3.24.2). */
3647 : 434 : artifact_obj->set<sarif_artifact_location>
3648 : 434 : ("location", make_artifact_location_object (filename));
3649 : :
3650 : : /* "sourceLanguage" property (SARIF v2.1.0 section 3.24.10). */
3651 : 434 : switch (role)
3652 : : {
3653 : 0 : default:
3654 : 0 : gcc_unreachable ();
3655 : 434 : case diagnostic_artifact_role::analysis_target:
3656 : 434 : case diagnostic_artifact_role::result_file:
3657 : 434 : case diagnostic_artifact_role::scanned_file:
3658 : 434 : case diagnostic_artifact_role::traced_file:
3659 : : /* Assume that these are in the source language. */
3660 : 434 : if (auto client_data_hooks = m_context.get_client_data_hooks ())
3661 : 260 : if (const char *source_lang
3662 : 130 : = client_data_hooks->maybe_get_sarif_source_language (filename))
3663 : 130 : artifact_obj->set_string ("sourceLanguage", source_lang);
3664 : : break;
3665 : :
3666 : : case diagnostic_artifact_role::debug_output_file:
3667 : : /* Assume that these are not in the source language. */
3668 : : break;
3669 : : }
3670 : :
3671 : : return *artifact_obj;
3672 : : }
3673 : :
3674 : : /* Make an "artifactContent" object (SARIF v2.1.0 section 3.3) for the
3675 : : full contents of FILENAME. */
3676 : :
3677 : : std::unique_ptr<sarif_artifact_content>
3678 : 240 : sarif_builder::maybe_make_artifact_content_object (const char *filename) const
3679 : : {
3680 : : /* Let input.cc handle any charset conversion. */
3681 : 240 : char_span utf8_content
3682 : 240 : = m_context.get_file_cache ().get_source_file_content (filename);
3683 : 240 : if (!utf8_content)
3684 : 4 : return nullptr;
3685 : :
3686 : : /* Don't add it if it's not valid UTF-8. */
3687 : 236 : if (!cpp_valid_utf8_p(utf8_content.get_buffer (), utf8_content.length ()))
3688 : 12 : return nullptr;
3689 : :
3690 : 224 : auto artifact_content_obj = std::make_unique<sarif_artifact_content> ();
3691 : 224 : artifact_content_obj->set<json::string>
3692 : 448 : ("text",
3693 : 224 : std::make_unique <json::string> (utf8_content.get_buffer (),
3694 : 224 : utf8_content.length ()));
3695 : 224 : return artifact_content_obj;
3696 : 224 : }
3697 : :
3698 : : /* Attempt to read the given range of lines from FILENAME; return
3699 : : a freshly-allocated 0-terminated buffer containing them, or nullptr. */
3700 : :
3701 : : char *
3702 : 846 : sarif_builder::get_source_lines (const char *filename,
3703 : : int start_line,
3704 : : int end_line) const
3705 : : {
3706 : 846 : auto_vec<char> result;
3707 : :
3708 : 1692 : for (int line = start_line; line <= end_line; line++)
3709 : : {
3710 : 846 : char_span line_content
3711 : 846 : = m_context.get_file_cache ().get_source_line (filename, line);
3712 : 846 : if (!line_content.get_buffer ())
3713 : 0 : return nullptr;
3714 : 846 : result.reserve (line_content.length () + 1);
3715 : 23975 : for (size_t i = 0; i < line_content.length (); i++)
3716 : 23129 : result.quick_push (line_content[i]);
3717 : 846 : result.quick_push ('\n');
3718 : : }
3719 : 846 : result.safe_push ('\0');
3720 : :
3721 : 1692 : return xstrdup (result.address ());
3722 : 846 : }
3723 : :
3724 : : /* Make an "artifactContent" object (SARIF v2.1.0 section 3.3) for the given
3725 : : run of lines within FILENAME (including the endpoints).
3726 : : If R is non-NULL, use it to potentially set the "rendered"
3727 : : property (3.3.4). */
3728 : :
3729 : : std::unique_ptr<sarif_artifact_content>
3730 : 846 : sarif_builder::
3731 : : maybe_make_artifact_content_object (const char *filename,
3732 : : int start_line,
3733 : : int end_line,
3734 : : const content_renderer *r) const
3735 : : {
3736 : 846 : char *text_utf8 = get_source_lines (filename, start_line, end_line);
3737 : :
3738 : 846 : if (!text_utf8)
3739 : 0 : return nullptr;
3740 : :
3741 : : /* Don't add it if it's not valid UTF-8. */
3742 : 846 : if (!cpp_valid_utf8_p(text_utf8, strlen(text_utf8)))
3743 : : {
3744 : 172 : free (text_utf8);
3745 : 172 : return nullptr;
3746 : : }
3747 : :
3748 : 674 : auto artifact_content_obj = std::make_unique<sarif_artifact_content> ();
3749 : 674 : artifact_content_obj->set_string ("text", text_utf8);
3750 : 674 : free (text_utf8);
3751 : :
3752 : : /* 3.3.4 "rendered" property. */
3753 : 674 : if (r)
3754 : 136 : if (std::unique_ptr<sarif_multiformat_message_string> rendered
3755 : 136 : = r->render (*this))
3756 : 136 : artifact_content_obj->set ("rendered", std::move (rendered));
3757 : :
3758 : 674 : return artifact_content_obj;
3759 : 674 : }
3760 : :
3761 : : /* Attempt to generate a "message" object describing a fix-it hint,
3762 : : or null if there was a problem. */
3763 : :
3764 : : std::unique_ptr<sarif_message>
3765 : 9 : sarif_builder::
3766 : : make_message_describing_fix_it_hint (const fixit_hint &hint) const
3767 : : {
3768 : 9 : pretty_printer pp;
3769 : 9 : if (hint.insertion_p ())
3770 : 4 : pp_printf (&pp, G_("Insert %qs"), hint.get_string ());
3771 : : else
3772 : : {
3773 : : /* Try to get prior content. */
3774 : 5 : expanded_location start = expand_location (hint.get_start_loc ());
3775 : 5 : expanded_location next_loc = expand_location (hint.get_next_loc ());
3776 : 5 : if (start.file != next_loc.file)
3777 : 0 : return nullptr;
3778 : 5 : if (start.line != next_loc.line)
3779 : 0 : return nullptr;
3780 : 5 : if (start.column == 0)
3781 : 0 : return nullptr;
3782 : 5 : if (next_loc.column == 0)
3783 : 0 : return nullptr;
3784 : :
3785 : 5 : const int start_offset = start.column - 1;
3786 : 5 : const int next_offset = next_loc.column - 1;
3787 : 5 : if (next_offset <= start_offset)
3788 : 0 : return nullptr;
3789 : :
3790 : 5 : size_t victim_len = next_offset - start_offset;
3791 : :
3792 : 5 : char_span existing_line = get_context ()
3793 : 5 : .get_file_cache ()
3794 : 5 : .get_source_line (start.file, start.line);
3795 : 5 : if (!existing_line)
3796 : 0 : return nullptr;
3797 : :
3798 : 5 : label_text existing_text
3799 : 5 : = label_text::take (existing_line.subspan (start_offset,
3800 : 5 : victim_len).xstrdup ());
3801 : :
3802 : 5 : if (hint.deletion_p ())
3803 : : {
3804 : : // Removal
3805 : 1 : pp_printf (&pp, G_("Delete %qs"),
3806 : : existing_text.get ());
3807 : : }
3808 : : else
3809 : : {
3810 : : // Replacement
3811 : 4 : gcc_assert (hint.replacement_p ());
3812 : 4 : pp_printf (&pp, G_("Replace %qs with %qs"),
3813 : : existing_text.get (),
3814 : : hint.get_string ());
3815 : : }
3816 : 5 : }
3817 : 9 : return make_message_object (pp_formatted_text (&pp));
3818 : 9 : }
3819 : :
3820 : : /* Make a "fix" object (SARIF v2.1.0 section 3.55) for RICHLOC. */
3821 : :
3822 : : std::unique_ptr<sarif_fix>
3823 : 9 : sarif_builder::make_fix_object (const rich_location &richloc)
3824 : : {
3825 : 9 : auto fix_obj = std::make_unique<sarif_fix> ();
3826 : :
3827 : : /* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */
3828 : : /* We assume that all fix-it hints in RICHLOC affect the same file. */
3829 : 9 : auto artifact_change_arr = std::make_unique<json::array> ();
3830 : 9 : artifact_change_arr->append<sarif_artifact_change>
3831 : 9 : (make_artifact_change_object (richloc));
3832 : 9 : fix_obj->set<json::array> ("artifactChanges",
3833 : : std::move (artifact_change_arr));
3834 : :
3835 : : // 3.55.2 "description" property
3836 : : /* Attempt to generate a description. We can only do this
3837 : : if there was a single hint. */
3838 : 9 : if (richloc.get_num_fixit_hints () == 1)
3839 : : {
3840 : 9 : const fixit_hint *hint = richloc.get_fixit_hint (0);
3841 : 9 : gcc_assert (hint);
3842 : 9 : if (auto desc_msg = make_message_describing_fix_it_hint (*hint))
3843 : 9 : fix_obj->set<sarif_message> ("description",
3844 : 9 : std::move (desc_msg));
3845 : : }
3846 : :
3847 : 18 : return fix_obj;
3848 : 9 : }
3849 : :
3850 : : /* Make an "artifactChange" object (SARIF v2.1.0 section 3.56) for RICHLOC. */
3851 : :
3852 : : std::unique_ptr<sarif_artifact_change>
3853 : 9 : sarif_builder::make_artifact_change_object (const rich_location &richloc)
3854 : : {
3855 : 9 : auto artifact_change_obj = std::make_unique<sarif_artifact_change> ();
3856 : :
3857 : : /* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */
3858 : 9 : artifact_change_obj->set<sarif_artifact_location>
3859 : 9 : ("artifactLocation",
3860 : 9 : make_artifact_location_object (richloc.get_loc ()));
3861 : :
3862 : : /* "replacements" property (SARIF v2.1.0 section 3.56.3). */
3863 : 9 : auto replacement_arr = std::make_unique<json::array> ();
3864 : 18 : for (unsigned int i = 0; i < richloc.get_num_fixit_hints (); i++)
3865 : : {
3866 : 9 : const fixit_hint *hint = richloc.get_fixit_hint (i);
3867 : 9 : replacement_arr->append<sarif_replacement>
3868 : 9 : (make_replacement_object (*hint));
3869 : : }
3870 : 9 : artifact_change_obj->set<json::array> ("replacements",
3871 : : std::move (replacement_arr));
3872 : :
3873 : 18 : return artifact_change_obj;
3874 : 9 : }
3875 : :
3876 : : /* Make a "replacement" object (SARIF v2.1.0 section 3.57) for HINT. */
3877 : :
3878 : : std::unique_ptr<sarif_replacement>
3879 : 9 : sarif_builder::make_replacement_object (const fixit_hint &hint) const
3880 : : {
3881 : 9 : auto replacement_obj = std::make_unique<sarif_replacement> ();
3882 : :
3883 : : /* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */
3884 : 9 : replacement_obj->set<sarif_region> ("deletedRegion",
3885 : 9 : make_region_object_for_hint (hint));
3886 : :
3887 : : /* "insertedContent" property (SARIF v2.1.0 section 3.57.4). */
3888 : 9 : replacement_obj->set<sarif_artifact_content>
3889 : 9 : ("insertedContent",
3890 : 9 : make_artifact_content_object (hint.get_string ()));
3891 : :
3892 : 9 : return replacement_obj;
3893 : : }
3894 : :
3895 : : /* Make an "artifactContent" object (SARIF v2.1.0 section 3.3) for TEXT. */
3896 : :
3897 : : std::unique_ptr<sarif_artifact_content>
3898 : 9 : sarif_builder::make_artifact_content_object (const char *text) const
3899 : : {
3900 : 9 : auto content_obj = std::make_unique<sarif_artifact_content> ();
3901 : :
3902 : : /* "text" property (SARIF v2.1.0 section 3.3.2). */
3903 : 9 : content_obj->set_string ("text", text);
3904 : :
3905 : 9 : return content_obj;
3906 : : }
3907 : :
3908 : : /* class sarif_sink_buffer : public per_sink_buffer. */
3909 : :
3910 : : void
3911 : 0 : sarif_sink_buffer::dump (FILE *out, int indent) const
3912 : : {
3913 : 0 : dumping::emit_heading (out, indent, "sarif_sink_buffer");
3914 : 0 : int idx = 0;
3915 : 0 : for (auto &result : m_results)
3916 : : {
3917 : 0 : dumping::emit_indent (out, indent + 2);
3918 : 0 : fprintf (out, "result[%i]:\n", idx);
3919 : 0 : result->dump (out, true);
3920 : 0 : fprintf (out, "\n");
3921 : 0 : ++idx;
3922 : : }
3923 : 0 : }
3924 : :
3925 : : bool
3926 : 61 : sarif_sink_buffer::empty_p () const
3927 : : {
3928 : 61 : return m_results.empty ();
3929 : : }
3930 : :
3931 : : void
3932 : 0 : sarif_sink_buffer::move_to (per_sink_buffer &base)
3933 : : {
3934 : 0 : sarif_sink_buffer &dest
3935 : : = static_cast<sarif_sink_buffer &> (base);
3936 : 0 : for (auto &&result : m_results)
3937 : 0 : dest.m_results.push_back (std::move (result));
3938 : 0 : m_results.clear ();
3939 : 0 : }
3940 : :
3941 : : void
3942 : 22 : sarif_sink_buffer::clear ()
3943 : : {
3944 : 22 : m_results.clear ();
3945 : 22 : }
3946 : :
3947 : : void
3948 : 8 : sarif_sink_buffer::flush ()
3949 : : {
3950 : 16 : for (auto &&result : m_results)
3951 : : {
3952 : 8 : result->process_worklist (m_builder);
3953 : 8 : m_builder.m_results_array->append<sarif_result> (std::move (result));
3954 : : }
3955 : 8 : m_results.clear ();
3956 : 8 : }
3957 : :
3958 : : class sarif_sink : public sink
3959 : : {
3960 : : public:
3961 : 288 : ~sarif_sink ()
3962 : 288 : {
3963 : : /* Any sarifResult objects should have been handled by now.
3964 : : If not, then something's gone wrong with diagnostic
3965 : : groupings. */
3966 : 288 : std::unique_ptr<sarif_result> pending_result
3967 : 288 : = m_builder.take_current_result ();
3968 : 288 : gcc_assert (!pending_result);
3969 : 288 : }
3970 : :
3971 : 0 : void dump (FILE *out, int indent) const override
3972 : : {
3973 : 0 : sink::dump (out, indent);
3974 : 0 : dumping::emit_heading (out, indent, "sarif_builder");
3975 : 0 : m_builder.dump (out, indent + 2);
3976 : 0 : }
3977 : :
3978 : : void
3979 : 288 : set_main_input_filename (const char *name) final override
3980 : : {
3981 : 112 : m_builder.set_main_input_filename (name);
3982 : 112 : }
3983 : :
3984 : : std::unique_ptr<per_sink_buffer>
3985 : 17 : make_per_sink_buffer () final override
3986 : : {
3987 : 17 : return std::make_unique<sarif_sink_buffer> (m_builder);
3988 : : }
3989 : 34 : void set_buffer (per_sink_buffer *base_buffer) final override
3990 : : {
3991 : 34 : sarif_sink_buffer *buffer
3992 : : = static_cast<sarif_sink_buffer *> (base_buffer);
3993 : 34 : m_buffer = buffer;
3994 : 34 : }
3995 : :
3996 : 0 : bool follows_reference_printer_p () const final override
3997 : : {
3998 : 0 : return false;
3999 : : }
4000 : :
4001 : 288 : void update_printer () final override
4002 : : {
4003 : 288 : m_printer = m_context.clone_printer ();
4004 : :
4005 : : /* Don't colorize the text. */
4006 : 288 : pp_show_color (m_printer.get ()) = false;
4007 : :
4008 : : /* No textual URLs. */
4009 : 288 : m_printer->set_url_format (URL_FORMAT_NONE);
4010 : :
4011 : : /* Use builder's token printer. */
4012 : 288 : get_printer ()->set_token_printer (&m_builder.get_token_printer ());
4013 : :
4014 : : /* Update the builder to use the new printer. */
4015 : 288 : m_builder.set_printer (*get_printer ());
4016 : 288 : }
4017 : :
4018 : 482 : void on_begin_group () final override
4019 : : {
4020 : : /* No-op, */
4021 : 482 : }
4022 : 482 : void on_end_group () override
4023 : : {
4024 : 482 : m_builder.end_group ();
4025 : 482 : }
4026 : : void
4027 : 601 : on_report_diagnostic (const diagnostic_info &diagnostic,
4028 : : enum kind orig_diag_kind) final override
4029 : : {
4030 : 601 : DIAGNOSTICS_LOG_SCOPE_PRINTF0
4031 : : (get_logger (),
4032 : 601 : "diagnostics::sarif_sink::on_report_diagnostic");
4033 : 601 : m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer);
4034 : 601 : }
4035 : 4 : void on_diagram (const diagram &d) final override
4036 : : {
4037 : 4 : m_builder.emit_diagram (d);
4038 : 4 : }
4039 : 573 : void after_diagnostic (const diagnostic_info &) final override
4040 : : {
4041 : : /* No-op. */
4042 : 573 : }
4043 : :
4044 : : void
4045 : 1 : report_global_digraph (const lazily_created<digraphs::digraph> &ldg)
4046 : : final override
4047 : : {
4048 : 1 : m_builder.report_global_digraph (ldg);
4049 : 1 : }
4050 : :
4051 : : sarif_builder &get_builder () { return m_builder; }
4052 : :
4053 : 96 : size_t num_results () const { return m_builder.num_results (); }
4054 : 16 : sarif_result &get_result (size_t idx) { return m_builder.get_result (idx); }
4055 : :
4056 : : protected:
4057 : 288 : sarif_sink (context &dc,
4058 : : const line_maps *line_maps,
4059 : : std::unique_ptr<sarif_serialization_format> serialization_format,
4060 : : const sarif_generation_options &sarif_gen_opts)
4061 : 288 : : sink (dc),
4062 : 288 : m_builder (dc, *get_printer (), line_maps,
4063 : : std::move (serialization_format), sarif_gen_opts),
4064 : 288 : m_buffer (nullptr)
4065 : 288 : {}
4066 : :
4067 : : sarif_builder m_builder;
4068 : : sarif_sink_buffer *m_buffer;
4069 : : };
4070 : :
4071 : : class sarif_stream_sink : public sarif_sink
4072 : : {
4073 : : public:
4074 : 0 : sarif_stream_sink (context &dc,
4075 : : const line_maps *line_maps,
4076 : : std::unique_ptr<sarif_serialization_format> serialization_format,
4077 : : const sarif_generation_options &sarif_gen_opts,
4078 : : FILE *stream)
4079 : 0 : : sarif_sink (dc, line_maps,
4080 : : std::move (serialization_format), sarif_gen_opts),
4081 : 0 : m_stream (stream)
4082 : : {
4083 : 0 : }
4084 : 0 : ~sarif_stream_sink ()
4085 : 0 : {
4086 : 0 : m_builder.flush_to_file (m_stream);
4087 : 0 : }
4088 : 0 : void dump_kind (FILE *out) const override
4089 : : {
4090 : 0 : fprintf (out, "sarif_stream_sink");
4091 : 0 : }
4092 : 0 : bool machine_readable_stderr_p () const final override
4093 : : {
4094 : 0 : return m_stream == stderr;
4095 : : }
4096 : : private:
4097 : : FILE *m_stream;
4098 : : };
4099 : :
4100 : : class sarif_file_sink : public sarif_sink
4101 : : {
4102 : : public:
4103 : 112 : sarif_file_sink (context &dc,
4104 : : const line_maps *line_maps,
4105 : : std::unique_ptr<sarif_serialization_format> serialization_format,
4106 : : const sarif_generation_options &sarif_gen_opts,
4107 : : output_file output_file_)
4108 : 112 : : sarif_sink (dc, line_maps,
4109 : : std::move (serialization_format),
4110 : : sarif_gen_opts),
4111 : 112 : m_output_file (std::move (output_file_))
4112 : : {
4113 : 112 : gcc_assert (m_output_file.get_open_file ());
4114 : 112 : gcc_assert (m_output_file.get_filename ());
4115 : 112 : }
4116 : 224 : ~sarif_file_sink ()
4117 : 112 : {
4118 : 112 : m_builder.flush_to_file (m_output_file.get_open_file ());
4119 : 224 : }
4120 : 0 : void dump_kind (FILE *out) const override
4121 : : {
4122 : 0 : fprintf (out, "sarif_file_sink: %s",
4123 : : m_output_file.get_filename ());
4124 : 0 : }
4125 : 15 : bool machine_readable_stderr_p () const final override
4126 : : {
4127 : 15 : return false;
4128 : : }
4129 : :
4130 : : private:
4131 : : output_file m_output_file;
4132 : : };
4133 : :
4134 : : class unique_fd
4135 : : {
4136 : : public:
4137 : : unique_fd () : m_ival (-1) {}
4138 : 0 : explicit unique_fd (int ival) : m_ival (ival) {}
4139 : : unique_fd (const unique_fd &) = delete;
4140 : 0 : unique_fd (unique_fd &&other)
4141 : 0 : : m_ival (other.m_ival)
4142 : : {
4143 : 0 : other.m_ival = -1;
4144 : : }
4145 : 0 : ~unique_fd ()
4146 : : {
4147 : 0 : if (m_ival != -1)
4148 : 0 : close (m_ival);
4149 : 0 : }
4150 : : unique_fd &operator= (const unique_fd &other) = delete;
4151 : : unique_fd &operator= (unique_fd &&other)
4152 : : {
4153 : : if (m_ival != -1)
4154 : : close (m_ival);
4155 : : m_ival = other.m_ival;
4156 : : other.m_ival = -1;
4157 : : return *this;
4158 : : }
4159 : :
4160 : 0 : operator int () const { return m_ival; }
4161 : :
4162 : : private:
4163 : : int m_ival;
4164 : : };
4165 : :
4166 : : class sarif_socket_sink : public sarif_sink
4167 : : {
4168 : : public:
4169 : 0 : sarif_socket_sink (context &dc,
4170 : : const line_maps *line_maps,
4171 : : std::unique_ptr<sarif_serialization_format> serialization_format,
4172 : : const sarif_generation_options &sarif_gen_opts,
4173 : : unique_fd fd)
4174 : 0 : : sarif_sink (dc, line_maps,
4175 : : std::move (serialization_format),
4176 : : sarif_gen_opts),
4177 : 0 : m_fd (std::move (fd))
4178 : : {
4179 : 0 : }
4180 : 0 : void dump_kind (FILE *out) const override
4181 : : {
4182 : 0 : fprintf (out, "sarif_socket_sink: fd=%i", int (m_fd));
4183 : 0 : }
4184 : 0 : bool machine_readable_stderr_p () const final override
4185 : : {
4186 : 0 : return false;
4187 : : }
4188 : :
4189 : : /* Rather than appending it to the results array, instead
4190 : : send it to the output socket as a JSON-RPC 2.0 notification. */
4191 : 0 : void on_end_group () final override
4192 : : {
4193 : : // TODO: what about buffering?
4194 : :
4195 : 0 : std::unique_ptr<sarif_result> result = m_builder.take_current_result ();
4196 : 0 : if (!result)
4197 : 0 : return;
4198 : :
4199 : 0 : auto notification = std::make_unique<json::object> ();
4200 : 0 : notification->set_string ("jsonrpc", "2.0");
4201 : 0 : notification->set_string ("method", "OnSarifResult");
4202 : 0 : {
4203 : 0 : auto params = std::make_unique<json::object> ();
4204 : 0 : params->set ("result", std::move (result));
4205 : 0 : notification->set ("params", std::move (params));
4206 : 0 : }
4207 : :
4208 : 0 : send_rpc_notification (*notification);
4209 : 0 : }
4210 : :
4211 : : private:
4212 : : void
4213 : 0 : send_rpc_notification (const json::object ¬ification)
4214 : : {
4215 : 0 : DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
4216 : 0 : "sarif_socket_sink::send_rpc_notification");
4217 : 0 : const bool formatted = false;
4218 : 0 : pretty_printer pp_content;
4219 : 0 : notification.print (&pp_content, formatted);
4220 : 0 : size_t content_length = strlen (pp_formatted_text (&pp_content));
4221 : :
4222 : 0 : pretty_printer pp_header;
4223 : : #if __GNUC__ >= 10
4224 : 0 : # pragma GCC diagnostic push
4225 : 0 : # pragma GCC diagnostic ignored "-Wformat-diag"
4226 : : #endif
4227 : 0 : pp_printf (&pp_header, "Content-Length: %li\n\n", content_length);
4228 : : #if __GNUC__ >= 10
4229 : 0 : # pragma GCC diagnostic pop
4230 : : #endif
4231 : 0 : size_t header_length = strlen (pp_formatted_text (&pp_header));
4232 : :
4233 : 0 : size_t output_size = header_length + content_length;
4234 : 0 : char *buf = (char *)xmalloc (output_size);
4235 : 0 : memcpy (buf, pp_formatted_text (&pp_header), header_length);
4236 : 0 : memcpy (buf + header_length,
4237 : 0 : pp_formatted_text (&pp_content),
4238 : : content_length);
4239 : :
4240 : : /* TODO: should we attempt to handle partial writes here? */
4241 : 0 : write (m_fd, buf, output_size);
4242 : :
4243 : 0 : free (buf);
4244 : 0 : }
4245 : :
4246 : : unique_fd m_fd;
4247 : : };
4248 : :
4249 : : /* Print the start of an embedded link to PP, as per 3.11.6. */
4250 : :
4251 : : static void
4252 : 43 : sarif_begin_embedded_link (pretty_printer *pp)
4253 : : {
4254 : 0 : pp_character (pp, '[');
4255 : 17 : }
4256 : :
4257 : : /* Print the end of an embedded link to PP, as per 3.11.6. */
4258 : :
4259 : : static void
4260 : 43 : sarif_end_embedded_link (pretty_printer *pp,
4261 : : const char *url)
4262 : : {
4263 : 43 : pp_string (pp, "](");
4264 : : /* TODO: does the URI need escaping?
4265 : : See https://github.com/oasis-tcs/sarif-spec/issues/657 */
4266 : 43 : pp_string (pp, url);
4267 : 43 : pp_character (pp, ')');
4268 : 43 : }
4269 : :
4270 : : /* class sarif_token_printer : public token_printer. */
4271 : :
4272 : : /* Implementation of pretty_printer::token_printer for SARIF output.
4273 : : Emit URLs as per 3.11.6 ("Messages with embedded links"). */
4274 : :
4275 : : void
4276 : 791 : sarif_builder::sarif_token_printer::print_tokens (pretty_printer *pp,
4277 : : const pp_token_list &tokens)
4278 : : {
4279 : : /* Convert to text, possibly with colorization, URLs, etc. */
4280 : 791 : label_text current_url;
4281 : 4213 : for (auto iter = tokens.m_first; iter; iter = iter->m_next)
4282 : 3422 : switch (iter->m_kind)
4283 : : {
4284 : 0 : default:
4285 : 0 : gcc_unreachable ();
4286 : :
4287 : 1894 : case pp_token::kind::text:
4288 : 1894 : {
4289 : 1894 : const pp_token_text *sub = as_a <const pp_token_text *> (iter);
4290 : 1894 : const char * const str = sub->m_value.get ();
4291 : 1894 : if (current_url.get ())
4292 : : {
4293 : : /* Write iter->m_value, but escaping any
4294 : : escaped link characters as per 3.11.6. */
4295 : 296 : for (const char *ptr = str; *ptr; ptr++)
4296 : : {
4297 : 270 : const char ch = *ptr;
4298 : 270 : switch (ch)
4299 : : {
4300 : 230 : default:
4301 : 230 : pp_character (pp, ch);
4302 : 230 : break;
4303 : 40 : case '\\':
4304 : 40 : case '[':
4305 : 40 : case ']':
4306 : 40 : pp_character (pp, '\\');
4307 : 40 : pp_character (pp, ch);
4308 : 40 : break;
4309 : : }
4310 : : }
4311 : : }
4312 : : else
4313 : : /* TODO: is other escaping needed? (e.g. of '[')
4314 : : See https://github.com/oasis-tcs/sarif-spec/issues/658 */
4315 : 1868 : pp_string (pp, str);
4316 : : }
4317 : : break;
4318 : :
4319 : : case pp_token::kind::begin_color:
4320 : : case pp_token::kind::end_color:
4321 : : /* These are no-ops. */
4322 : : break;
4323 : :
4324 : 700 : case pp_token::kind::begin_quote:
4325 : 700 : pp_begin_quote (pp, pp_show_color (pp));
4326 : 700 : break;
4327 : 658 : case pp_token::kind::end_quote:
4328 : 658 : pp_end_quote (pp, pp_show_color (pp));
4329 : 658 : break;
4330 : :
4331 : : /* Emit URLs as per 3.11.6 ("Messages with embedded links"). */
4332 : 26 : case pp_token::kind::begin_url:
4333 : 26 : {
4334 : 26 : pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter);
4335 : 26 : sarif_begin_embedded_link (pp);
4336 : 26 : current_url = std::move (sub->m_value);
4337 : : }
4338 : 26 : break;
4339 : 26 : case pp_token::kind::end_url:
4340 : 26 : gcc_assert (current_url.get ());
4341 : 26 : sarif_end_embedded_link (pp, current_url.get ());
4342 : 26 : current_url = label_text::borrow (nullptr);
4343 : 26 : break;
4344 : :
4345 : 114 : case pp_token::kind::event_id:
4346 : 114 : {
4347 : 114 : pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);
4348 : 114 : gcc_assert (sub->m_event_id.known_p ());
4349 : 114 : const sarif_code_flow *code_flow
4350 : 114 : = m_builder.get_code_flow_for_event_ids ();
4351 : 114 : label_text url = make_sarif_url_for_event (code_flow,
4352 : 114 : sub->m_event_id);
4353 : 114 : if (url.get ())
4354 : 17 : sarif_begin_embedded_link (pp);
4355 : 114 : pp_character (pp, '(');
4356 : 114 : pp_decimal_int (pp, sub->m_event_id.one_based ());
4357 : 114 : pp_character (pp, ')');
4358 : 114 : if (url.get ())
4359 : 17 : sarif_end_embedded_link (pp, url.get ());
4360 : 114 : }
4361 : 114 : break;
4362 : : }
4363 : 791 : }
4364 : :
4365 : : /* Populate CONTEXT in preparation for SARIF output (either to stderr, or
4366 : : to a file).
4367 : : Return a reference to *FMT. */
4368 : :
4369 : : static sink &
4370 : 266 : init_sarif_sink (context &dc,
4371 : : std::unique_ptr<sarif_sink> fmt)
4372 : : {
4373 : 266 : gcc_assert (fmt);
4374 : 266 : sink &out = *fmt;
4375 : :
4376 : 266 : fmt->update_printer ();
4377 : :
4378 : 266 : dc.set_sink (std::move (fmt));
4379 : :
4380 : 266 : return out;
4381 : : }
4382 : :
4383 : : /* Populate DC in preparation for SARIF output to stderr.
4384 : : Return a reference to the new sink. */
4385 : :
4386 : : sink &
4387 : 0 : init_sarif_stderr (context &dc,
4388 : : const line_maps *line_maps,
4389 : : bool formatted)
4390 : : {
4391 : 0 : gcc_assert (line_maps);
4392 : 0 : const sarif_generation_options sarif_gen_opts;
4393 : 0 : auto serialization
4394 : 0 : = std::make_unique<sarif_serialization_format_json> (formatted);
4395 : 0 : return init_sarif_sink
4396 : 0 : (dc,
4397 : 0 : std::make_unique<sarif_stream_sink> (dc,
4398 : : line_maps,
4399 : : std::move (serialization),
4400 : : sarif_gen_opts,
4401 : 0 : stderr));
4402 : 0 : }
4403 : :
4404 : : /* Attempt to open "BASE_FILE_NAME""EXTENSION" for writing.
4405 : : Return a non-null output_file,
4406 : : or return a null output_file and complain to DC
4407 : : using LINE_MAPS. */
4408 : :
4409 : : output_file
4410 : 110 : output_file::try_to_open (context &dc,
4411 : : line_maps *line_maps,
4412 : : const char *base_file_name,
4413 : : const char *extension,
4414 : : bool is_binary)
4415 : : {
4416 : 110 : gcc_assert (extension);
4417 : 110 : gcc_assert (extension[0] == '.');
4418 : :
4419 : 110 : if (!base_file_name)
4420 : : {
4421 : 0 : rich_location richloc (line_maps, UNKNOWN_LOCATION);
4422 : 0 : dc.emit_diagnostic_with_group
4423 : 0 : (kind::error, richloc, nullptr, 0,
4424 : : "unable to determine filename for SARIF output");
4425 : 0 : return output_file ();
4426 : 0 : }
4427 : :
4428 : 110 : label_text filename = label_text::take (concat (base_file_name,
4429 : : extension,
4430 : 110 : nullptr));
4431 : 220 : FILE *outf = fopen (filename.get (), is_binary ? "wb" : "w");
4432 : 110 : if (!outf)
4433 : : {
4434 : 0 : rich_location richloc (line_maps, UNKNOWN_LOCATION);
4435 : 0 : dc.emit_diagnostic_with_group
4436 : 0 : (kind::error, richloc, nullptr, 0,
4437 : : "unable to open %qs for diagnostic output: %m",
4438 : : filename.get ());
4439 : 0 : return output_file ();
4440 : 0 : }
4441 : 110 : return output_file (outf, true, std::move (filename));
4442 : 110 : }
4443 : :
4444 : : /* Attempt to open BASE_FILE_NAME.sarif for writing JSON.
4445 : : Return a non-null output_file,
4446 : : or return a null output_file and complain to DC
4447 : : using LINE_MAPS. */
4448 : :
4449 : : output_file
4450 : 110 : open_sarif_output_file (context &dc,
4451 : : line_maps *line_maps,
4452 : : const char *base_file_name,
4453 : : enum sarif_serialization_kind serialization_kind)
4454 : : {
4455 : 110 : const char *suffix;
4456 : 110 : bool is_binary;
4457 : 110 : switch (serialization_kind)
4458 : : {
4459 : 0 : default:
4460 : 0 : gcc_unreachable ();
4461 : 110 : case sarif_serialization_kind::json:
4462 : 110 : suffix = ".sarif";
4463 : 110 : is_binary = false;
4464 : 110 : break;
4465 : : }
4466 : :
4467 : 110 : return output_file::try_to_open (dc,
4468 : : line_maps,
4469 : : base_file_name,
4470 : : suffix,
4471 : 110 : is_binary);
4472 : : }
4473 : :
4474 : : /* Populate DC in preparation for SARIF output to a file named
4475 : : BASE_FILE_NAME.sarif.
4476 : : Return a reference to the new sink. */
4477 : :
4478 : : sink &
4479 : 90 : init_sarif_file (context &dc,
4480 : : line_maps *line_maps,
4481 : : bool formatted,
4482 : : const char *base_file_name)
4483 : : {
4484 : 90 : gcc_assert (line_maps);
4485 : :
4486 : 90 : output_file output_file_
4487 : : = open_sarif_output_file (dc,
4488 : : line_maps,
4489 : : base_file_name,
4490 : 90 : sarif_serialization_kind::json);
4491 : 90 : auto serialization
4492 : 90 : = std::make_unique<sarif_serialization_format_json> (formatted);
4493 : :
4494 : 90 : const sarif_generation_options sarif_gen_opts;
4495 : 90 : return init_sarif_sink
4496 : 90 : (dc,
4497 : 90 : std::make_unique<sarif_file_sink> (dc,
4498 : : line_maps,
4499 : : std::move (serialization),
4500 : : sarif_gen_opts,
4501 : 90 : std::move (output_file_)));
4502 : 90 : }
4503 : :
4504 : : /* Populate DC in preparation for SARIF output to STREAM.
4505 : : Return a reference to the new sink. */
4506 : :
4507 : : sink &
4508 : 0 : init_sarif_stream (context &dc,
4509 : : const line_maps *line_maps,
4510 : : bool formatted,
4511 : : FILE *stream)
4512 : : {
4513 : 0 : gcc_assert (line_maps);
4514 : 0 : const sarif_generation_options sarif_gen_opts;
4515 : 0 : auto serialization
4516 : 0 : = std::make_unique<sarif_serialization_format_json> (formatted);
4517 : 0 : return init_sarif_sink
4518 : 0 : (dc,
4519 : 0 : std::make_unique<sarif_stream_sink> (dc,
4520 : : line_maps,
4521 : : std::move (serialization),
4522 : : sarif_gen_opts,
4523 : 0 : stream));
4524 : 0 : }
4525 : :
4526 : : std::unique_ptr<sink>
4527 : 22 : make_sarif_sink (context &dc,
4528 : : const line_maps &line_maps,
4529 : : std::unique_ptr<sarif_serialization_format> serialization,
4530 : : const sarif_generation_options &sarif_gen_opts,
4531 : : output_file output_file_)
4532 : : {
4533 : 22 : auto sink
4534 : : = std::make_unique<sarif_file_sink> (dc,
4535 : 44 : &line_maps,
4536 : : std::move (serialization),
4537 : : sarif_gen_opts,
4538 : 22 : std::move (output_file_));
4539 : 22 : sink->update_printer ();
4540 : 22 : return sink;
4541 : 22 : }
4542 : :
4543 : : // struct sarif_generation_options
4544 : :
4545 : 349 : sarif_generation_options::sarif_generation_options ()
4546 : 349 : : m_version (sarif_version::v2_1_0),
4547 : 349 : m_state_graph (false)
4548 : : {
4549 : 349 : }
4550 : :
4551 : : static const char *
4552 : 0 : get_dump_string_for_sarif_version (enum sarif_version version)
4553 : : {
4554 : 0 : switch (version)
4555 : : {
4556 : 0 : default:
4557 : 0 : gcc_unreachable ();
4558 : : case sarif_version::v2_1_0:
4559 : : return "v2_1_0";
4560 : 0 : case sarif_version::v2_2_prerelease_2024_08_08:
4561 : 0 : return "v2_2_prerelease_2024_08_08";
4562 : : }
4563 : : }
4564 : :
4565 : : void
4566 : 0 : sarif_generation_options::dump (FILE *outfile, int indent) const
4567 : : {
4568 : 0 : dumping::emit_string_field (outfile, indent,
4569 : : "m_version",
4570 : 0 : get_dump_string_for_sarif_version (m_version));
4571 : 0 : DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_state_graph);
4572 : 0 : }
4573 : :
4574 : : void
4575 : 289298 : maybe_open_sarif_sink_for_socket (context &dc)
4576 : : {
4577 : 289298 : gcc_assert (line_table);
4578 : :
4579 : 289298 : const char * const env_var_name = "EXPERIMENTAL_SARIF_SOCKET";
4580 : 289298 : const char * const socket_name = getenv (env_var_name);
4581 : 289298 : if (!socket_name)
4582 : 289298 : return;
4583 : :
4584 : 0 : unique_fd sfd (socket (AF_UNIX, SOCK_STREAM, 0));
4585 : 0 : if (sfd == -1)
4586 : 0 : fatal_error (UNKNOWN_LOCATION,
4587 : : "unable to create socket: %m");
4588 : :
4589 : 0 : struct sockaddr_un addr;
4590 : 0 : memset (&addr, 0, sizeof (addr));
4591 : 0 : addr.sun_family = AF_UNIX;
4592 : 0 : strncpy (addr.sun_path, socket_name, sizeof (addr.sun_path) - 1);
4593 : :
4594 : 0 : if (connect (sfd, (struct sockaddr *)&addr, sizeof (addr)) == -1)
4595 : 0 : fatal_error (UNKNOWN_LOCATION,
4596 : : "unable to connect to %qs: %m",
4597 : : socket_name);
4598 : :
4599 : : /* TODO: should there be a way to specify other key/value
4600 : : pairs here? (as per -fdiagnostics-add-output, but as an
4601 : : environment variable, perhaps). */
4602 : 0 : sarif_generation_options sarif_gen_opts;
4603 : 0 : sarif_gen_opts.m_version = sarif_version::v2_1_0;
4604 : :
4605 : 0 : auto sink_ = std::make_unique<sarif_socket_sink>
4606 : : (dc,
4607 : : line_table,
4608 : 0 : std::make_unique <sarif_serialization_format_json> (true),
4609 : : sarif_gen_opts,
4610 : 0 : std::move (sfd));
4611 : 0 : sink_->update_printer ();
4612 : 0 : dc.add_sink (std::move (sink_));
4613 : 0 : }
4614 : :
4615 : : #if CHECKING_P
4616 : :
4617 : : namespace selftest {
4618 : :
4619 : : using auto_fix_quotes = ::selftest::auto_fix_quotes;
4620 : : using line_table_case = ::selftest::line_table_case;
4621 : :
4622 : : static void
4623 : 4 : test_sarif_array_of_unique_1 ()
4624 : : {
4625 : 4 : sarif_array_of_unique<json::string> arr;
4626 : :
4627 : 4 : ASSERT_EQ (arr.length (), 0);
4628 : :
4629 : 4 : {
4630 : 4 : size_t idx = arr.append_uniquely (std::make_unique<json::string> ("foo"));
4631 : 4 : ASSERT_EQ (idx, 0);
4632 : 4 : ASSERT_EQ (arr.length (), 1);
4633 : : }
4634 : 4 : {
4635 : 4 : size_t idx = arr.append_uniquely (std::make_unique<json::string> ("bar"));
4636 : 4 : ASSERT_EQ (idx, 1);
4637 : 4 : ASSERT_EQ (arr.length (), 2);
4638 : : }
4639 : :
4640 : : /* Try adding them again, should be idempotent. */
4641 : 4 : {
4642 : 4 : size_t idx = arr.append_uniquely (std::make_unique<json::string> ("foo"));
4643 : 4 : ASSERT_EQ (idx, 0);
4644 : 4 : ASSERT_EQ (arr.length (), 2);
4645 : : }
4646 : 4 : {
4647 : 4 : size_t idx = arr.append_uniquely (std::make_unique<json::string> ("bar"));
4648 : 4 : ASSERT_EQ (idx, 1);
4649 : 4 : ASSERT_EQ (arr.length (), 2);
4650 : : }
4651 : 4 : }
4652 : :
4653 : : static void
4654 : 4 : test_sarif_array_of_unique_2 ()
4655 : : {
4656 : 4 : sarif_array_of_unique<json::object> arr;
4657 : :
4658 : 4 : ASSERT_EQ (arr.length (), 0);
4659 : :
4660 : 4 : {
4661 : 4 : auto obj0 = std::make_unique<json::object> ();
4662 : 4 : size_t idx = arr.append_uniquely (std::move (obj0));
4663 : 4 : ASSERT_EQ (idx, 0);
4664 : 4 : ASSERT_EQ (arr.length (), 1);
4665 : :
4666 : : // Attempting to add another empty objects should be idempotent.
4667 : 4 : idx = arr.append_uniquely (std::make_unique<json::object> ());
4668 : 4 : ASSERT_EQ (idx, 0);
4669 : 4 : ASSERT_EQ (arr.length (), 1);
4670 : 4 : }
4671 : 4 : {
4672 : 4 : auto obj1 = std::make_unique<json::object> ();
4673 : 4 : obj1->set_string ("foo", "bar");
4674 : 4 : size_t idx = arr.append_uniquely (std::move (obj1));
4675 : 4 : ASSERT_EQ (idx, 1);
4676 : 4 : ASSERT_EQ (arr.length (), 2);
4677 : :
4678 : : // Attempting to add an equivalent object should be idempotent.
4679 : 4 : auto other = std::make_unique<json::object> ();
4680 : 4 : other->set_string ("foo", "bar");
4681 : 4 : idx = arr.append_uniquely (std::move (other));
4682 : 4 : ASSERT_EQ (idx, 1);
4683 : 4 : ASSERT_EQ (arr.length (), 2);
4684 : 4 : }
4685 : :
4686 : : // Verify behavior of add_explicit_index_values.
4687 : 4 : arr.add_explicit_index_values ();
4688 : 4 : ASSERT_JSON_INT_PROPERTY_EQ (arr[0], "index", 0);
4689 : 4 : ASSERT_JSON_INT_PROPERTY_EQ (arr[1], "index", 1);
4690 : 4 : }
4691 : :
4692 : : /* A subclass of sarif_sink for writing selftests.
4693 : : The JSON output is cached internally, rather than written
4694 : : out to a file. */
4695 : :
4696 : 352 : class test_sarif_diagnostic_context : public test_context
4697 : : {
4698 : : public:
4699 : 176 : test_sarif_diagnostic_context (const char *main_input_filename,
4700 : : const sarif_generation_options &sarif_gen_opts)
4701 : 176 : {
4702 : 176 : auto sink_ = std::make_unique<sarif_buffered_sink> (*this,
4703 : : line_table,
4704 : 352 : true,
4705 : 176 : sarif_gen_opts);
4706 : 176 : m_sink = sink_.get (); // borrowed
4707 : 176 : init_sarif_sink (*this, std::move (sink_));
4708 : 176 : m_sink->set_main_input_filename (main_input_filename);
4709 : 176 : }
4710 : :
4711 : 168 : std::unique_ptr<sarif_log> flush_to_object ()
4712 : : {
4713 : 336 : return m_sink->flush_to_object ();
4714 : : }
4715 : :
4716 : 96 : size_t num_results () const { return m_sink->num_results (); }
4717 : 32 : sarif_result &get_result (size_t idx) { return m_sink->get_result (idx); }
4718 : :
4719 : : private:
4720 : : class sarif_buffered_sink : public sarif_sink
4721 : : {
4722 : : public:
4723 : 176 : sarif_buffered_sink (context &dc,
4724 : : const line_maps *line_maps,
4725 : : bool formatted,
4726 : : const sarif_generation_options &sarif_gen_opts)
4727 : 176 : : sarif_sink (dc, line_maps,
4728 : 176 : std::make_unique<sarif_serialization_format_json> (formatted),
4729 : 176 : sarif_gen_opts)
4730 : : {
4731 : 176 : }
4732 : 0 : void dump_kind (FILE *out) const final override
4733 : : {
4734 : 0 : fprintf (out, "sarif_buffered_sink");
4735 : 0 : }
4736 : 0 : bool machine_readable_stderr_p () const final override
4737 : : {
4738 : 0 : return false;
4739 : : }
4740 : 168 : std::unique_ptr<sarif_log> flush_to_object ()
4741 : : {
4742 : 168 : return m_builder.flush_to_object ();
4743 : : }
4744 : : };
4745 : :
4746 : : sarif_buffered_sink *m_sink; // borrowed
4747 : : };
4748 : :
4749 : : /* Test making a sarif_location for a complex rich_location
4750 : : with labels and escape-on-output. */
4751 : :
4752 : : static void
4753 : 192 : test_make_location_object (const sarif_generation_options &sarif_gen_opts,
4754 : : const ::selftest::line_table_case &case_)
4755 : : {
4756 : 192 : source_printing_fixture_one_liner_utf8 f (case_);
4757 : 192 : location_t line_end = linemap_position_for_column (line_table, 31);
4758 : :
4759 : : /* Don't attempt to run the tests if column data might be unavailable. */
4760 : 192 : if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
4761 : 64 : return;
4762 : :
4763 : 128 : test_context dc;
4764 : 128 : pretty_printer pp;
4765 : 128 : sarif_builder builder
4766 : : (dc, pp, line_table,
4767 : 128 : std::make_unique<sarif_serialization_format_json> (true),
4768 : 128 : sarif_gen_opts);
4769 : :
4770 : : /* These "columns" are byte offsets, whereas later on the columns
4771 : : in the generated SARIF use sarif_builder::get_sarif_column and
4772 : : thus respect tabs, encoding. */
4773 : 128 : const location_t foo
4774 : 128 : = make_location (linemap_position_for_column (line_table, 1),
4775 : : linemap_position_for_column (line_table, 1),
4776 : : linemap_position_for_column (line_table, 8));
4777 : 128 : const location_t bar
4778 : 128 : = make_location (linemap_position_for_column (line_table, 12),
4779 : : linemap_position_for_column (line_table, 12),
4780 : : linemap_position_for_column (line_table, 17));
4781 : 128 : const location_t field
4782 : 128 : = make_location (linemap_position_for_column (line_table, 19),
4783 : : linemap_position_for_column (line_table, 19),
4784 : : linemap_position_for_column (line_table, 30));
4785 : :
4786 : 128 : text_range_label label0 ("label0");
4787 : 128 : text_range_label label1 ("label1");
4788 : 128 : text_range_label label2 ("label2");
4789 : :
4790 : 128 : rich_location richloc (line_table, foo, &label0, nullptr);
4791 : 128 : richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
4792 : 128 : richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
4793 : 128 : richloc.set_escape_on_output (true);
4794 : :
4795 : 128 : sarif_result result (0);
4796 : :
4797 : 128 : std::unique_ptr<sarif_location> location_obj
4798 : : = builder.make_location_object
4799 : 128 : (&result, richloc, logical_locations::key (),
4800 : 128 : diagnostic_artifact_role::analysis_target);
4801 : 128 : ASSERT_NE (location_obj, nullptr);
4802 : :
4803 : 128 : auto physical_location
4804 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (location_obj.get (),
4805 : : "physicalLocation");
4806 : 128 : {
4807 : 128 : auto region
4808 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (physical_location, "region");
4809 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (region, "startLine", 1);
4810 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (region, "startColumn", 1);
4811 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (region, "endColumn", 7);
4812 : : }
4813 : 128 : {
4814 : 128 : auto context_region
4815 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (physical_location,
4816 : : "contextRegion");
4817 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (context_region, "startLine", 1);
4818 : :
4819 : 128 : {
4820 : 128 : auto snippet
4821 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (context_region, "snippet");
4822 : :
4823 : : /* We expect the snippet's "text" to be a copy of the content. */
4824 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (snippet, "text", f.m_content);
4825 : :
4826 : : /* We expect the snippet to have a "rendered" whose "text" has a
4827 : : pure ASCII escaped copy of the line (with labels, etc). */
4828 : 128 : {
4829 : 128 : auto rendered
4830 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (snippet, "rendered");
4831 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ
4832 : : (rendered, "text",
4833 : : "1 | <U+1F602>_foo = <U+03C0>_bar.<U+1F602>_field<U+03C0>;\n"
4834 : : " | ^~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~\n"
4835 : : " | | | |\n"
4836 : : " | label0 label1 label2\n");
4837 : : }
4838 : : }
4839 : : }
4840 : 128 : auto annotations
4841 : 128 : = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (location_obj.get (),
4842 : : "annotations");
4843 : 128 : ASSERT_EQ (annotations->size (), 3);
4844 : 128 : {
4845 : 128 : {
4846 : 128 : auto a0 = (*annotations)[0];
4847 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a0, "startLine", 1);
4848 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a0, "startColumn", 1);
4849 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a0, "endColumn", 7);
4850 : 128 : auto message
4851 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (a0, "message");
4852 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (message, "text", "label0");
4853 : : }
4854 : 128 : {
4855 : 128 : auto a1 = (*annotations)[1];
4856 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a1, "startLine", 1);
4857 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a1, "startColumn", 10);
4858 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a1, "endColumn", 15);
4859 : 128 : auto message
4860 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (a1, "message");
4861 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (message, "text", "label1");
4862 : : }
4863 : 128 : {
4864 : 128 : auto a2 = (*annotations)[2];
4865 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a2, "startLine", 1);
4866 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a2, "startColumn", 16);
4867 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (a2, "endColumn", 25);
4868 : 128 : auto message
4869 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (a2, "message");
4870 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (message, "text", "label2");
4871 : : }
4872 : : }
4873 : 192 : }
4874 : :
4875 : : /* Test of reporting a diagnostic at UNKNOWN_LOCATION to a
4876 : : diagnostics::context and examining the generated sarif_log.
4877 : : Verify various basic properties. */
4878 : :
4879 : : static void
4880 : 8 : test_simple_log (const sarif_generation_options &sarif_gen_opts)
4881 : : {
4882 : 8 : test_sarif_diagnostic_context dc ("MAIN_INPUT_FILENAME", sarif_gen_opts);
4883 : :
4884 : 8 : rich_location richloc (line_table, UNKNOWN_LOCATION);
4885 : 8 : dc.report (kind::error, richloc, nullptr, 0, "this is a test: %i", 42);
4886 : :
4887 : 8 : auto log_ptr = dc.flush_to_object ();
4888 : :
4889 : : // 3.13 sarifLog:
4890 : 8 : auto log = log_ptr.get ();
4891 : 8 : const enum sarif_version version = sarif_gen_opts.m_version;
4892 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (log, "$schema",
4893 : : sarif_version_to_url (version));
4894 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (log, "version",
4895 : : sarif_version_to_property (version));
4896 : :
4897 : 8 : auto runs = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (log, "runs"); // 3.13.4
4898 : 8 : ASSERT_EQ (runs->size (), 1);
4899 : :
4900 : : // 3.14 "run" object:
4901 : 8 : auto run = (*runs)[0];
4902 : :
4903 : 8 : {
4904 : : // 3.14.6:
4905 : 8 : auto tool = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (run, "tool");
4906 : :
4907 : 8 : EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (tool, "driver"); // 3.18.2
4908 : : }
4909 : :
4910 : 8 : {
4911 : : // 3.14.11
4912 : 8 : auto invocations
4913 : 8 : = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "invocations");
4914 : 8 : ASSERT_EQ (invocations->size (), 1);
4915 : :
4916 : 8 : {
4917 : : // 3.20 "invocation" object:
4918 : 8 : auto invocation = (*invocations)[0];
4919 : :
4920 : : // 3.20.3 arguments property
4921 : :
4922 : : // 3.20.7 startTimeUtc property
4923 : 8 : EXPECT_JSON_OBJECT_WITH_STRING_PROPERTY (invocation, "startTimeUtc");
4924 : :
4925 : : // 3.20.8 endTimeUtc property
4926 : 8 : EXPECT_JSON_OBJECT_WITH_STRING_PROPERTY (invocation, "endTimeUtc");
4927 : :
4928 : : // 3.20.19 workingDirectory property
4929 : 8 : {
4930 : 8 : auto wd_obj
4931 : 8 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (invocation,
4932 : : "workingDirectory");
4933 : 8 : EXPECT_JSON_OBJECT_WITH_STRING_PROPERTY (wd_obj, "uri");
4934 : : }
4935 : :
4936 : : // 3.20.21 toolExecutionNotifications property
4937 : 8 : auto notifications
4938 : 8 : = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY
4939 : : (invocation, "toolExecutionNotifications");
4940 : 8 : ASSERT_EQ (notifications->size (), 0);
4941 : : }
4942 : : }
4943 : :
4944 : 8 : {
4945 : : // 3.14.15:
4946 : 8 : auto artifacts = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "artifacts");
4947 : 8 : ASSERT_EQ (artifacts->size (), 1);
4948 : :
4949 : 8 : {
4950 : : // 3.24 "artifact" object:
4951 : 8 : auto artifact = (*artifacts)[0];
4952 : :
4953 : : // 3.24.2:
4954 : 8 : auto location
4955 : 8 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (artifact, "location");
4956 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (location, "uri", "MAIN_INPUT_FILENAME");
4957 : :
4958 : : // 3.24.6:
4959 : 8 : auto roles = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (artifact, "roles");
4960 : 8 : ASSERT_EQ (roles->size (), 1);
4961 : 8 : {
4962 : 8 : auto role = (*roles)[0];
4963 : 8 : ASSERT_JSON_STRING_EQ (role, "analysisTarget");
4964 : : }
4965 : : }
4966 : : }
4967 : :
4968 : 8 : {
4969 : : // 3.14.23:
4970 : 8 : auto results = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "results");
4971 : 8 : ASSERT_EQ (results->size (), 1);
4972 : :
4973 : 8 : {
4974 : : // 3.27 "result" object:
4975 : 8 : auto result = (*results)[0];
4976 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (result, "ruleId", "error");
4977 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (result, "level", "error"); // 3.27.10
4978 : :
4979 : 8 : {
4980 : : // 3.27.11:
4981 : 8 : auto message
4982 : 8 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (result, "message");
4983 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (message, "text",
4984 : : "this is a test: 42");
4985 : : }
4986 : :
4987 : : // 3.27.12:
4988 : 8 : auto locations
4989 : 8 : = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (result, "locations");
4990 : 8 : ASSERT_EQ (locations->size (), 0);
4991 : : }
4992 : : }
4993 : 8 : }
4994 : :
4995 : : /* As above, but with a "real" location_t. */
4996 : :
4997 : : static void
4998 : 192 : test_simple_log_2 (const sarif_generation_options &sarif_gen_opts,
4999 : : const line_table_case &case_)
5000 : : {
5001 : 192 : auto_fix_quotes fix_quotes;
5002 : :
5003 : 192 : const char *const content
5004 : : /* 000000000111111
5005 : : 123456789012345. */
5006 : : = "unsinged int i;\n";
5007 : 192 : source_printing_fixture f (case_, content);
5008 : 192 : location_t line_end = linemap_position_for_column (line_table, 31);
5009 : :
5010 : : /* Don't attempt to run the tests if column data might be unavailable. */
5011 : 192 : if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
5012 : 64 : return;
5013 : :
5014 : 128 : test_sarif_diagnostic_context dc (f.get_filename (), sarif_gen_opts);
5015 : :
5016 : 128 : const location_t typo_loc
5017 : 128 : = make_location (linemap_position_for_column (line_table, 1),
5018 : : linemap_position_for_column (line_table, 1),
5019 : : linemap_position_for_column (line_table, 8));
5020 : :
5021 : 128 : rich_location richloc (line_table, typo_loc);
5022 : 128 : dc.report (kind::error, richloc, nullptr, 0,
5023 : : "did you misspell %qs again?",
5024 : : "unsigned");
5025 : :
5026 : 128 : auto log_ptr = dc.flush_to_object ();
5027 : :
5028 : : // 3.13 sarifLog:
5029 : 128 : auto log = log_ptr.get ();
5030 : :
5031 : 128 : auto runs = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (log, "runs"); // 3.13.4
5032 : 128 : ASSERT_EQ (runs->size (), 1);
5033 : :
5034 : : // 3.14 "run" object:
5035 : 128 : auto run = (*runs)[0];
5036 : :
5037 : 128 : {
5038 : : // 3.14.23:
5039 : 128 : auto results = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "results");
5040 : 128 : ASSERT_EQ (results->size (), 1);
5041 : :
5042 : 128 : {
5043 : : // 3.27 "result" object:
5044 : 128 : auto result = (*results)[0];
5045 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (result, "ruleId", "error");
5046 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (result, "level", "error"); // 3.27.10
5047 : :
5048 : 128 : {
5049 : : // 3.27.11:
5050 : 128 : auto message
5051 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (result, "message");
5052 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (message, "text",
5053 : : "did you misspell `unsigned' again?");
5054 : : }
5055 : :
5056 : : // 3.27.12:
5057 : 128 : auto locations
5058 : 128 : = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (result, "locations");
5059 : 128 : ASSERT_EQ (locations->size (), 1);
5060 : :
5061 : 128 : {
5062 : : // 3.28 "location" object:
5063 : 128 : auto location = (*locations)[0];
5064 : :
5065 : 128 : auto physical_location
5066 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (location,
5067 : : "physicalLocation");
5068 : 128 : {
5069 : 128 : auto region
5070 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (physical_location,
5071 : : "region");
5072 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (region, "startLine", 1);
5073 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (region, "startColumn", 1);
5074 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (region, "endColumn", 9);
5075 : : }
5076 : 128 : {
5077 : 128 : auto context_region
5078 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (physical_location,
5079 : : "contextRegion");
5080 : 128 : ASSERT_JSON_INT_PROPERTY_EQ (context_region, "startLine", 1);
5081 : :
5082 : 128 : {
5083 : 128 : auto snippet
5084 : 128 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (context_region,
5085 : : "snippet");
5086 : :
5087 : : /* We expect the snippet's "text" to be a copy of the content. */
5088 : 128 : ASSERT_JSON_STRING_PROPERTY_EQ (snippet, "text", f.m_content);
5089 : : }
5090 : : }
5091 : : }
5092 : : }
5093 : : }
5094 : 192 : }
5095 : :
5096 : : /* Assuming that a single diagnostic has been emitted within
5097 : : LOG, get a json::object for the result object. */
5098 : :
5099 : : static const json::object *
5100 : 32 : get_result_from_log (const sarif_log *log)
5101 : : {
5102 : 32 : auto runs = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (log, "runs"); // 3.13.4
5103 : 32 : ASSERT_EQ (runs->size (), 1);
5104 : :
5105 : : // 3.14 "run" object:
5106 : 32 : auto run = (*runs)[0];
5107 : :
5108 : : // 3.14.23:
5109 : 32 : auto results = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "results");
5110 : 32 : ASSERT_EQ (results->size (), 1);
5111 : :
5112 : : // 3.27 "result" object:
5113 : 32 : auto result = (*results)[0];
5114 : 32 : return expect_json_object (SELFTEST_LOCATION, result);
5115 : : }
5116 : :
5117 : : static const json::object *
5118 : 16 : get_message_from_result (const sarif_result &result)
5119 : : {
5120 : : // 3.27.11:
5121 : 16 : auto message_obj
5122 : 16 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (&result, "message");
5123 : 16 : return message_obj;
5124 : : }
5125 : :
5126 : : /* Assuming that a single diagnostic has been emitted to
5127 : : DC, get a json::object for the messsage object within
5128 : : the result. */
5129 : :
5130 : : static const json::object *
5131 : 32 : get_message_from_log (const sarif_log *log)
5132 : : {
5133 : 32 : auto result_obj = get_result_from_log (log);
5134 : :
5135 : : // 3.27.11:
5136 : 32 : auto message_obj
5137 : 32 : = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (result_obj, "message");
5138 : 32 : return message_obj;
5139 : : }
5140 : :
5141 : : /* Tests of messages with embedded links; see SARIF v2.1.0 3.11.6. */
5142 : :
5143 : : static void
5144 : 8 : test_message_with_embedded_link (const sarif_generation_options &sarif_gen_opts)
5145 : : {
5146 : 8 : auto_fix_quotes fix_quotes;
5147 : 8 : {
5148 : 8 : test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
5149 : 8 : rich_location richloc (line_table, UNKNOWN_LOCATION);
5150 : 8 : dc.report (kind::error, richloc, nullptr, 0,
5151 : : "before %{text%} after",
5152 : : "http://example.com");
5153 : 8 : std::unique_ptr<sarif_log> log = dc.flush_to_object ();
5154 : :
5155 : 8 : auto message_obj = get_message_from_log (log.get ());
5156 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ
5157 : : (message_obj, "text",
5158 : : "before [text](http://example.com) after");
5159 : 8 : }
5160 : :
5161 : : /* Escaping in message text.
5162 : : This is "EXAMPLE 1" from 3.11.6. */
5163 : 8 : {
5164 : 8 : test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
5165 : 8 : rich_location richloc (line_table, UNKNOWN_LOCATION);
5166 : :
5167 : : /* Disable "unquoted sequence of 2 consecutive punctuation
5168 : : characters `]\' in format" warning. */
5169 : : #if __GNUC__ >= 10
5170 : 8 : # pragma GCC diagnostic push
5171 : 8 : # pragma GCC diagnostic ignored "-Wformat-diag"
5172 : : #endif
5173 : 8 : dc.report (kind::error, richloc, nullptr, 0,
5174 : : "Prohibited term used in %{para[0]\\spans[2]%}.",
5175 : : "1");
5176 : : #if __GNUC__ >= 10
5177 : 8 : # pragma GCC diagnostic pop
5178 : : #endif
5179 : :
5180 : 8 : std::unique_ptr<sarif_log> log = dc.flush_to_object ();
5181 : :
5182 : 8 : auto message_obj = get_message_from_log (log.get ());
5183 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ
5184 : : (message_obj, "text",
5185 : : "Prohibited term used in [para\\[0\\]\\\\spans\\[2\\]](1).");
5186 : : /* This isn't exactly what EXAMPLE 1 of the spec has; reported as
5187 : : https://github.com/oasis-tcs/sarif-spec/issues/656 */
5188 : 8 : }
5189 : :
5190 : : /* Urlifier. */
5191 : 8 : {
5192 : 8 : class test_urlifier : public urlifier
5193 : : {
5194 : : public:
5195 : : char *
5196 : 16 : get_url_for_quoted_text (const char *p, size_t sz) const final override
5197 : : {
5198 : 16 : if (!strncmp (p, "-foption", sz))
5199 : 8 : return xstrdup ("http://example.com");
5200 : : return nullptr;
5201 : : }
5202 : : };
5203 : :
5204 : 8 : test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
5205 : 8 : dc.push_owned_urlifier (std::make_unique<test_urlifier> ());
5206 : 8 : rich_location richloc (line_table, UNKNOWN_LOCATION);
5207 : 8 : dc.report (kind::error, richloc, nullptr, 0,
5208 : : "foo %<-foption%> %<unrecognized%> bar");
5209 : 8 : std::unique_ptr<sarif_log> log = dc.flush_to_object ();
5210 : :
5211 : 8 : auto message_obj = get_message_from_log (log.get ());
5212 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ
5213 : : (message_obj, "text",
5214 : : "foo `[-foption](http://example.com)' `unrecognized' bar");
5215 : 8 : }
5216 : 8 : }
5217 : :
5218 : : /* Verify that braces in messages get escaped, as per
5219 : : 3.11.5 ("Messages with placeholders"). */
5220 : :
5221 : : static void
5222 : 8 : test_message_with_braces (const sarif_generation_options &sarif_gen_opts)
5223 : : {
5224 : 8 : auto_fix_quotes fix_quotes;
5225 : 8 : {
5226 : 8 : test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
5227 : 8 : rich_location richloc (line_table, UNKNOWN_LOCATION);
5228 : 8 : dc.report (kind::error, richloc, nullptr, 0,
5229 : : "open brace: %qs close brace: %qs",
5230 : : "{", "}");
5231 : 8 : std::unique_ptr<sarif_log> log = dc.flush_to_object ();
5232 : :
5233 : 8 : auto message_obj = get_message_from_log (log.get ());
5234 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ
5235 : : (message_obj, "text",
5236 : : "open brace: `{{' close brace: `}}'");
5237 : 8 : }
5238 : 8 : }
5239 : :
5240 : : static void
5241 : 8 : test_buffering (const sarif_generation_options &sarif_gen_opts)
5242 : : {
5243 : 8 : test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
5244 : :
5245 : 8 : diagnostics::buffer buf_a (dc);
5246 : 8 : diagnostics::buffer buf_b (dc);
5247 : :
5248 : 8 : rich_location rich_loc (line_table, UNKNOWN_LOCATION);
5249 : :
5250 : 8 : ASSERT_EQ (dc.diagnostic_count (kind::error), 0);
5251 : 8 : ASSERT_EQ (buf_a.diagnostic_count (kind::error), 0);
5252 : 8 : ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
5253 : 8 : ASSERT_EQ (dc.num_results (), 0);
5254 : 8 : ASSERT_TRUE (buf_a.empty_p ());
5255 : 8 : ASSERT_TRUE (buf_b.empty_p ());
5256 : :
5257 : : /* Unbuffered diagnostic. */
5258 : 8 : {
5259 : 8 : dc.report (kind::error, rich_loc, nullptr, 0,
5260 : : "message 1");
5261 : :
5262 : 8 : ASSERT_EQ (dc.diagnostic_count (kind::error), 1);
5263 : 8 : ASSERT_EQ (buf_a.diagnostic_count (kind::error), 0);
5264 : 8 : ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
5265 : 8 : ASSERT_EQ (dc.num_results (), 1);
5266 : 8 : sarif_result &result_obj = dc.get_result (0);
5267 : 8 : auto message_obj = get_message_from_result (result_obj);
5268 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (message_obj, "text",
5269 : : "message 1");
5270 : 8 : ASSERT_TRUE (buf_a.empty_p ());
5271 : 8 : ASSERT_TRUE (buf_b.empty_p ());
5272 : : }
5273 : :
5274 : : /* Buffer diagnostic into buffer A. */
5275 : 8 : {
5276 : 8 : dc.set_diagnostic_buffer (&buf_a);
5277 : 8 : dc.report (kind::error, rich_loc, nullptr, 0,
5278 : : "message in buffer a");
5279 : 8 : ASSERT_EQ (dc.diagnostic_count (kind::error), 1);
5280 : 8 : ASSERT_EQ (buf_a.diagnostic_count (kind::error), 1);
5281 : 8 : ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
5282 : 8 : ASSERT_EQ (dc.num_results (), 1);
5283 : 8 : ASSERT_FALSE (buf_a.empty_p ());
5284 : 8 : ASSERT_TRUE (buf_b.empty_p ());
5285 : : }
5286 : :
5287 : : /* Buffer diagnostic into buffer B. */
5288 : 8 : {
5289 : 8 : dc.set_diagnostic_buffer (&buf_b);
5290 : 8 : dc.report (kind::error, rich_loc, nullptr, 0,
5291 : : "message in buffer b");
5292 : 8 : ASSERT_EQ (dc.diagnostic_count (kind::error), 1);
5293 : 8 : ASSERT_EQ (buf_a.diagnostic_count (kind::error), 1);
5294 : 8 : ASSERT_EQ (buf_b.diagnostic_count (kind::error), 1);
5295 : 8 : ASSERT_EQ (dc.num_results (), 1);
5296 : 8 : ASSERT_FALSE (buf_a.empty_p ());
5297 : 8 : ASSERT_FALSE (buf_b.empty_p ());
5298 : : }
5299 : :
5300 : : /* Flush buffer B to dc. */
5301 : 8 : {
5302 : 8 : dc.flush_diagnostic_buffer (buf_b);
5303 : 8 : ASSERT_EQ (dc.diagnostic_count (kind::error), 2);
5304 : 8 : ASSERT_EQ (buf_a.diagnostic_count (kind::error), 1);
5305 : 8 : ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
5306 : 8 : ASSERT_EQ (dc.num_results (), 2);
5307 : 8 : sarif_result &result_1_obj = dc.get_result (1);
5308 : 8 : auto message_1_obj = get_message_from_result (result_1_obj);
5309 : 8 : ASSERT_JSON_STRING_PROPERTY_EQ (message_1_obj, "text",
5310 : : "message in buffer b");
5311 : 8 : ASSERT_FALSE (buf_a.empty_p ());
5312 : 8 : ASSERT_TRUE (buf_b.empty_p ());
5313 : : }
5314 : :
5315 : : /* Clear buffer A. */
5316 : 8 : {
5317 : 8 : dc.clear_diagnostic_buffer (buf_a);
5318 : 8 : ASSERT_EQ (dc.diagnostic_count (kind::error), 2);
5319 : 8 : ASSERT_EQ (buf_a.diagnostic_count (kind::error), 0);
5320 : 8 : ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
5321 : 8 : ASSERT_EQ (dc.num_results (), 2);
5322 : 8 : ASSERT_TRUE (buf_a.empty_p ());
5323 : 8 : ASSERT_TRUE (buf_b.empty_p ());
5324 : : }
5325 : 8 : }
5326 : :
5327 : : template <class ...ArgTypes>
5328 : : static void
5329 : 208 : for_each_sarif_gen_option (void (*callback) (const sarif_generation_options &,
5330 : : ArgTypes ...),
5331 : : ArgTypes ...args)
5332 : : {
5333 : 208 : sarif_generation_options sarif_gen_opts;
5334 : 624 : for (int version_idx = 0;
5335 : 624 : version_idx < (int)sarif_version::num_versions;
5336 : : ++version_idx)
5337 : : {
5338 : 416 : sarif_gen_opts.m_version = static_cast<enum sarif_version> (version_idx);
5339 : :
5340 : 416 : callback (sarif_gen_opts, args...);
5341 : : }
5342 : 208 : }
5343 : :
5344 : : static void
5345 : 96 : run_line_table_case_tests_per_version (const line_table_case &case_)
5346 : : {
5347 : 96 : for_each_sarif_gen_option<const line_table_case &>
5348 : 96 : (test_make_location_object, case_);
5349 : :
5350 : 96 : for_each_sarif_gen_option<const line_table_case &>
5351 : 96 : (test_simple_log_2, case_);
5352 : 96 : }
5353 : :
5354 : : /* Run all of the selftests within this file. */
5355 : :
5356 : : void
5357 : 4 : sarif_sink_cc_tests ()
5358 : : {
5359 : 4 : test_sarif_array_of_unique_1 ();
5360 : 4 : test_sarif_array_of_unique_2 ();
5361 : :
5362 : 4 : for_each_sarif_gen_option (test_simple_log);
5363 : 4 : for_each_sarif_gen_option (test_message_with_embedded_link);
5364 : 4 : for_each_sarif_gen_option (test_message_with_braces);
5365 : 4 : for_each_sarif_gen_option (test_buffering);
5366 : :
5367 : : /* Run tests per (SARIF gen-option, line-table-case) pair. */
5368 : 4 : for_each_line_table_case (run_line_table_case_tests_per_version);
5369 : 4 : }
5370 : :
5371 : : } // namespace diagnostics::selftest
5372 : :
5373 : : #endif /* CHECKING_P */
5374 : :
5375 : : } // namespace diagnostics
|