LCOV - code coverage report
Current view: top level - gcc - opts-diagnostic.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 76.9 % 355 273
Test Date: 2025-06-21 16:26:05 Functions: 86.4 % 22 19
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Support for -fdiagnostics-add-output= and -fdiagnostics-set-output=.
       2                 :             :    Copyright (C) 2024-2025 Free Software Foundation, Inc.
       3                 :             : 
       4                 :             : This file is part of GCC.
       5                 :             : 
       6                 :             : GCC is free software; you can redistribute it and/or modify it under
       7                 :             : the terms of the GNU General Public License as published by the Free
       8                 :             : Software Foundation; either version 3, or (at your option) any later
       9                 :             : version.
      10                 :             : 
      11                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14                 :             : for more details.
      15                 :             : 
      16                 :             : You should have received a copy of the GNU General Public License
      17                 :             : along with GCC; see the file COPYING3.  If not see
      18                 :             : <http://www.gnu.org/licenses/>.  */
      19                 :             : 
      20                 :             : 
      21                 :             : /* This file implements the options -fdiagnostics-add-output=,
      22                 :             :    -fdiagnostics-set-output=, and their domain-specific language.  */
      23                 :             : 
      24                 :             : #include "config.h"
      25                 :             : #define INCLUDE_ARRAY
      26                 :             : #define INCLUDE_STRING
      27                 :             : #define INCLUDE_VECTOR
      28                 :             : #include "system.h"
      29                 :             : #include "coretypes.h"
      30                 :             : #include "version.h"
      31                 :             : #include "intl.h"
      32                 :             : #include "diagnostic.h"
      33                 :             : #include "diagnostic-color.h"
      34                 :             : #include "diagnostic-format.h"
      35                 :             : #include "diagnostic-format-html.h"
      36                 :             : #include "diagnostic-format-text.h"
      37                 :             : #include "diagnostic-format-sarif.h"
      38                 :             : #include "selftest.h"
      39                 :             : #include "selftest-diagnostic.h"
      40                 :             : #include "pretty-print-markup.h"
      41                 :             : #include "opts.h"
      42                 :             : #include "options.h"
      43                 :             : 
      44                 :             : /* A namespace for handling the DSL of the arguments of
      45                 :             :    -fdiagnostics-add-output= and -fdiagnostics-set-output=.  */
      46                 :             : 
      47                 :             : namespace gcc {
      48                 :             : namespace diagnostics_output_spec {
      49                 :             : 
      50                 :             : /* Decls.  */
      51                 :             : 
      52                 :             : struct context
      53                 :             : {
      54                 :             : public:
      55                 :          53 :   context (const gcc_options &opts,
      56                 :             :            diagnostic_context &dc,
      57                 :             :            line_maps *location_mgr,
      58                 :             :            location_t loc,
      59                 :             :            const char *option_name)
      60                 :          53 :   : m_opts (opts), m_dc (dc), m_location_mgr (location_mgr), m_loc (loc),
      61                 :          53 :     m_option_name (option_name)
      62                 :             :   {}
      63                 :             : 
      64                 :             :   void
      65                 :             :   report_error (const char *gmsgid, ...) const
      66                 :             :     ATTRIBUTE_GCC_DIAG(2,3);
      67                 :             : 
      68                 :             :   void
      69                 :             :   report_unknown_key (const char *unparsed_arg,
      70                 :             :                       const std::string &key,
      71                 :             :                       const std::string &scheme_name,
      72                 :             :                       auto_vec<const char *> &known_keys) const;
      73                 :             : 
      74                 :             :   void
      75                 :             :   report_missing_key (const char *unparsed_arg,
      76                 :             :                       const std::string &key,
      77                 :             :                       const std::string &scheme_name,
      78                 :             :                       const char *metavar) const;
      79                 :             : 
      80                 :             :   diagnostic_output_file
      81                 :             :   open_output_file (label_text &&filename) const;
      82                 :             : 
      83                 :             :   const gcc_options &m_opts;
      84                 :             :   diagnostic_context &m_dc;
      85                 :             :   line_maps *m_location_mgr;
      86                 :             :   location_t m_loc;
      87                 :             :   const char *m_option_name;
      88                 :             : };
      89                 :             : 
      90                 :          90 : struct scheme_name_and_params
      91                 :             : {
      92                 :             :   std::string m_scheme_name;
      93                 :             :   std::vector<std::pair<std::string, std::string>> m_kvs;
      94                 :             : };
      95                 :             : 
      96                 :             : static std::unique_ptr<scheme_name_and_params>
      97                 :             : parse (const context &ctxt, const char *unparsed_arg);
      98                 :             : 
      99                 :             : /* Class for parsing the arguments of -fdiagnostics-add-output= and
     100                 :             :    -fdiagnostics-set-output=, and making diagnostic_output_format
     101                 :             :    instances (or issuing errors).  */
     102                 :             : 
     103                 :          50 : class output_factory
     104                 :             : {
     105                 :             : public:
     106                 :             :   class scheme_handler
     107                 :             :   {
     108                 :             :   public:
     109                 :          75 :     scheme_handler (std::string scheme_name)
     110                 :          75 :     : m_scheme_name (std::move (scheme_name))
     111                 :             :     {}
     112                 :             :     virtual ~scheme_handler () {}
     113                 :             : 
     114                 :          45 :     const std::string &get_scheme_name () const { return m_scheme_name; }
     115                 :             : 
     116                 :             :     virtual std::unique_ptr<diagnostic_output_format>
     117                 :             :     make_sink (const context &ctxt,
     118                 :             :                const char *unparsed_arg,
     119                 :             :                const scheme_name_and_params &parsed_arg) const = 0;
     120                 :             : 
     121                 :             :   protected:
     122                 :             :     bool
     123                 :          29 :     parse_bool_value (const context &ctxt,
     124                 :             :                       const char *unparsed_arg,
     125                 :             :                       const std::string &key,
     126                 :             :                       const std::string &value,
     127                 :             :                       bool &out) const
     128                 :             :     {
     129                 :          29 :       if (value == "yes")
     130                 :             :         {
     131                 :          13 :           out = true;
     132                 :          13 :           return true;
     133                 :             :         }
     134                 :          16 :       else if (value == "no")
     135                 :             :         {
     136                 :          16 :           out = false;
     137                 :          16 :           return true;
     138                 :             :         }
     139                 :             :       else
     140                 :             :         {
     141                 :           0 :           ctxt.report_error
     142                 :           0 :             ("%<%s%s%>:"
     143                 :             :              " unexpected value %qs for key %qs; expected %qs or %qs",
     144                 :           0 :              ctxt.m_option_name, unparsed_arg,
     145                 :             :              value.c_str (),
     146                 :             :              key.c_str (),
     147                 :             :              "yes", "no");
     148                 :             : 
     149                 :           0 :           return false;
     150                 :             :         }
     151                 :             :     }
     152                 :             :     template <typename EnumType, size_t NumValues>
     153                 :             :     bool
     154                 :           3 :     parse_enum_value (const context &ctxt,
     155                 :             :                       const char *unparsed_arg,
     156                 :             :                       const std::string &key,
     157                 :             :                       const std::string &value,
     158                 :             :                       const std::array<std::pair<const char *, EnumType>, NumValues> &value_names,
     159                 :             :                       EnumType &out) const
     160                 :             :     {
     161                 :           5 :       for (auto &iter : value_names)
     162                 :           5 :         if (value == iter.first)
     163                 :             :           {
     164                 :           3 :             out = iter.second;
     165                 :           3 :             return true;
     166                 :             :           }
     167                 :             : 
     168                 :           0 :       auto_vec<const char *> known_values;
     169                 :           0 :       for (auto iter : value_names)
     170                 :           0 :         known_values.safe_push (iter.first);
     171                 :           0 :       pp_markup::comma_separated_quoted_strings e (known_values);
     172                 :             :       ctxt.report_error
     173                 :           0 :         ("%<%s%s%>:"
     174                 :             :          " unexpected value %qs for key %qs; known values: %e",
     175                 :           0 :          ctxt.m_option_name, unparsed_arg,
     176                 :             :          value.c_str (),
     177                 :             :          key.c_str (),
     178                 :             :          &e);
     179                 :           0 :       return false;
     180                 :           0 :     }
     181                 :             : 
     182                 :             :   private:
     183                 :             :     const std::string m_scheme_name;
     184                 :             :   };
     185                 :             : 
     186                 :             :   output_factory ();
     187                 :             : 
     188                 :             :   std::unique_ptr<diagnostic_output_format>
     189                 :             :   make_sink (const context &ctxt,
     190                 :             :              const char *unparsed_arg,
     191                 :             :              const scheme_name_and_params &parsed_arg);
     192                 :             : 
     193                 :             :   const scheme_handler *get_scheme_handler (const std::string &scheme_name);
     194                 :             : 
     195                 :             : private:
     196                 :             :   std::vector<std::unique_ptr<scheme_handler>> m_scheme_handlers;
     197                 :             : };
     198                 :             : 
     199                 :             : class text_scheme_handler : public output_factory::scheme_handler
     200                 :             : {
     201                 :             : public:
     202                 :          25 :   text_scheme_handler () : scheme_handler ("text") {}
     203                 :             : 
     204                 :             :   std::unique_ptr<diagnostic_output_format>
     205                 :             :   make_sink (const context &ctxt,
     206                 :             :              const char *unparsed_arg,
     207                 :             :              const scheme_name_and_params &parsed_arg) const final override;
     208                 :             : };
     209                 :             : 
     210                 :             : class sarif_scheme_handler : public output_factory::scheme_handler
     211                 :             : {
     212                 :             : public:
     213                 :          25 :   sarif_scheme_handler () : scheme_handler ("sarif") {}
     214                 :             : 
     215                 :             :   std::unique_ptr<diagnostic_output_format>
     216                 :             :   make_sink (const context &ctxt,
     217                 :             :              const char *unparsed_arg,
     218                 :             :              const scheme_name_and_params &parsed_arg) const final override;
     219                 :             : };
     220                 :             : 
     221                 :             : class html_scheme_handler : public output_factory::scheme_handler
     222                 :             : {
     223                 :             : public:
     224                 :          25 :   html_scheme_handler () : scheme_handler ("experimental-html") {}
     225                 :             : 
     226                 :             :   std::unique_ptr<diagnostic_output_format>
     227                 :             :   make_sink (const context &ctxt,
     228                 :             :              const char *unparsed_arg,
     229                 :             :              const scheme_name_and_params &parsed_arg) const final override;
     230                 :             : };
     231                 :             : 
     232                 :             : /* struct context.  */
     233                 :             : 
     234                 :             : void
     235                 :          16 : context::report_error (const char *gmsgid, ...) const
     236                 :             : {
     237                 :          16 :   m_dc.begin_group ();
     238                 :          16 :   va_list ap;
     239                 :          16 :   va_start (ap, gmsgid);
     240                 :          16 :   rich_location richloc (m_location_mgr, m_loc);
     241                 :          16 :   m_dc.diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_ERROR);
     242                 :          16 :   va_end (ap);
     243                 :          16 :   m_dc.end_group ();
     244                 :          16 : }
     245                 :             : 
     246                 :             : void
     247                 :           0 : context::report_unknown_key (const char *unparsed_arg,
     248                 :             :                              const std::string &key,
     249                 :             :                              const std::string &scheme_name,
     250                 :             :                              auto_vec<const char *> &known_keys) const
     251                 :             : {
     252                 :           0 :   pp_markup::comma_separated_quoted_strings e (known_keys);
     253                 :           0 :   report_error
     254                 :           0 :     ("%<%s%s%>:"
     255                 :             :      " unknown key %qs for format %qs; known keys: %e",
     256                 :           0 :      m_option_name, unparsed_arg,
     257                 :             :      key.c_str (), scheme_name.c_str (), &e);
     258                 :           0 : }
     259                 :             : 
     260                 :             : void
     261                 :           0 : context::report_missing_key (const char *unparsed_arg,
     262                 :             :                              const std::string &key,
     263                 :             :                              const std::string &scheme_name,
     264                 :             :                              const char *metavar) const
     265                 :             : {
     266                 :           0 :   report_error
     267                 :           0 :     ("%<%s%s%>:"
     268                 :             :      " missing required key %qs for format %qs;"
     269                 :             :      " try %<%s%s:%s=%s%>",
     270                 :             :      m_option_name, unparsed_arg,
     271                 :             :      key.c_str (), scheme_name.c_str (),
     272                 :           0 :      m_option_name, scheme_name.c_str (), key.c_str (), metavar);
     273                 :           0 : }
     274                 :             : 
     275                 :             : std::unique_ptr<scheme_name_and_params>
     276                 :          53 : parse (const context &ctxt, const char *unparsed_arg)
     277                 :             : {
     278                 :          53 :   scheme_name_and_params result;
     279                 :          53 :   if (const char *const colon = strchr (unparsed_arg, ':'))
     280                 :             :     {
     281                 :          46 :       result.m_scheme_name = std::string (unparsed_arg, colon - unparsed_arg);
     282                 :             :       /* Expect zero of more of KEY=VALUE,KEY=VALUE, etc  .*/
     283                 :          46 :       const char *iter = colon + 1;
     284                 :          46 :       const char *last_separator = ":";
     285                 :          96 :       while (iter)
     286                 :             :         {
     287                 :             :           /* Look for a non-empty key string followed by '='.  */
     288                 :          66 :           const char *eq = strchr (iter, '=');
     289                 :          66 :           if (eq == nullptr || eq == iter)
     290                 :             :             {
     291                 :             :               /* Missing '='.  */
     292                 :          16 :               ctxt.report_error
     293                 :          16 :                 ("%<%s%s%>:"
     294                 :             :                  " expected KEY=VALUE-style parameter for format %qs"
     295                 :             :                  " after %qs;"
     296                 :             :                  " got %qs",
     297                 :          16 :                  ctxt.m_option_name, unparsed_arg,
     298                 :             :                  result.m_scheme_name.c_str (),
     299                 :             :                  last_separator,
     300                 :             :                  iter);
     301                 :          16 :               return nullptr;
     302                 :             :             }
     303                 :          50 :           std::string key = std::string (iter, eq - iter);
     304                 :          50 :           std::string value;
     305                 :          50 :           const char *comma = strchr (iter, ',');
     306                 :          50 :           if (comma)
     307                 :             :             {
     308                 :          20 :               value = std::string (eq + 1, comma - (eq + 1));
     309                 :          20 :               iter = comma + 1;
     310                 :          20 :               last_separator = ",";
     311                 :             :             }
     312                 :             :           else
     313                 :             :             {
     314                 :          30 :               value = std::string (eq + 1);
     315                 :          30 :               iter = nullptr;
     316                 :             :             }
     317                 :         150 :           result.m_kvs.push_back ({std::move (key), std::move (value)});
     318                 :          50 :         }
     319                 :             :     }
     320                 :             :   else
     321                 :           7 :     result.m_scheme_name = unparsed_arg;
     322                 :          37 :   return std::make_unique<scheme_name_and_params> (std::move (result));
     323                 :          53 : }
     324                 :             : 
     325                 :             : /* class output_factory::scheme_handler.  */
     326                 :             : 
     327                 :             : /* class output_factory.  */
     328                 :             : 
     329                 :          25 : output_factory::output_factory ()
     330                 :             : {
     331                 :          25 :   m_scheme_handlers.push_back (std::make_unique<text_scheme_handler> ());
     332                 :          25 :   m_scheme_handlers.push_back (std::make_unique<sarif_scheme_handler> ());
     333                 :          25 :   m_scheme_handlers.push_back (std::make_unique<html_scheme_handler> ());
     334                 :          25 : }
     335                 :             : 
     336                 :             : const output_factory::scheme_handler *
     337                 :          25 : output_factory::get_scheme_handler (const std::string &scheme_name)
     338                 :             : {
     339                 :          45 :   for (auto &iter : m_scheme_handlers)
     340                 :          45 :     if (iter->get_scheme_name () == scheme_name)
     341                 :          25 :       return iter.get ();
     342                 :             :   return nullptr;
     343                 :             : }
     344                 :             : 
     345                 :             : std::unique_ptr<diagnostic_output_format>
     346                 :          25 : output_factory::make_sink (const context &ctxt,
     347                 :             :                            const char *unparsed_arg,
     348                 :             :                            const scheme_name_and_params &parsed_arg)
     349                 :             : {
     350                 :          25 :   auto scheme_handler = get_scheme_handler (parsed_arg.m_scheme_name);
     351                 :          25 :   if (!scheme_handler)
     352                 :             :     {
     353                 :           0 :       auto_vec<const char *> strings;
     354                 :           0 :       for (auto &iter : m_scheme_handlers)
     355                 :           0 :         strings.safe_push (iter->get_scheme_name ().c_str ());
     356                 :           0 :       pp_markup::comma_separated_quoted_strings e (strings);
     357                 :           0 :       ctxt.report_error ("%<%s%s%>:"
     358                 :             :                          " unrecognized format %qs; known formats: %e",
     359                 :           0 :                          ctxt.m_option_name, unparsed_arg,
     360                 :             :                          parsed_arg.m_scheme_name.c_str (), &e);
     361                 :           0 :       return nullptr;
     362                 :           0 :     }
     363                 :             : 
     364                 :          25 :   return scheme_handler->make_sink (ctxt, unparsed_arg, parsed_arg);
     365                 :             : }
     366                 :             : 
     367                 :             : /* class text_scheme_handler : public output_factory::scheme_handler.  */
     368                 :             : 
     369                 :             : std::unique_ptr<diagnostic_output_format>
     370                 :          12 : text_scheme_handler::make_sink (const context &ctxt,
     371                 :             :                                 const char *unparsed_arg,
     372                 :             :                                 const scheme_name_and_params &parsed_arg) const
     373                 :             : {
     374                 :          12 :   bool show_color = pp_show_color (ctxt.m_dc.get_reference_printer ());
     375                 :          12 :   bool show_nesting = false;
     376                 :          12 :   bool show_locations_in_nesting = true;
     377                 :          12 :   bool show_levels = false;
     378                 :          34 :   for (auto& iter : parsed_arg.m_kvs)
     379                 :             :     {
     380                 :          22 :       const std::string &key = iter.first;
     381                 :          22 :       const std::string &value = iter.second;
     382                 :          22 :       if (key == "color")
     383                 :             :         {
     384                 :           0 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value, show_color))
     385                 :           0 :             return nullptr;
     386                 :          22 :           continue;
     387                 :             :         }
     388                 :          22 :       if (key == "experimental-nesting")
     389                 :             :         {
     390                 :          12 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value,
     391                 :             :                                  show_nesting))
     392                 :           0 :             return nullptr;
     393                 :          12 :           continue;
     394                 :             :         }
     395                 :          10 :       if (key == "experimental-nesting-show-locations")
     396                 :             :         {
     397                 :           9 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value,
     398                 :             :                                  show_locations_in_nesting))
     399                 :           0 :             return nullptr;
     400                 :           9 :           continue;
     401                 :             :         }
     402                 :           1 :       if (key == "experimental-nesting-show-levels")
     403                 :             :         {
     404                 :           1 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value, show_levels))
     405                 :           0 :             return nullptr;
     406                 :           1 :           continue;
     407                 :             :         }
     408                 :             : 
     409                 :             :       /* Key not found.  */
     410                 :           0 :       auto_vec<const char *> known_keys;
     411                 :           0 :       known_keys.safe_push ("color");
     412                 :           0 :       known_keys.safe_push ("experimental-nesting");
     413                 :           0 :       known_keys.safe_push ("experimental-nesting-show-locations");
     414                 :           0 :       known_keys.safe_push ("experimental-nesting-show-levels");
     415                 :           0 :       ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
     416                 :             :                                known_keys);
     417                 :           0 :       return nullptr;
     418                 :           0 :     }
     419                 :             : 
     420                 :          12 :   auto sink = std::make_unique<diagnostic_text_output_format> (ctxt.m_dc);
     421                 :          12 :   sink->set_show_nesting (show_nesting);
     422                 :          12 :   sink->set_show_locations_in_nesting (show_locations_in_nesting);
     423                 :          12 :   sink->set_show_nesting_levels (show_levels);
     424                 :          12 :   return sink;
     425                 :          12 : }
     426                 :             : 
     427                 :             : diagnostic_output_file
     428                 :           2 : context::open_output_file (label_text &&filename) const
     429                 :             : {
     430                 :           2 :   FILE *outf = fopen (filename.get (), "w");
     431                 :           2 :   if (!outf)
     432                 :             :     {
     433                 :           0 :       rich_location richloc (m_location_mgr, m_loc);
     434                 :           0 :       m_dc.emit_diagnostic_with_group
     435                 :           0 :         (DK_ERROR, richloc, nullptr, 0,
     436                 :             :          "unable to open %qs: %m", filename.get ());
     437                 :           0 :       return diagnostic_output_file (nullptr, false, std::move (filename));
     438                 :           0 :     }
     439                 :           2 :   return diagnostic_output_file (outf, true, std::move (filename));
     440                 :             : }
     441                 :             : 
     442                 :             : /* class sarif_scheme_handler : public output_factory::scheme_handler.  */
     443                 :             : 
     444                 :             : std::unique_ptr<diagnostic_output_format>
     445                 :           6 : sarif_scheme_handler::make_sink (const context &ctxt,
     446                 :             :                                  const char *unparsed_arg,
     447                 :             :                                  const scheme_name_and_params &parsed_arg) const
     448                 :             : {
     449                 :           6 :   label_text filename;
     450                 :           6 :   enum sarif_serialization_kind serialization_kind
     451                 :             :     = sarif_serialization_kind::json;
     452                 :           6 :   enum sarif_version version = sarif_version::v2_1_0;
     453                 :          11 :   for (auto& iter : parsed_arg.m_kvs)
     454                 :             :     {
     455                 :           5 :       const std::string &key = iter.first;
     456                 :           5 :       const std::string &value = iter.second;
     457                 :           5 :       if (key == "file")
     458                 :             :         {
     459                 :           2 :           filename = label_text::take (xstrdup (value.c_str ()));
     460                 :           5 :           continue;
     461                 :             :         }
     462                 :           3 :       if (key == "serialization")
     463                 :             :         {
     464                 :           0 :           static const std::array<std::pair<const char *, enum sarif_serialization_kind>,
     465                 :             :                                   (size_t)sarif_serialization_kind::num_values> value_names
     466                 :             :             {{{"json", sarif_serialization_kind::json}}};
     467                 :             : 
     468                 :           0 :           if (!parse_enum_value<enum sarif_serialization_kind>
     469                 :           0 :                  (ctxt, unparsed_arg,
     470                 :             :                   key, value,
     471                 :             :                   value_names,
     472                 :             :                   serialization_kind))
     473                 :           0 :             return nullptr;
     474                 :           0 :           continue;
     475                 :           0 :         }
     476                 :           3 :       if (key == "version")
     477                 :             :         {
     478                 :           3 :           static const std::array<std::pair<const char *, enum sarif_version>,
     479                 :             :                                   (size_t)sarif_version::num_versions> value_names
     480                 :             :             {{{"2.1", sarif_version::v2_1_0},
     481                 :             :               {"2.2-prerelease", sarif_version::v2_2_prerelease_2024_08_08}}};
     482                 :             : 
     483                 :           3 :             if (!parse_enum_value<enum sarif_version> (ctxt, unparsed_arg,
     484                 :             :                                                        key, value,
     485                 :             :                                                        value_names,
     486                 :             :                                                        version))
     487                 :           0 :             return nullptr;
     488                 :           3 :           continue;
     489                 :           3 :         }
     490                 :             : 
     491                 :             :       /* Key not found.  */
     492                 :           0 :       auto_vec<const char *> known_keys;
     493                 :           0 :       known_keys.safe_push ("file");
     494                 :           0 :       known_keys.safe_push ("serialization");
     495                 :           0 :       known_keys.safe_push ("version");
     496                 :           0 :       ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
     497                 :             :                                known_keys);
     498                 :           0 :       return nullptr;
     499                 :           0 :     }
     500                 :             : 
     501                 :           6 :   diagnostic_output_file output_file;
     502                 :           6 :   if (filename.get ())
     503                 :           2 :     output_file = ctxt.open_output_file (std::move (filename));
     504                 :             :   else
     505                 :             :     // Default filename
     506                 :             :     {
     507                 :           4 :       const char *basename = (ctxt.m_opts.x_dump_base_name
     508                 :             :                               ? ctxt.m_opts.x_dump_base_name
     509                 :             :                               : ctxt.m_opts.x_main_input_basename);
     510                 :           8 :       output_file = diagnostic_output_format_open_sarif_file (ctxt.m_dc,
     511                 :             :                                                               line_table,
     512                 :             :                                                               basename,
     513                 :           4 :                                                               serialization_kind);
     514                 :             :     }
     515                 :           6 :   if (!output_file)
     516                 :           0 :     return nullptr;
     517                 :             : 
     518                 :           6 :   sarif_generation_options sarif_gen_opts;
     519                 :           6 :   sarif_gen_opts.m_version = version;
     520                 :             : 
     521                 :           6 :   std::unique_ptr<sarif_serialization_format> serialization_obj;
     522                 :           6 :   switch (serialization_kind)
     523                 :             :     {
     524                 :           0 :     default:
     525                 :           0 :       gcc_unreachable ();
     526                 :           6 :     case sarif_serialization_kind::json:
     527                 :           6 :       serialization_obj
     528                 :           6 :         = std::make_unique<sarif_serialization_format_json> (true);
     529                 :           6 :       break;
     530                 :             :     }
     531                 :             : 
     532                 :           6 :   auto sink = make_sarif_sink (ctxt.m_dc,
     533                 :             :                                *line_table,
     534                 :             :                                std::move (serialization_obj),
     535                 :             :                                sarif_gen_opts,
     536                 :           6 :                                std::move (output_file));
     537                 :           6 :   return sink;
     538                 :           6 : }
     539                 :             : 
     540                 :             : /* class html_scheme_handler : public output_factory::scheme_handler.  */
     541                 :             : 
     542                 :             : std::unique_ptr<diagnostic_output_format>
     543                 :           7 : html_scheme_handler::make_sink (const context &ctxt,
     544                 :             :                                 const char *unparsed_arg,
     545                 :             :                                 const scheme_name_and_params &parsed_arg) const
     546                 :             : {
     547                 :           7 :   bool css = true;
     548                 :           7 :   label_text filename;
     549                 :           7 :   bool javascript = true;
     550                 :          14 :   for (auto& iter : parsed_arg.m_kvs)
     551                 :             :     {
     552                 :           7 :       const std::string &key = iter.first;
     553                 :           7 :       const std::string &value = iter.second;
     554                 :           7 :       if (key == "css")
     555                 :             :         {
     556                 :           0 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value,
     557                 :             :                                  css))
     558                 :           0 :             return nullptr;
     559                 :           7 :           continue;
     560                 :             :         }
     561                 :           7 :       if (key == "file")
     562                 :             :         {
     563                 :           0 :           filename = label_text::take (xstrdup (value.c_str ()));
     564                 :           0 :           continue;
     565                 :             :         }
     566                 :           7 :       if (key == "javascript")
     567                 :             :         {
     568                 :           7 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value,
     569                 :             :                                  javascript))
     570                 :           0 :             return nullptr;
     571                 :           7 :           continue;
     572                 :             :         }
     573                 :             : 
     574                 :             :       /* Key not found.  */
     575                 :           0 :       auto_vec<const char *> known_keys;
     576                 :           0 :       known_keys.safe_push ("css");
     577                 :           0 :       known_keys.safe_push ("file");
     578                 :           0 :       known_keys.safe_push ("javascript");
     579                 :           0 :       ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
     580                 :             :                                known_keys);
     581                 :           0 :       return nullptr;
     582                 :           0 :     }
     583                 :             : 
     584                 :           7 :   diagnostic_output_file output_file;
     585                 :           7 :   if (filename.get ())
     586                 :           0 :     output_file = ctxt.open_output_file (std::move (filename));
     587                 :             :   else
     588                 :             :     // Default filename
     589                 :             :     {
     590                 :           7 :       const char *basename = (ctxt.m_opts.x_dump_base_name
     591                 :             :                               ? ctxt.m_opts.x_dump_base_name
     592                 :             :                               : ctxt.m_opts.x_main_input_basename);
     593                 :          14 :       output_file = diagnostic_output_format_open_html_file (ctxt.m_dc,
     594                 :             :                                                              line_table,
     595                 :           7 :                                                              basename);
     596                 :             :     }
     597                 :           7 :   if (!output_file)
     598                 :           0 :     return nullptr;
     599                 :             : 
     600                 :           7 :   html_generation_options html_gen_opts;
     601                 :           7 :   html_gen_opts.m_css = css;
     602                 :           7 :   html_gen_opts.m_javascript = javascript;
     603                 :             : 
     604                 :          14 :   auto sink = make_html_sink (ctxt.m_dc,
     605                 :             :                               *line_table,
     606                 :             :                               html_gen_opts,
     607                 :           7 :                               std::move (output_file));
     608                 :           7 :   return sink;
     609                 :           7 : }
     610                 :             : 
     611                 :             : } // namespace diagnostics_output_spec
     612                 :             : } // namespace gcc
     613                 :             : 
     614                 :             : void
     615                 :          11 : handle_OPT_fdiagnostics_add_output_ (const gcc_options &opts,
     616                 :             :                                      diagnostic_context &dc,
     617                 :             :                                      const char *arg,
     618                 :             :                                      location_t loc)
     619                 :             : {
     620                 :          11 :   gcc_assert (arg);
     621                 :          11 :   gcc_assert (line_table);
     622                 :             : 
     623                 :          11 :   const char *const option_name = "-fdiagnostics-add-output=";
     624                 :          11 :   gcc::diagnostics_output_spec::context ctxt (opts, dc, line_table, loc,
     625                 :          11 :                                               option_name);
     626                 :          11 :   auto result = gcc::diagnostics_output_spec::parse (ctxt, arg);
     627                 :          11 :   if (!result)
     628                 :             :     return;
     629                 :             : 
     630                 :          11 :   gcc::diagnostics_output_spec::output_factory factory;
     631                 :          11 :   auto sink = factory.make_sink (ctxt, arg, *result);
     632                 :          11 :   if (!sink)
     633                 :           0 :     return;
     634                 :             : 
     635                 :          11 :   sink->set_main_input_filename (opts.x_main_input_filename);
     636                 :          11 :   dc.add_sink (std::move (sink));
     637                 :          11 : }
     638                 :             : 
     639                 :             : void
     640                 :          14 : handle_OPT_fdiagnostics_set_output_ (const gcc_options &opts,
     641                 :             :                                      diagnostic_context &dc,
     642                 :             :                                      const char *arg,
     643                 :             :                                      location_t loc)
     644                 :             : {
     645                 :          14 :   gcc_assert (arg);
     646                 :          14 :   gcc_assert (line_table);
     647                 :             : 
     648                 :          14 :   const char *const option_name = "-fdiagnostics-set-output=";
     649                 :          14 :   gcc::diagnostics_output_spec::context ctxt (opts, dc, line_table, loc,
     650                 :          14 :                                               option_name);
     651                 :          14 :   auto result = gcc::diagnostics_output_spec::parse (ctxt, arg);
     652                 :          14 :   if (!result)
     653                 :             :     return;
     654                 :             : 
     655                 :          14 :   gcc::diagnostics_output_spec::output_factory factory;
     656                 :          14 :   auto sink = factory.make_sink (ctxt, arg, *result);
     657                 :          14 :   if (!sink)
     658                 :           0 :     return;
     659                 :             : 
     660                 :          14 :   sink->set_main_input_filename (opts.x_main_input_filename);
     661                 :          14 :   dc.set_output_format (std::move (sink));
     662                 :          14 : }
     663                 :             : 
     664                 :             : #if CHECKING_P
     665                 :             : 
     666                 :             : namespace selftest {
     667                 :             : 
     668                 :             : /* RAII class to temporarily override "progname" to the
     669                 :             :    string "PROGNAME".  */
     670                 :             : 
     671                 :             : class auto_fix_progname
     672                 :             : {
     673                 :             : public:
     674                 :           4 :   auto_fix_progname ()
     675                 :           4 :   {
     676                 :           4 :     m_old_progname = progname;
     677                 :           4 :     progname = "PROGNAME";
     678                 :             :   }
     679                 :             : 
     680                 :           4 :   ~auto_fix_progname ()
     681                 :             :   {
     682                 :           4 :     progname = m_old_progname;
     683                 :           4 :   }
     684                 :             : 
     685                 :             : private:
     686                 :             :   const char *m_old_progname;
     687                 :             : };
     688                 :             : 
     689                 :          56 : struct parser_test
     690                 :             : {
     691                 :          28 :   parser_test ()
     692                 :          28 :   : m_opts (),
     693                 :          28 :     m_dc (),
     694                 :          28 :     m_ctxt (m_opts, m_dc, line_table, UNKNOWN_LOCATION, "-fOPTION="),
     695                 :          28 :     m_fmt (m_dc.get_output_format (0))
     696                 :             :   {
     697                 :          28 :     pp_buffer (m_fmt.get_printer ())->m_flush_p = false;
     698                 :          28 :   }
     699                 :             : 
     700                 :             :   std::unique_ptr<gcc::diagnostics_output_spec::scheme_name_and_params>
     701                 :          28 :   parse (const char *unparsed_arg)
     702                 :             :   {
     703                 :          28 :     return gcc::diagnostics_output_spec::parse (m_ctxt, unparsed_arg);
     704                 :             :   }
     705                 :             : 
     706                 :          28 :   bool execution_failed_p () const
     707                 :             :   {
     708                 :          28 :     return m_dc.execution_failed_p ();
     709                 :             :   }
     710                 :             : 
     711                 :             :   const char *
     712                 :          16 :   get_diagnostic_text () const
     713                 :             :   {
     714                 :          16 :     return pp_formatted_text (m_fmt.get_printer ());
     715                 :             :   }
     716                 :             : 
     717                 :             : private:
     718                 :             :   const gcc_options m_opts;
     719                 :             :   test_diagnostic_context m_dc;
     720                 :             :   gcc::diagnostics_output_spec::context m_ctxt;
     721                 :             :   diagnostic_output_format &m_fmt;
     722                 :             : };
     723                 :             : 
     724                 :             : /* Selftests.  */
     725                 :             : 
     726                 :             : static void
     727                 :           4 : test_output_arg_parsing ()
     728                 :             : {
     729                 :           4 :   auto_fix_quotes fix_quotes;
     730                 :           4 :   auto_fix_progname fix_progname;
     731                 :             : 
     732                 :             :   /* Minimal correct example.  */
     733                 :           4 :   {
     734                 :           4 :     parser_test pt;
     735                 :           4 :     auto result = pt.parse ("foo");
     736                 :           4 :     ASSERT_EQ (result->m_scheme_name, "foo");
     737                 :           4 :     ASSERT_EQ (result->m_kvs.size (), 0);
     738                 :           4 :     ASSERT_FALSE (pt.execution_failed_p ());
     739                 :           4 :   }
     740                 :             : 
     741                 :             :   /* Stray trailing colon with no key/value pairs.  */
     742                 :           4 :   {
     743                 :           4 :     parser_test pt;
     744                 :           4 :     auto result = pt.parse ("foo:");
     745                 :           4 :     ASSERT_EQ (result, nullptr);
     746                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     747                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     748                 :             :                   "PROGNAME: error: `-fOPTION=foo:':"
     749                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     750                 :             :                   " after `:';"
     751                 :             :                   " got `'\n");
     752                 :           4 :   }
     753                 :             : 
     754                 :             :   /* No key before '='.  */
     755                 :           4 :   {
     756                 :           4 :     parser_test pt;
     757                 :           4 :     auto result = pt.parse ("foo:=");
     758                 :           4 :     ASSERT_EQ (result, nullptr);
     759                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     760                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     761                 :             :                   "PROGNAME: error: `-fOPTION=foo:=':"
     762                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     763                 :             :                   " after `:';"
     764                 :             :                   " got `='\n");
     765                 :           4 :   }
     766                 :             : 
     767                 :             :   /* No value for key.  */
     768                 :           4 :   {
     769                 :           4 :     parser_test pt;
     770                 :           4 :     auto result = pt.parse ("foo:key,");
     771                 :           4 :     ASSERT_EQ (result, nullptr);
     772                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     773                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     774                 :             :                   "PROGNAME: error: `-fOPTION=foo:key,':"
     775                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     776                 :             :                   " after `:';"
     777                 :             :                   " got `key,'\n");
     778                 :           4 :   }
     779                 :             : 
     780                 :             :   /* Correct example, with one key/value pair.  */
     781                 :           4 :   {
     782                 :           4 :     parser_test pt;
     783                 :           4 :     auto result = pt.parse ("foo:key=value");
     784                 :           4 :     ASSERT_EQ (result->m_scheme_name, "foo");
     785                 :           4 :     ASSERT_EQ (result->m_kvs.size (), 1);
     786                 :           4 :     ASSERT_EQ (result->m_kvs[0].first, "key");
     787                 :           4 :     ASSERT_EQ (result->m_kvs[0].second, "value");
     788                 :           4 :     ASSERT_FALSE (pt.execution_failed_p ());
     789                 :           4 :   }
     790                 :             : 
     791                 :             :   /* Stray trailing comma.  */
     792                 :           4 :   {
     793                 :           4 :     parser_test pt;
     794                 :           4 :     auto result = pt.parse ("foo:key=value,");
     795                 :           4 :     ASSERT_EQ (result, nullptr);
     796                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     797                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     798                 :             :                   "PROGNAME: error: `-fOPTION=foo:key=value,':"
     799                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     800                 :             :                   " after `,';"
     801                 :             :                   " got `'\n");
     802                 :           4 :   }
     803                 :             : 
     804                 :             :   /* Correct example, with two key/value pairs.  */
     805                 :           4 :   {
     806                 :           4 :     parser_test pt;
     807                 :           4 :     auto result = pt.parse ("foo:color=red,shape=circle");
     808                 :           4 :     ASSERT_EQ (result->m_scheme_name, "foo");
     809                 :           4 :     ASSERT_EQ (result->m_kvs.size (), 2);
     810                 :           4 :     ASSERT_EQ (result->m_kvs[0].first, "color");
     811                 :           4 :     ASSERT_EQ (result->m_kvs[0].second, "red");
     812                 :           4 :     ASSERT_EQ (result->m_kvs[1].first, "shape");
     813                 :           4 :     ASSERT_EQ (result->m_kvs[1].second, "circle");
     814                 :           4 :     ASSERT_FALSE (pt.execution_failed_p ());
     815                 :           4 :   }
     816                 :           4 : }
     817                 :             : 
     818                 :             : /* Run all of the selftests within this file.  */
     819                 :             : 
     820                 :             : void
     821                 :           4 : opts_diagnostic_cc_tests ()
     822                 :             : {
     823                 :           4 :   test_output_arg_parsing ();
     824                 :           4 : }
     825                 :             : 
     826                 :             : } // namespace selftest
     827                 :             : 
     828                 :             : #endif /* #if 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.