From a9fe04327a7c24634a3657639d661a04317dbdf7 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 18 Jul 2017 17:15:11 -0400
Subject: [PATCH 06/27] C: use BLT to highlight parameter of callee decl for
 mismatching types

This patch to the C frontend uses the BLT infrastructure to improve:

  extern int callee_1 (int one, const char *two, float three);

  int test_1 (int first, int second, float third)
  {
    return callee_1 (first, second, third);
  }

from:

  warning: passing argument 2 of 'callee_1' makes pointer from integer without a cast [-Wint-conversion]
   return callee_1 (first, second, third);
                           ^~~~~~
  note: expected 'const char *' but argument is of type 'int'
   extern int callee_1 (int one, const char *two, float three);
              ^~~~~~~~

to:

  warning: passing argument 2 of 'callee_1' makes pointer from integer without a cast [-Wint-conversion]
   return callee_1 (first, second, third);
                           ^~~~~~
  note: expected 'const char *' but argument is of type 'int'
   extern int callee_1 (int one, const char *two, float three);
                                 ^~~~~~~~~~~~~~~

by locating the pertinent parameter within the decl, by traversing the
BLT tree (if present).

gcc/c/ChangeLog:
	* c-typeck.c: Include "blt.h".
	(get_fndecl_argument_location): New function.
	(convert_for_assignment): Replace calls to "inform" with...
	(inform_for_arg): ...this new function, attempting to highlight
	the pertinent parameter.

gcc/testsuite/ChangeLog:
	* gcc.dg/param-type-mismatch.c: Add -fblt to options.  Update
	expected underlining to show the pertinent parameters.
---
 gcc/c/c-typeck.c                           | 63 ++++++++++++++++++++++++------
 gcc/testsuite/gcc.dg/param-type-mismatch.c | 13 +++---
 2 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 4d067e9..c37cc33 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
 #include "asan.h"
+#include "blt.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
    diagnostic messages in convert_for_assignment.  */
@@ -6112,6 +6113,53 @@ maybe_warn_string_init (location_t loc, tree type, struct c_expr expr)
 		  "array initialized from parenthesized string constant");
 }
 
+/* Attempt to locate the parameter with the given index within FNDECL,
+   returning LOC if it can't be found (or blt was not enabled).  */
+
+static location_t
+get_fndecl_argument_location (tree fundecl, int argnum, location_t loc)
+{
+  blt_node *node = blt_get_node_for_tree (fundecl);
+  if (!node)
+    return loc;
+
+  if (node->get_kind () != BLT_DIRECT_DECLARATOR)
+    return loc;
+
+  /* We expect a parameter-list containing parameter-declaration.  */
+  node = node->get_first_child_of_kind (BLT_PARAMETER_LIST);
+  if (!node)
+    return loc;
+
+  auto_vec<blt_node *> params;
+  node->get_children_of_kind (params, BLT_PARAMETER_DECLARATION);
+
+  if (argnum >= (int)params.length ())
+    return loc;
+
+  blt_node *param = params[argnum];
+  return param->get_range ();
+}
+
+/* Issue a note about a mismatching argument for parameter PARMNUM
+   to FUNDECL, for types EXPECTED_TYPE and ACTUAL_TYPE.
+   Attempt to issue the note at the pertinent parameter of the decl;
+   failing that issue it at the location of FUNDECL; failing that
+   issue it at PLOC.  */
+
+static void
+inform_for_arg (tree fundecl, location_t ploc, int parmnum,
+		tree expected_type, tree actual_type)
+{
+  location_t loc = (fundecl && !DECL_IS_BUILTIN (fundecl)
+		    ? DECL_SOURCE_LOCATION (fundecl) : ploc);
+  loc = get_fndecl_argument_location (fundecl, parmnum - 1, loc);
+
+  inform (loc,
+	  "expected %qT but argument is of type %qT",
+	  expected_type, actual_type);
+}
+
 /* Convert value RHS to type TYPE as preparation for an assignment to
    an lvalue of type TYPE.  If ORIGTYPE is not NULL_TREE, it is the
    original type of RHS; this differs from TREE_TYPE (RHS) for enum
@@ -6183,10 +6231,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
       {                                                                  \
       case ic_argpass:                                                   \
         if (pedwarn (PLOC, OPT, AR, parmnum, rname))			 \
-          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))	         \
-		  ? DECL_SOURCE_LOCATION (fundecl) : PLOC,		 \
-                  "expected %qT but argument is of type %qT",            \
-                  type, rhstype);                                        \
+          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);	\
         break;                                                           \
       case ic_assign:                                                    \
         pedwarn (LOCATION, OPT, AS);                                     \
@@ -6212,10 +6257,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
       {                                                                  \
       case ic_argpass:                                                   \
         if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))		 \
-          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))	         \
-		  ? DECL_SOURCE_LOCATION (fundecl) : PLOC,		 \
-                  "expected %qT but argument is of type %qT",            \
-                  type, rhstype);                                        \
+          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);	\
         break;                                                           \
       case ic_assign:                                                    \
         pedwarn (LOCATION, OPT, AS, QUALS);				 \
@@ -6241,10 +6283,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
       {                                                                  \
       case ic_argpass:                                                   \
         if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))           \
-          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))                \
-                  ? DECL_SOURCE_LOCATION (fundecl) : PLOC,               \
-                  "expected %qT but argument is of type %qT",            \
-                  type, rhstype);                                        \
+          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);      \
         break;                                                           \
       case ic_assign:                                                    \
         warning_at (LOCATION, OPT, AS, QUALS);                           \
diff --git a/gcc/testsuite/gcc.dg/param-type-mismatch.c b/gcc/testsuite/gcc.dg/param-type-mismatch.c
index 70ea0bc..eb3169b 100644
--- a/gcc/testsuite/gcc.dg/param-type-mismatch.c
+++ b/gcc/testsuite/gcc.dg/param-type-mismatch.c
@@ -1,9 +1,6 @@
-/* { dg-options "-fdiagnostics-show-caret" }  */
+/* { dg-options "-fdiagnostics-show-caret -fblt" }  */
 
-/* A collection of calls where argument 2 is of the wrong type.
-
-   TODO: we should highlight the second parameter of the callee, rather
-   than its name.  */
+/* A collection of calls where argument 2 is of the wrong type.  */
 
 /* decl, with argname.  */
 
@@ -19,7 +16,7 @@ int test_1 (int first, int second, float third)
   /* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_1 } */
   /* { dg-begin-multiline-output "" }
  extern int callee_1 (int one, const char *two, float three);
-            ^~~~~~~~
+                               ^~~~~~~~~~~~~~~
      { dg-end-multiline-output "" } */
 }
 
@@ -37,7 +34,7 @@ int test_2 (int first, int second, float third)
   /* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_2 } */
   /* { dg-begin-multiline-output "" }
  extern int callee_2 (int, const char *, float);
-            ^~~~~~~~
+                           ^~~~~~~~~~~~
      { dg-end-multiline-output "" } */
 }
 
@@ -58,6 +55,6 @@ int test_3 (int first, int second, float third)
   /* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_3 } */
   /* { dg-begin-multiline-output "" }
  static int callee_3 (int one, const char *two, float three)
-            ^~~~~~~~
+                               ^~~~~~~~~~~~~~~
      { dg-end-multiline-output "" } */
 }
-- 
1.8.5.3

