]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
diagnostics: add ability to associate diagnostics with rules from coding standards
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 23 Jun 2022 18:59:24 +0000 (14:59 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 23 Jun 2022 18:59:24 +0000 (14:59 -0400)
gcc/ChangeLog:
* common.opt (fdiagnostics-show-rules): New option.
* diagnostic-format-json.cc (diagnostic_output_format_init_json):
Fix up context->show_rules.
* diagnostic-format-sarif.cc
(diagnostic_output_format_init_sarif): Likewise.
* diagnostic-metadata.h (diagnostic_metadata::rule): New class.
(diagnostic_metadata::precanned_rule): New class.
(diagnostic_metadata::add_rule): New.
(diagnostic_metadata::get_num_rules): New.
(diagnostic_metadata::get_rule): New.
(diagnostic_metadata::m_rules): New field.
* diagnostic.cc (diagnostic_initialize): Initialize show_rules.
(print_any_rules): New.
(diagnostic_report_diagnostic): Call it.
* diagnostic.h (diagnostic_context::show_rules): New field.
* doc/invoke.texi (-fno-diagnostics-show-rules): New option.
* opts.cc (common_handle_option): Handle
OPT_fdiagnostics_show_rules.
* toplev.cc (general_init): Set up global_dc->show_rules.

gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic-test-metadata.c: Expect " [STR34-C]" to
be emitted at the "gets" call.
* gcc.dg/plugin/diagnostic_plugin_test_metadata.c
(pass_test_metadata::execute): Associate the "gets" diagnostic
with a rule named "STR34-C".

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/common.opt
gcc/diagnostic-format-json.cc
gcc/diagnostic-format-sarif.cc
gcc/diagnostic-metadata.h
gcc/diagnostic.cc
gcc/diagnostic.h
gcc/doc/invoke.texi
gcc/opts.cc
gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata.c
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.c
gcc/toplev.cc

index da5d23d1de83d9d2a5e6d29dba20bd6f5c7cec40..ed50f77848ddda18bad13a37543bf7370f130522 100644 (file)
@@ -1466,6 +1466,10 @@ fdiagnostics-show-cwe
 Common Var(flag_diagnostics_show_cwe) Init(1)
 Print CWE identifiers for diagnostic messages, where available.
 
+fdiagnostics-show-rules
+Common Var(flag_diagnostics_show_rules) Init(1)
+Print any rules associated with diagnostic messages.
+
 fdiagnostics-path-format=
 Common Joined RejectNegative Var(flag_diagnostics_path_format) Enum(diagnostic_path_format) Init(DPF_INLINE_EVENTS)
 Specify how to print any control-flow path associated with a diagnostic.
index 051fa6c2e487b482421017db442447b894bf5fe6..d1d8d3f2081172e1a24c868045625d9d264fccf5 100644 (file)
@@ -345,6 +345,7 @@ diagnostic_output_format_init_json (diagnostic_context *context)
 
   /* The metadata is handled in JSON format, rather than as text.  */
   context->show_cwe = false;
+  context->show_rules = false;
 
   /* The option is handled in JSON format, rather than as text.  */
   context->show_option_requested = false;
index 0c33179e8cfbc4349639acb60821ef18c23434e0..a7bb9fb639d6dc37fd7559525f25fe26fc3dac91 100644 (file)
@@ -1556,6 +1556,7 @@ diagnostic_output_format_init_sarif (diagnostic_context *context)
 
   /* The metadata is handled in SARIF format, rather than as text.  */
   context->show_cwe = false;
+  context->show_rules = false;
 
   /* The option is handled in SARIF format, rather than as text.  */
   context->show_option_requested = false;
index ae59942c65ec1737fceaf382613db238de504cc6..80017d35fa9d068b6d79386ac42d1c57e92c5a90 100644 (file)
@@ -24,19 +24,62 @@ along with GCC; see the file COPYING3.  If not see
 /* A bundle of additional metadata that can be associated with a
    diagnostic.
 
-   Currently this only supports associating a CWE identifier with a
-   diagnostic.  */
+   This supports an optional CWE identifier, and zero or more
+   "rules".  */
 
 class diagnostic_metadata
 {
  public:
+  /* Abstract base class for referencing a rule that has been violated,
+     such as within a coding standard, or within a specification.  */
+  class rule
+  {
+  public:
+    virtual char *make_description () const = 0;
+    virtual char *make_url () const = 0;
+  };
+
+  /* Concrete subclass.  */
+  class precanned_rule : public rule
+  {
+  public:
+    precanned_rule (const char *desc, const char *url)
+    : m_desc (desc), m_url (url)
+    {}
+
+    char *make_description () const final override
+    {
+      return m_desc ? xstrdup (m_desc) : NULL;
+    }
+
+    char *make_url () const final override
+    {
+      return m_url ? xstrdup (m_url) : NULL;
+    }
+
+  private:
+    const char *m_desc;
+    const char *m_url;
+  };
+
   diagnostic_metadata () : m_cwe (0) {}
 
   void add_cwe (int cwe) { m_cwe = cwe; }
   int get_cwe () const { return m_cwe; }
 
+  /* Associate R with the diagnostic.  R must outlive
+     the metadata.  */
+  void add_rule (const rule &r)
+  {
+    m_rules.safe_push (&r);
+  }
+
+  unsigned get_num_rules () const { return m_rules.length (); }
+  const rule &get_rule (unsigned idx) const { return *(m_rules[idx]); }
+
  private:
   int m_cwe;
+  auto_vec<const rule *> m_rules;
 };
 
 #endif /* ! GCC_DIAGNOSTIC_METADATA_H */
index f2a82fff46290d2cc56ec8679116de3757e00c0b..22f7b0b6d6ed8d1faeb540ed0e85d0f267f82a9c 100644 (file)
@@ -190,6 +190,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
   for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
     context->caret_chars[i] = '^';
   context->show_cwe = false;
+  context->show_rules = false;
   context->path_format = DPF_NONE;
   context->show_path_depths = false;
   context->show_option_requested = false;
@@ -1291,6 +1292,51 @@ print_any_cwe (diagnostic_context *context,
     }
 }
 
