LCOV - code coverage report
Current view: top level - gcc - opts-diagnostic.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 79.9 % 293 234
Test Date: 2024-12-21 13:15:12 Functions: 89.5 % 19 17
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 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-text.h"
      36                 :             : #include "diagnostic-format-sarif.h"
      37                 :             : #include "selftest.h"
      38                 :             : #include "selftest-diagnostic.h"
      39                 :             : #include "pretty-print-markup.h"
      40                 :             : #include "opts.h"
      41                 :             : #include "options.h"
      42                 :             : #include "make-unique.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                 :          46 :   context (const gcc_options &opts,
      56                 :             :            diagnostic_context &dc,
      57                 :             :            line_maps *location_mgr,
      58                 :             :            location_t loc,
      59                 :             :            const char *option_name)
      60                 :          46 :   : m_opts (opts), m_dc (dc), m_location_mgr (location_mgr), m_loc (loc),
      61                 :          46 :     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                 :          76 : 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                 :          36 : class output_factory
     104                 :             : {
     105                 :             : public:
     106                 :             :   class scheme_handler
     107                 :             :   {
     108                 :             :   public:
     109                 :          36 :     scheme_handler (std::string scheme_name)
     110                 :          36 :     : m_scheme_name (std::move (scheme_name))
     111                 :             :     {}
     112                 :             :     virtual ~scheme_handler () {}
     113                 :             : 
     114                 :          24 :     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                 :          22 :     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                 :          22 :       if (value == "yes")
     130                 :             :         {
     131                 :          13 :           out = true;
     132                 :          13 :           return true;
     133                 :             :         }
     134                 :           9 :       else if (value == "no")
     135                 :             :         {
     136                 :           9 :           out = false;
     137                 :           9 :           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                 :          18 :   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                 :          18 :   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                 :             : /* struct context.  */
     222                 :             : 
     223                 :             : void
     224                 :          16 : context::report_error (const char *gmsgid, ...) const
     225                 :             : {
     226                 :          16 :   m_dc.begin_group ();
     227                 :          16 :   va_list ap;
     228                 :          16 :   va_start (ap, gmsgid);
     229                 :          16 :   rich_location richloc (m_location_mgr, m_loc);
     230                 :          16 :   m_dc.diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_ERROR);
     231                 :          16 :   va_end (ap);
     232                 :          16 :   m_dc.end_group ();
     233                 :          16 : }
     234                 :             : 
     235                 :             : void
     236                 :           0 : context::report_unknown_key (const char *unparsed_arg,
     237                 :             :                              const std::string &key,
     238                 :             :                              const std::string &scheme_name,
     239                 :             :                              auto_vec<const char *> &known_keys) const
     240                 :             : {
     241                 :           0 :   pp_markup::comma_separated_quoted_strings e (known_keys);
     242                 :           0 :   report_error
     243                 :           0 :     ("%<%s%s%>:"
     244                 :             :      " unknown key %qs for format %qs; known keys: %e",
     245                 :           0 :      m_option_name, unparsed_arg,
     246                 :             :      key.c_str (), scheme_name.c_str (), &e);
     247                 :           0 : }
     248                 :             : 
     249                 :             : void
     250                 :           0 : context::report_missing_key (const char *unparsed_arg,
     251                 :             :                              const std::string &key,
     252                 :             :                              const std::string &scheme_name,
     253                 :             :                              const char *metavar) const
     254                 :             : {
     255                 :           0 :   report_error
     256                 :           0 :     ("%<%s%s%>:"
     257                 :             :      " missing required key %qs for format %qs;"
     258                 :             :      " try %<%s%s:%s=%s%>",
     259                 :             :      m_option_name, unparsed_arg,
     260                 :             :      key.c_str (), scheme_name.c_str (),
     261                 :           0 :      m_option_name, scheme_name.c_str (), key.c_str (), metavar);
     262                 :           0 : }
     263                 :             : 
     264                 :             : std::unique_ptr<scheme_name_and_params>
     265                 :          46 : parse (const context &ctxt, const char *unparsed_arg)
     266                 :             : {
     267                 :          46 :   scheme_name_and_params result;
     268                 :          46 :   if (const char *const colon = strchr (unparsed_arg, ':'))
     269                 :             :     {
     270                 :          39 :       result.m_scheme_name = std::string (unparsed_arg, colon - unparsed_arg);
     271                 :             :       /* Expect zero of more of KEY=VALUE,KEY=VALUE, etc  .*/
     272                 :          39 :       const char *iter = colon + 1;
     273                 :          39 :       const char *last_separator = ":";
     274                 :          82 :       while (iter)
     275                 :             :         {
     276                 :             :           /* Look for a non-empty key string followed by '='.  */
     277                 :          59 :           const char *eq = strchr (iter, '=');
     278                 :          59 :           if (eq == nullptr || eq == iter)
     279                 :             :             {
     280                 :             :               /* Missing '='.  */
     281                 :          16 :               ctxt.report_error
     282                 :          16 :                 ("%<%s%s%>:"
     283                 :             :                  " expected KEY=VALUE-style parameter for format %qs"
     284                 :             :                  " after %qs;"
     285                 :             :                  " got %qs",
     286                 :          16 :                  ctxt.m_option_name, unparsed_arg,
     287                 :             :                  result.m_scheme_name.c_str (),
     288                 :             :                  last_separator,
     289                 :             :                  iter);
     290                 :          16 :               return nullptr;
     291                 :             :             }
     292                 :          43 :           std::string key = std::string (iter, eq - iter);
     293                 :          43 :           std::string value;
     294                 :          43 :           const char *comma = strchr (iter, ',');
     295                 :          43 :           if (comma)
     296                 :             :             {
     297                 :          20 :               value = std::string (eq + 1, comma - (eq + 1));
     298                 :          20 :               iter = comma + 1;
     299                 :          20 :               last_separator = ",";
     300                 :             :             }
     301                 :             :           else
     302                 :             :             {
     303                 :          23 :               value = std::string (eq + 1);
     304                 :          23 :               iter = nullptr;
     305                 :             :             }
     306                 :         129 :           result.m_kvs.push_back ({std::move (key), std::move (value)});
     307                 :          43 :         }
     308                 :             :     }
     309                 :             :   else
     310                 :           7 :     result.m_scheme_name = unparsed_arg;
     311                 :          30 :   return ::make_unique<scheme_name_and_params> (std::move (result));
     312                 :          46 : }
     313                 :             : 
     314                 :             : /* class output_factory::scheme_handler.  */
     315                 :             : 
     316                 :             : /* class output_factory.  */
     317                 :             : 
     318                 :          18 : output_factory::output_factory ()
     319                 :             : {
     320                 :          18 :   m_scheme_handlers.push_back (::make_unique<text_scheme_handler> ());
     321                 :          18 :   m_scheme_handlers.push_back (::make_unique<sarif_scheme_handler> ());
     322                 :          18 : }
     323                 :             : 
     324                 :             : const output_factory::scheme_handler *
     325                 :          18 : output_factory::get_scheme_handler (const std::string &scheme_name)
     326                 :             : {
     327                 :          24 :   for (auto &iter : m_scheme_handlers)
     328                 :          24 :     if (iter->get_scheme_name () == scheme_name)
     329                 :          18 :       return iter.get ();
     330                 :             :   return nullptr;
     331                 :             : }
     332                 :             : 
     333                 :             : std::unique_ptr<diagnostic_output_format>
     334                 :          18 : output_factory::make_sink (const context &ctxt,
     335                 :             :                            const char *unparsed_arg,
     336                 :             :                            const scheme_name_and_params &parsed_arg)
     337                 :             : {
     338                 :          18 :   auto scheme_handler = get_scheme_handler (parsed_arg.m_scheme_name);
     339                 :          18 :   if (!scheme_handler)
     340                 :             :     {
     341                 :           0 :       auto_vec<const char *> strings;
     342                 :           0 :       for (auto &iter : m_scheme_handlers)
     343                 :           0 :         strings.safe_push (iter->get_scheme_name ().c_str ());
     344                 :           0 :       pp_markup::comma_separated_quoted_strings e (strings);
     345                 :           0 :       ctxt.report_error ("%<%s%s%>:"
     346                 :             :                          " unrecognized format %qs; known formats: %e",
     347                 :           0 :                          ctxt.m_option_name, unparsed_arg,
     348                 :             :                          parsed_arg.m_scheme_name.c_str (), &e);
     349                 :           0 :       return nullptr;
     350                 :           0 :     }
     351                 :             : 
     352                 :          18 :   return scheme_handler->make_sink (ctxt, unparsed_arg, parsed_arg);
     353                 :             : }
     354                 :             : 
     355                 :             : /* class text_scheme_handler : public output_factory::scheme_handler.  */
     356                 :             : 
     357                 :             : std::unique_ptr<diagnostic_output_format>
     358                 :          12 : text_scheme_handler::make_sink (const context &ctxt,
     359                 :             :                                 const char *unparsed_arg,
     360                 :             :                                 const scheme_name_and_params &parsed_arg) const
     361                 :             : {
     362                 :          12 :   bool show_color = pp_show_color (ctxt.m_dc.get_reference_printer ());
     363                 :          12 :   bool show_nesting = false;
     364                 :          12 :   bool show_locations_in_nesting = true;
     365                 :          12 :   bool show_levels = false;
     366                 :          34 :   for (auto& iter : parsed_arg.m_kvs)
     367                 :             :     {
     368                 :          22 :       const std::string &key = iter.first;
     369                 :          22 :       const std::string &value = iter.second;
     370                 :          22 :       if (key == "color")
     371                 :             :         {
     372                 :           0 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value, show_color))
     373                 :           0 :             return nullptr;
     374                 :          22 :           continue;
     375                 :             :         }
     376                 :          22 :       if (key == "experimental-nesting")
     377                 :             :         {
     378                 :          12 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value,
     379                 :             :                                  show_nesting))
     380                 :           0 :             return nullptr;
     381                 :          12 :           continue;
     382                 :             :         }
     383                 :          10 :       if (key == "experimental-nesting-show-locations")
     384                 :             :         {
     385                 :           9 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value,
     386                 :             :                                  show_locations_in_nesting))
     387                 :           0 :             return nullptr;
     388                 :           9 :           continue;
     389                 :             :         }
     390                 :           1 :       if (key == "experimental-nesting-show-levels")
     391                 :             :         {
     392                 :           1 :           if (!parse_bool_value (ctxt, unparsed_arg, key, value, show_levels))
     393                 :           0 :             return nullptr;
     394                 :           1 :           continue;
     395                 :             :         }
     396                 :             : 
     397                 :             :       /* Key not found.  */
     398                 :           0 :       auto_vec<const char *> known_keys;
     399                 :           0 :       known_keys.safe_push ("color");
     400                 :           0 :       known_keys.safe_push ("experimental-nesting");
     401                 :           0 :       known_keys.safe_push ("experimental-nesting-show-locations");
     402                 :           0 :       known_keys.safe_push ("experimental-nesting-show-levels");
     403                 :           0 :       ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
     404                 :             :                                known_keys);
     405                 :           0 :       return nullptr;
     406                 :           0 :     }
     407                 :             : 
     408                 :          12 :   auto sink = ::make_unique<diagnostic_text_output_format> (ctxt.m_dc);
     409                 :          12 :   sink->set_show_nesting (show_nesting);
     410                 :          12 :   sink->set_show_locations_in_nesting (show_locations_in_nesting);
     411                 :          12 :   sink->set_show_nesting_levels (show_levels);
     412                 :          12 :   return sink;
     413                 :          12 : }
     414                 :             : 
     415                 :             : diagnostic_output_file
     416                 :           2 : context::open_output_file (label_text &&filename) const
     417                 :             : {
     418                 :           2 :   FILE *outf = fopen (filename.get (), "w");
     419                 :           2 :   if (!outf)
     420                 :             :     {
     421                 :           0 :       rich_location richloc (m_location_mgr, m_loc);
     422                 :           0 :       m_dc.emit_diagnostic_with_group
     423                 :           0 :         (DK_ERROR, richloc, nullptr, 0,
     424                 :             :          "unable to open %qs: %m", filename.get ());
     425                 :           0 :       return diagnostic_output_file (nullptr, false, std::move (filename));
     426                 :           0 :     }
     427                 :           2 :   return diagnostic_output_file (outf, true, std::move (filename));
     428                 :             : }
     429                 :             : 
     430                 :             : /* class sarif_scheme_handler : public output_factory::scheme_handler.  */
     431                 :             : 
     432                 :             : std::unique_ptr<diagnostic_output_format>
     433                 :           6 : sarif_scheme_handler::make_sink (const context &ctxt,
     434                 :             :                                  const char *unparsed_arg,
     435                 :             :                                  const scheme_name_and_params &parsed_arg) const
     436                 :             : {
     437                 :           6 :   enum sarif_version version = sarif_version::v2_1_0;
     438                 :           6 :   label_text filename;
     439                 :          11 :   for (auto& iter : parsed_arg.m_kvs)
     440                 :             :     {
     441                 :           5 :       const std::string &key = iter.first;
     442                 :           5 :       const std::string &value = iter.second;
     443                 :           5 :       if (key == "version")
     444                 :             :         {
     445                 :           3 :           static const std::array<std::pair<const char *, enum sarif_version>,
     446                 :             :                                   (size_t)sarif_version::num_versions> value_names
     447                 :             :             {{{"2.1", sarif_version::v2_1_0},
     448                 :             :               {"2.2-prerelease", sarif_version::v2_2_prerelease_2024_08_08}}};
     449                 :             : 
     450                 :           3 :             if (!parse_enum_value<enum sarif_version> (ctxt, unparsed_arg,
     451                 :             :                                                        key, value,
     452                 :             :                                                        value_names,
     453                 :             :                                                        version))
     454                 :           0 :             return nullptr;
     455                 :           5 :           continue;
     456                 :           3 :         }
     457                 :           2 :       if (key == "file")
     458                 :             :         {
     459                 :           2 :           filename = label_text::take (xstrdup (value.c_str ()));
     460                 :           2 :           continue;
     461                 :             :         }
     462                 :             : 
     463                 :             :       /* Key not found.  */
     464                 :           0 :       auto_vec<const char *> known_keys;
     465                 :           0 :       known_keys.safe_push ("file");
     466                 :           0 :       known_keys.safe_push ("version");
     467                 :           0 :       ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
     468                 :             :                                known_keys);
     469                 :           0 :       return nullptr;
     470                 :           0 :     }
     471                 :             : 
     472                 :           6 :   diagnostic_output_file output_file;
     473                 :           6 :   if (filename.get ())
     474                 :           2 :     output_file = ctxt.open_output_file (std::move (filename));
     475                 :             :   else
     476                 :             :     // Default filename
     477                 :             :     {
     478                 :           4 :       const char *basename = (ctxt.m_opts.x_dump_base_name
     479                 :             :                               ? ctxt.m_opts.x_dump_base_name
     480                 :             :                               : ctxt.m_opts.x_main_input_basename);
     481                 :           8 :       output_file = diagnostic_output_format_open_sarif_file (ctxt.m_dc,
     482                 :             :                                                               line_table,
     483                 :           4 :                                                               basename);
     484                 :             :     }
     485                 :           6 :   if (!output_file)
     486                 :           0 :     return nullptr;
     487                 :             : 
     488                 :          12 :   auto sink = make_sarif_sink (ctxt.m_dc,
     489                 :             :                                *line_table,
     490                 :           6 :                                ctxt.m_opts.x_main_input_filename,
     491                 :             :                                version,
     492                 :           6 :                                std::move (output_file));
     493                 :           6 :   return sink;
     494                 :           6 : }
     495                 :             : 
     496                 :             : } // namespace diagnostics_output_spec
     497                 :             : } // namespace gcc
     498                 :             : 
     499                 :             : void
     500                 :           5 : handle_OPT_fdiagnostics_add_output_ (const gcc_options &opts,
     501                 :             :                                      diagnostic_context &dc,
     502                 :             :                                      const char *arg,
     503                 :             :                                      location_t loc)
     504                 :             : {
     505                 :           5 :   gcc_assert (arg);
     506                 :           5 :   gcc_assert (line_table);
     507                 :             : 
     508                 :           5 :   const char *const option_name = "-fdiagnostics-add-output=";
     509                 :           5 :   gcc::diagnostics_output_spec::context ctxt (opts, dc, line_table, loc,
     510                 :           5 :                                               option_name);
     511                 :           5 :   auto result = gcc::diagnostics_output_spec::parse (ctxt, arg);
     512                 :           5 :   if (!result)
     513                 :             :     return;
     514                 :             : 
     515                 :           5 :   gcc::diagnostics_output_spec::output_factory factory;
     516                 :           5 :   auto sink = factory.make_sink (ctxt, arg, *result);
     517                 :           5 :   if (!sink)
     518                 :           0 :     return;
     519                 :             : 
     520                 :           5 :   dc.add_sink (std::move (sink));
     521                 :           5 : }
     522                 :             : 
     523                 :             : void
     524                 :          13 : handle_OPT_fdiagnostics_set_output_ (const gcc_options &opts,
     525                 :             :                                      diagnostic_context &dc,
     526                 :             :                                      const char *arg,
     527                 :             :                                      location_t loc)
     528                 :             : {
     529                 :          13 :   gcc_assert (arg);
     530                 :          13 :   gcc_assert (line_table);
     531                 :             : 
     532                 :          13 :   const char *const option_name = "-fdiagnostics-set-output=";
     533                 :          13 :   gcc::diagnostics_output_spec::context ctxt (opts, dc, line_table, loc,
     534                 :          13 :                                               option_name);
     535                 :          13 :   auto result = gcc::diagnostics_output_spec::parse (ctxt, arg);
     536                 :          13 :   if (!result)
     537                 :             :     return;
     538                 :             : 
     539                 :          13 :   gcc::diagnostics_output_spec::output_factory factory;
     540                 :          13 :   auto sink = factory.make_sink (ctxt, arg, *result);
     541                 :          13 :   if (!sink)
     542                 :           0 :     return;
     543                 :             : 
     544                 :          13 :   dc.set_output_format (std::move (sink));
     545                 :          13 : }
     546                 :             : 
     547                 :             : #if CHECKING_P
     548                 :             : 
     549                 :             : namespace selftest {
     550                 :             : 
     551                 :             : /* RAII class to temporarily override "progname" to the
     552                 :             :    string "PROGNAME".  */
     553                 :             : 
     554                 :             : class auto_fix_progname
     555                 :             : {
     556                 :             : public:
     557                 :           4 :   auto_fix_progname ()
     558                 :           4 :   {
     559                 :           4 :     m_old_progname = progname;
     560                 :           4 :     progname = "PROGNAME";
     561                 :             :   }
     562                 :             : 
     563                 :           4 :   ~auto_fix_progname ()
     564                 :             :   {
     565                 :           4 :     progname = m_old_progname;
     566                 :           4 :   }
     567                 :             : 
     568                 :             : private:
     569                 :             :   const char *m_old_progname;
     570                 :             : };
     571                 :             : 
     572                 :          56 : struct parser_test
     573                 :             : {
     574                 :          28 :   parser_test ()
     575                 :          28 :   : m_opts (),
     576                 :          28 :     m_dc (),
     577                 :          28 :     m_ctxt (m_opts, m_dc, line_table, UNKNOWN_LOCATION, "-fOPTION="),
     578                 :          28 :     m_fmt (m_dc.get_output_format (0))
     579                 :             :   {
     580                 :          28 :     pp_buffer (m_fmt.get_printer ())->m_flush_p = false;
     581                 :          28 :   }
     582                 :             : 
     583                 :             :   std::unique_ptr<gcc::diagnostics_output_spec::scheme_name_and_params>
     584                 :          28 :   parse (const char *unparsed_arg)
     585                 :             :   {
     586                 :          28 :     return gcc::diagnostics_output_spec::parse (m_ctxt, unparsed_arg);
     587                 :             :   }
     588                 :             : 
     589                 :          28 :   bool execution_failed_p () const
     590                 :             :   {
     591                 :          28 :     return m_dc.execution_failed_p ();
     592                 :             :   }
     593                 :             : 
     594                 :             :   const char *
     595                 :          16 :   get_diagnostic_text () const
     596                 :             :   {
     597                 :          16 :     return pp_formatted_text (m_fmt.get_printer ());
     598                 :             :   }
     599                 :             : 
     600                 :             : private:
     601                 :             :   const gcc_options m_opts;
     602                 :             :   test_diagnostic_context m_dc;
     603                 :             :   gcc::diagnostics_output_spec::context m_ctxt;
     604                 :             :   diagnostic_output_format &m_fmt;
     605                 :             : };
     606                 :             : 
     607                 :             : /* Selftests.  */
     608                 :             : 
     609                 :             : static void
     610                 :           4 : test_output_arg_parsing ()
     611                 :             : {
     612                 :           4 :   auto_fix_quotes fix_quotes;
     613                 :           4 :   auto_fix_progname fix_progname;
     614                 :             : 
     615                 :             :   /* Minimal correct example.  */
     616                 :           4 :   {
     617                 :           4 :     parser_test pt;
     618                 :           4 :     auto result = pt.parse ("foo");
     619                 :           4 :     ASSERT_EQ (result->m_scheme_name, "foo");
     620                 :           4 :     ASSERT_EQ (result->m_kvs.size (), 0);
     621                 :           4 :     ASSERT_FALSE (pt.execution_failed_p ());
     622                 :           4 :   }
     623                 :             : 
     624                 :             :   /* Stray trailing colon with no key/value pairs.  */
     625                 :           4 :   {
     626                 :           4 :     parser_test pt;
     627                 :           4 :     auto result = pt.parse ("foo:");
     628                 :           4 :     ASSERT_EQ (result, nullptr);
     629                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     630                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     631                 :             :                   "PROGNAME: error: `-fOPTION=foo:':"
     632                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     633                 :             :                   " after `:';"
     634                 :             :                   " got `'\n");
     635                 :           4 :   }
     636                 :             : 
     637                 :             :   /* No key before '='.  */
     638                 :           4 :   {
     639                 :           4 :     parser_test pt;
     640                 :           4 :     auto result = pt.parse ("foo:=");
     641                 :           4 :     ASSERT_EQ (result, nullptr);
     642                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     643                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     644                 :             :                   "PROGNAME: error: `-fOPTION=foo:=':"
     645                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     646                 :             :                   " after `:';"
     647                 :             :                   " got `='\n");
     648                 :           4 :   }
     649                 :             : 
     650                 :             :   /* No value for key.  */
     651                 :           4 :   {
     652                 :           4 :     parser_test pt;
     653                 :           4 :     auto result = pt.parse ("foo:key,");
     654                 :           4 :     ASSERT_EQ (result, nullptr);
     655                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     656                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     657                 :             :                   "PROGNAME: error: `-fOPTION=foo:key,':"
     658                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     659                 :             :                   " after `:';"
     660                 :             :                   " got `key,'\n");
     661                 :           4 :   }
     662                 :             : 
     663                 :             :   /* Correct example, with one key/value pair.  */
     664                 :           4 :   {
     665                 :           4 :     parser_test pt;
     666                 :           4 :     auto result = pt.parse ("foo:key=value");
     667                 :           4 :     ASSERT_EQ (result->m_scheme_name, "foo");
     668                 :           4 :     ASSERT_EQ (result->m_kvs.size (), 1);
     669                 :           4 :     ASSERT_EQ (result->m_kvs[0].first, "key");
     670                 :           4 :     ASSERT_EQ (result->m_kvs[0].second, "value");
     671                 :           4 :     ASSERT_FALSE (pt.execution_failed_p ());
     672                 :           4 :   }
     673                 :             : 
     674                 :             :   /* Stray trailing comma.  */
     675                 :           4 :   {
     676                 :           4 :     parser_test pt;
     677                 :           4 :     auto result = pt.parse ("foo:key=value,");
     678                 :           4 :     ASSERT_EQ (result, nullptr);
     679                 :           4 :     ASSERT_TRUE (pt.execution_failed_p ());
     680                 :           4 :     ASSERT_STREQ (pt.get_diagnostic_text (),
     681                 :             :                   "PROGNAME: error: `-fOPTION=foo:key=value,':"
     682                 :             :                   " expected KEY=VALUE-style parameter for format `foo'"
     683                 :             :                   " after `,';"
     684                 :             :                   " got `'\n");
     685                 :           4 :   }
     686                 :             : 
     687                 :             :   /* Correct example, with two key/value pairs.  */
     688                 :           4 :   {
     689                 :           4 :     parser_test pt;
     690                 :           4 :     auto result = pt.parse ("foo:color=red,shape=circle");
     691                 :           4 :     ASSERT_EQ (result->m_scheme_name, "foo");
     692                 :           4 :     ASSERT_EQ (result->m_kvs.size (), 2);
     693                 :           4 :     ASSERT_EQ (result->m_kvs[0].first, "color");
     694                 :           4 :     ASSERT_EQ (result->m_kvs[0].second, "red");
     695                 :           4 :     ASSERT_EQ (result->m_kvs[1].first, "shape");
     696                 :           4 :     ASSERT_EQ (result->m_kvs[1].second, "circle");
     697                 :           4 :     ASSERT_FALSE (pt.execution_failed_p ());
     698                 :           4 :   }
     699                 :           4 : }
     700                 :             : 
     701                 :             : /* Run all of the selftests within this file.  */
     702                 :             : 
     703                 :             : void
     704                 :           4 : opts_diagnostic_cc_tests ()
     705                 :             : {
     706                 :           4 :   test_output_arg_parsing ();
     707                 :           4 : }
     708                 :             : 
     709                 :             : } // namespace selftest
     710                 :             : 
     711                 :             : #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.