From ee1e21b49d00aeec0d132d8f9b4015167610fb22 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 2 Aug 2017 15:00:47 -0400
Subject: [PATCH 05/22] diagnostic.c/h: add support for external tools

This patch adds fields "external_tool" and "external_test_id"
to diagnostic_info, allowing for diagnostics to be marked as
coming from a 3rd-party tool.

Instead of printing the pertinent warning flag e.g.:

  foo.c:10:1: something is wrong [-Wpointer-arith]

the tool "ID" and (optionally) test ID is printed e.g.:

  foo.c:10:1: something is wrong [cppcheck:memleak]

gcc/ChangeLog:
	* diagnostic-show-locus.c: Include "selftest-diagnostic.h".
	(class selftest::test_diagnostic_context): Move to
	selftest-diagnostic.h.
	* diagnostic.c: Include "selftest-diagnostic.h".
	(diagnostic_info::diagnostic_info): New ctor.
	(print_option_information): Handle external_tool and
	external_test_id fields of diagnostic_info.
	(diagnostic_report_diagnostic): Assert that diagnostic->kind is
	not DK_UNSPECIFIED.
	(selftest::dummy_option_name_cb): New function.
	(selftest::assert_option_information): New function.
	(selftest::test_print_option_information): New function.
	(selftest::diagnostic_c_tests): Call
	selftest::test_print_option_information.
	* diagnostic.h (struct diagnostic_info): Add default ctor,
	along with new fields "external_tool" and "external_test_id".
	* selftest-diagnostic.h: New file.
---
 gcc/diagnostic-show-locus.c | 29 +---------------
 gcc/diagnostic.c            | 85 ++++++++++++++++++++++++++++++++++++++++++---
 gcc/diagnostic.h            |  5 +++
 gcc/selftest-diagnostic.h   | 62 +++++++++++++++++++++++++++++++++
 4 files changed, 149 insertions(+), 32 deletions(-)
 create mode 100644 gcc/selftest-diagnostic.h

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index b0e72e7..08b2e56 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-color.h"
 #include "gcc-rich-location.h"
 #include "selftest.h"
+#include "selftest-diagnostic.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -1988,34 +1989,6 @@ namespace selftest {
 
 /* Selftests for diagnostic_show_locus.  */
 
-/* Convenience subclass of diagnostic_context for testing
-   diagnostic_show_locus.  */
-
-class test_diagnostic_context : public diagnostic_context
-{
- public:
-  test_diagnostic_context ()
-  {
-    diagnostic_initialize (this, 0);
-    show_caret = true;
-    show_column = true;
-    start_span = start_span_cb;
-  }
-  ~test_diagnostic_context ()
-  {
-    diagnostic_finish (this);
-  }
-
-  /* Implementation of diagnostic_start_span_fn, hiding the
-     real filename (to avoid printing the names of tempfiles).  */
-  static void
-  start_span_cb (diagnostic_context *context, expanded_location exploc)
-  {
-    exploc.file = "FILENAME";
-    default_diagnostic_start_span_fn (context, exploc);
-  }
-};
-
 /* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION.  */
 
 static void
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index bbf5f5c..570f8c2 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-color.h"
 #include "edit-context.h"
 #include "selftest.h"
+#include "selftest-diagnostic.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -67,7 +68,17 @@ const char *progname;
 /* A diagnostic_context surrogate for stderr.  */
 static diagnostic_context global_diagnostic_context;
 diagnostic_context *global_dc = &global_diagnostic_context;
+
 
+
+/* diagnostic_info's ctor.  */
+
+diagnostic_info::diagnostic_info ()
+: message (), richloc (NULL), x_data (NULL), kind (DK_UNSPECIFIED),
+  option_index (0), external_tool (NULL), external_test_id (NULL)
+{
+}
+
 /* Return a malloc'd string containing MSG formatted a la printf.  The
    caller is responsible for freeing the memory.  */
 char *