+/* If DIAGNOSTIC has any rules associated with it, print them.
+
+   For example, if the diagnostic metadata associates it with a rule
+   named "STR34-C", then " [STR34-C]" will be printed, suitably colorized,
+   with any URL provided by the rule.  */
+
+static void
+print_any_rules (diagnostic_context *context,
+               const diagnostic_info *diagnostic)
+{
+  if (diagnostic->metadata == NULL)
+    return;
+
+  for (unsigned idx = 0; idx < diagnostic->metadata->get_num_rules (); idx++)
+    {
+      const diagnostic_metadata::rule &rule
+       = diagnostic->metadata->get_rule (idx);
+      if (char *desc = rule.make_description ())
+       {
+         pretty_printer *pp = context->printer;
+         char *saved_prefix = pp_take_prefix (context->printer);
+         pp_string (pp, " [");
+         pp_string (pp,
+                    colorize_start (pp_show_color (pp),
+                                    diagnostic_kind_color[diagnostic->kind]));
+         char *url = NULL;
+         if (pp->url_format != URL_FORMAT_NONE)
+           {
+             url = rule.make_url ();
+             if (url)
+               pp_begin_url (pp, url);
+           }
+         pp_string (pp, desc);
+         pp_set_prefix (context->printer, saved_prefix);
+         if (pp->url_format != URL_FORMAT_NONE)
+           if (url)
+             pp_end_url (pp);
+         free (url);
+         pp_string (pp, colorize_stop (pp_show_color (pp)));
+         pp_character (pp, ']');
+         free (desc);
+       }
+    }
+}
+
 /* Print any metadata about the option used to control DIAGNOSTIC to CONTEXT's
    printer, e.g. " [-Werror=uninitialized]".
    Subroutine of diagnostic_report_diagnostic.  */
