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