@@ -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.
@@ -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;
@@ -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;
@@ -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 */
@@ -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);
@@ -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;
@@ -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
@@ -2872,6 +2872,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;
@@ -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\\\]" } */
}
@@ -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");
}
@@ -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
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 | 4 ++ gcc/diagnostic-format-json.cc | 1 + gcc/diagnostic-format-sarif.cc | 1 + gcc/diagnostic-metadata.h | 47 +++++++++++++++++- gcc/diagnostic.cc | 48 +++++++++++++++++++ gcc/diagnostic.h | 3 ++ gcc/doc/invoke.texi | 10 ++++ gcc/opts.cc | 4 ++ .../gcc.dg/plugin/diagnostic-test-metadata.c | 2 +- .../plugin/diagnostic_plugin_test_metadata.c | 9 +++- gcc/toplev.cc | 2 + 11 files changed, 127 insertions(+), 4 deletions(-)