LCOV - code coverage report
Current view: top level - gcc - diagnostic-format-sarif.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.5 % 1724 1594
Test Date: 2025-03-22 13:13:03 Functions: 89.0 % 145 129
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

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

Generated by: LCOV version 2.1-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.