LCOV - code coverage report
Current view: top level - gcc/diagnostics - sarif-sink.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.9 % 2166 1903
Test Date: 2026-02-28 14:20:25 Functions: 85.7 % 189 162
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.