@@ -1504,6 +1550,8 @@ diagnostic_report_diagnostic (diagnostic_context *context,
   pp_output_formatted_text (context->printer);
   if (context->show_cwe)
     print_any_cwe (context, diagnostic);
+  if (context->show_rules)
+    print_any_rules (context, diagnostic);
   if (context->show_option_requested)
     print_option_information (context, diagnostic, orig_diag_kind);
   (*diagnostic_finalizer (context)) (context, diagnostic, orig_diag_kind);
index 96c9a7202f9750eaa511e4ac624ec2c4f551ed5b..ae6f2dfb7f43e36224b767ade795aaa4fbfca5dc 100644 (file)
@@ -227,6 +227,9 @@ struct diagnostic_context
      diagnostics.  */
   bool show_cwe;
 
+  /* True if we should print any rules associated with diagnostics.  */
+  bool show_rules;
+
   /* How should diagnostic_path objects be printed.  */
   enum diagnostic_path_format path_format;
 
index e7526c5a58eef790aaac277768789e65c5f1756f..07a1bf40ad942ddd9dcd973c3eb052931391ca9e 100644 (file)
@@ -305,6 +305,7 @@ Objective-C and Objective-C++ Dialects}.
 -fno-diagnostics-show-option  -fno-diagnostics-show-caret @gol
 -fno-diagnostics-show-labels  -fno-diagnostics-show-line-numbers @gol
 -fno-diagnostics-show-cwe  @gol
+-fno-diagnostics-show-rule  @gol
 -fdiagnostics-minimum-margin-width=@var{width} @gol
 -fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch @gol
 -fdiagnostics-show-template-tree  -fno-elide-type @gol
@@ -5028,6 +5029,15 @@ diagnostics.  GCC plugins may also provide diagnostics with such metadata.
 By default, if this information is present, it will be printed with
 the diagnostic.  This option suppresses the printing of this metadata.
 
+@item -fno-diagnostics-show-rules
+@opindex fno-diagnostics-show-rules
+@opindex fdiagnostics-show-rules
+Diagnostic messages can optionally have rules associated with them, such
+as from a coding standard, or a specification.
+GCC itself does not do this for any of its diagnostics, but plugins may do so.
+By default, if this information is present, it will be printed with
+the diagnostic.  This option suppresses the printing of this metadata.
+
 @item -fno-diagnostics-show-line-numbers
 @opindex fno-diagnostics-show-line-numbers
 @opindex fdiagnostics-show-line-numbers
index 9982974c8b5089a617612cecd93cd8f4d17c2267..fe0293e4283df41248dfdfb572c60b9ae9b6e437 100644 (file)
@@ -2876,6 +2876,10 @@ common_handle_option (struct gcc_options *opts,
       dc->show_cwe = value;
       break;
 
+    case OPT_fdiagnostics_show_rules:
+      dc->show_rules = value;
+      break;
+
     case OPT_fdiagnostics_path_format_:
       dc->path_format = (enum diagnostic_path_format)value;
       break;
index d2babd357539a50e97364fb95ed2fb7967f5cef9..38ecf0a6d95b923cf2cc01488b58be8255de8a1a 100644 (file)
@@ -5,5 +5,5 @@ extern char *gets (char *s);
 void test_cwe (void)
 {
   char buf[1024];
-  gets (buf); /* { dg-warning "never use 'gets' \\\[CWE-242\\\]" } */
+  gets (buf); /* { dg-warning "never use 'gets' \\\[CWE-242\\\] \\\[STR34-C\\\]" } */
 }
index 4b13afc093d589c0be1e031e01c13238749c721b..b86a8b3650ef82bb69b52a576285abb96922baa8 100644 (file)
@@ -106,9 +106,16 @@ pass_test_metadata::execute (function *fun)
        if (gcall *call = check_for_named_call (stmt, "gets", 1))
          {
            gcc_rich_location richloc (gimple_location (call));
-           /* CWE-242: Use of Inherently Dangerous Function.  */
            diagnostic_metadata m;
+
+           /* CWE-242: Use of Inherently Dangerous Function.  */
            m.add_cwe (242);
+
+           /* Example of a diagnostic_metadata::rule.  */
+           diagnostic_metadata::precanned_rule
+             test_rule ("STR34-C", "https://example.com/");
+           m.add_rule (test_rule);
+
            warning_meta (&richloc, m, 0,
                          "never use %qs", "gets");
          }
index 055e0642f775d5e6d0aa80863678cf492a4e1657..a24ad5db43854e956b67006173cb198d026cf177 100644 (file)
@@ -1038,6 +1038,8 @@ general_init (const char *argv0, bool init_signals)
     = global_options_init.x_flag_diagnostics_show_line_numbers;
   global_dc->show_cwe
     = global_options_init.x_flag_diagnostics_show_cwe;
+  global_dc->show_rules
+    = global_options_init.x_flag_diagnostics_show_rules;
   global_dc->path_format
     = (enum diagnostic_path_format)global_options_init.x_flag_diagnostics_path_format;
   global_dc->show_path_depths