@@ -843,6 +854,28 @@ print_option_information (diagnostic_context *context,
 			  const diagnostic_info *diagnostic,
 			  diagnostic_t orig_diag_kind)
 {
+  pretty_printer *pp = context->printer;
+  const char *cs = colorize_start (pp_show_color (pp),
+				   diagnostic_kind_color[diagnostic->kind]);
+  const char *ce = colorize_stop (pp_show_color (pp));
+
+  if (diagnostic->external_tool)
+    {
+      pp_string (pp, " [");
+      pp_string (pp, cs);
+      pp_string (pp, diagnostic->external_tool);
+      pp_string (pp, ce);
+      if (diagnostic->external_test_id)
+	{
+	  pp_character (pp, ':');
+	  pp_string (pp, cs);
+	  pp_string (pp, diagnostic->external_test_id);
+	  pp_string (pp, ce);
+	}
+      pp_character (pp, ']');
+      return;
+    }
+
   char *option_text;
 
   option_text = context->option_name (context, diagnostic->option_index,
@@ -850,12 +883,10 @@ print_option_information (diagnostic_context *context,
 
   if (option_text)
     {
-      pretty_printer *pp = context->printer;
       pp_string (pp, " [");
-      pp_string (pp, colorize_start (pp_show_color (pp),
-				     diagnostic_kind_color[diagnostic->kind]));
+      pp_string (pp, cs);
       pp_string (pp, option_text);
-      pp_string (pp, colorize_stop (pp_show_color (pp)));
+      pp_string (pp, ce);
       pp_character (pp, ']');
       free (option_text);
     }
@@ -875,6 +906,8 @@ diagnostic_report_diagnostic (diagnostic_context *context,
   location_t location = diagnostic_location (diagnostic);
   diagnostic_t orig_diag_kind = diagnostic->kind;
 
+  gcc_assert (diagnostic->kind != DK_UNSPECIFIED);
+
   /* Give preference to being able to inhibit warnings, before they
      get reclassified to something else.  */
   if ((diagnostic->kind == DK_WARNING || diagnostic->kind == DK_PEDWARN)
@@ -1490,6 +1523,49 @@ real_abort (void)
 
 namespace selftest {
 
+/* A dummy diagnostic_context::option_name callback that always
+   returns a copy of "-Woption-name-goes-here".  */
+
+char *
+dummy_option_name_cb (diagnostic_context *, int, diagnostic_t, diagnostic_t)
+{
+  return xstrdup ("-Woption-name-goes-here");
+}
+
+/* Verify that print_option_information on DIAGNOSTIC prints
+   EXPECTED.  */
+
+static void
+assert_option_information (diagnostic_info *diagnostic,
+			   const char *expected)
+{
+  test_diagnostic_context dc;
+  dc.option_name = dummy_option_name_cb;
+  print_option_information (&dc, diagnostic, DK_WARNING);
+  ASSERT_STREQ (expected, pp_formatted_text (dc.printer));
+}
+
+/* Verify that print_option_information does the right thing.  */
+
+static void
+test_print_option_information ()
+{
+  diagnostic_info diagnostic;
+  diagnostic.kind = DK_WARNING;
+
+  /* A built-in warning.  */
+  assert_option_information (&diagnostic, " [-Woption-name-goes-here]");
+
+  /* An external tool, without a test ID.  */
+  diagnostic.external_tool = "external-tool-name";
+  assert_option_information (&diagnostic, " [external-tool-name]");
+
+  /* An external tool, with a test ID.  */
+  diagnostic.external_test_id = "external-test-id";
+  assert_option_information (&diagnostic,
+			     " [external-tool-name:external-test-id]");
+}
+
 /* Helper function for test_print_escaped_string.  */
 
 static void
@@ -1621,6 +1697,7 @@ test_print_parseable_fixits_replace ()
 void
 diagnostic_c_tests ()
 {
+  test_print_option_information ();
   test_print_escaped_string ();
   test_print_parseable_fixits_none ();
   test_print_parseable_fixits_insert ();
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index dbd1703..0127a6c 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -29,6 +29,8 @@ along with GCC; see the file COPYING3.  If not see
    list in diagnostic.def.  */
 struct diagnostic_info
 {
+  diagnostic_info ();
+
   /* Text to be formatted.  */
   text_info message;
 
@@ -41,6 +43,9 @@ struct diagnostic_info
   diagnostic_t kind;
   /* Which OPT_* directly controls this diagnostic.  */
   int option_index;
+
+  const char *external_tool;
+  const char *external_test_id;
 };
 
 /* Each time a diagnostic's classification is changed with a pragma,
diff --git a/gcc/selftest-diagnostic.h b/gcc/selftest-diagnostic.h
new file mode 100644
index 0000000..78bc5cf
--- /dev/null
+++ b/gcc/selftest-diagnostic.h
@@ -0,0 +1,62 @@
+/* Support for selftests of diagnostics.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_SELFTEST_DIAGNOSTIC_H
+#define GCC_SELFTEST_DIAGNOSTIC_H
+
+/* The selftest code should entirely disappear in a production
+   configuration, hence we guard all of it with #if CHECKING_P.  */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Convenience subclass of diagnostic_context for testing
+   diagnostic_show_locus etc.  */
+
+class test_diagnostic_context : public diagnostic_context
+{
+ public:
+  test_diagnostic_context ()
+  {
+    diagnostic_initialize (this, 0);
+    show_caret = true;
+    show_column = true;
+    start_span = start_span_cb;
+  }
+  ~test_diagnostic_context ()
+  {
+    diagnostic_finish (this);
+  }
+
+  /* Implementation of diagnostic_start_span_fn, hiding the
+     real filename (to avoid printing the names of tempfiles).  */
+  static void
+  start_span_cb (diagnostic_context *context, expanded_location exploc)
+  {
+    exploc.file = "FILENAME";
+    default_diagnostic_start_span_fn (context, exploc);
+  }
+};
+
+} /* end of namespace selftest.  */
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_DIAGNOSTIC_H */
-- 
1.8.5.3

