Consider:

  class t1
  {
  public:
    double length () const { return m_length; }
  private:
    double m_length;
  };

missing-parens-fixit.C: In function 'bool test_1(const t1&)':
missing-parens-fixit.C:14:15: error: invalid use of member function
  'double t1::length() const' (did you forget the '()' ?)
   14 |   return inst.length > 0.0;
      |          ~~~~~^~~~~~

This patch adds a fix-it hint for the case where the member function
takes no parameters, suggesting the addition of the parentheses:

   14 |   return inst.length > 0.0;
      |          ~~~~~^~~~~~
      |                     ()

so that an IDE can potentially apply the fix.

OK for trunk?

gcc/cp/ChangeLog:
        * typeck2.c: Include "gcc-rich-location.h".
        (cxx_incomplete_type_diagnostic): When complaining about possibly
        missing parens, add a fix-it hint if the member function takes no
        additional params.

gcc/ChangeLog:
        * diagnostic-core.h (emit_diagnostic): New decl.
        * diagnostic.c (emit_diagnostic): New overload, taking a
        rich_location *.

gcc/testsuite/ChangeLog:
        * g++.dg/parse/missing-parens-fixit.C: New test.
---
 gcc/cp/typeck2.c                                  | 14 +++++++---
 gcc/diagnostic-core.h                             |  2 ++
 gcc/diagnostic.c                                  | 14 ++++++++++
 gcc/testsuite/g++.dg/parse/missing-parens-fixit.C | 32 +++++++++++++++++++++++
 4 files changed, 59 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/parse/missing-parens-fixit.C

diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index fec1db0..c3c59a8 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "varasm.h"
 #include "intl.h"
+#include "gcc-rich-location.h"
 
 static tree
 process_init_constructor (tree type, tree init, int nested,
@@ -507,9 +508,16 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree 
value,
 
        if (DECL_FUNCTION_MEMBER_P (member)
            && ! flag_ms_extensions)
-         emit_diagnostic (diag_kind, loc, 0,
-                          "invalid use of member function %qD "
-                          "(did you forget the %<()%> ?)", member);
+         {
+           gcc_rich_location richloc (loc);
+           /* If "member" has no arguments (other than "this"), then
+              add a fix-it hint.  */
+           if (type_num_arguments (TREE_TYPE (member)) == 1)
+             richloc.add_fixit_insert_after ("()");
+           emit_diagnostic (diag_kind, &richloc, 0,
+                            "invalid use of member function %qD "
+                            "(did you forget the %<()%> ?)", member);
+         }
        else
          emit_diagnostic (diag_kind, loc, 0,
                           "invalid use of member %qD "
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index 80ff395..6c40f26 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -105,6 +105,8 @@ extern void inform_n (location_t, unsigned HOST_WIDE_INT, 
const char *,
 extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 extern bool emit_diagnostic (diagnostic_t, location_t, int,
                             const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
+extern bool emit_diagnostic (diagnostic_t, rich_location *, int,
+                            const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
 extern bool emit_diagnostic_valist (diagnostic_t, location_t, int, const char 
*,
                                    va_list *) ATTRIBUTE_GCC_DIAG (4,0);
 extern bool seen_error (void);
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index a572c08..9b583ce 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -1168,6 +1168,20 @@ emit_diagnostic (diagnostic_t kind, location_t location, 
int opt,
   return ret;
 }
 
+/* As above, but for rich_location *.  */
+
+bool
+emit_diagnostic (diagnostic_t kind, rich_location *richloc, int opt,
+                const char *gmsgid, ...)
+{
+  auto_diagnostic_group d;
+  va_list ap;
+  va_start (ap, gmsgid);
+  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, kind);
+  va_end (ap);
+  return ret;
+}
+
 /* Wrapper around diagnostic_impl taking a va_list parameter.  */
 
 bool
diff --git a/gcc/testsuite/g++.dg/parse/missing-parens-fixit.C 
b/gcc/testsuite/g++.dg/parse/missing-parens-fixit.C
new file mode 100644
index 0000000..a0fd7dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/missing-parens-fixit.C
@@ -0,0 +1,32 @@
+// { dg-options "-fdiagnostics-show-caret" }
+
+class t1
+{
+public:
+  double length () const { return m_length; }
+  double area (double width) const { return m_length * width; }
+
+private:
+  double m_length;
+};
+
+bool test_1 (const t1 &inst)
+{
+  return inst.length > 0.0; // { dg-error "did you forget the '\\(\\)'" }
+  /* We expect a fix-it hint.  */
+  /* { dg-begin-multiline-output "" }
+   return inst.length > 0.0;
+          ~~~~~^~~~~~
+                     ()
+     { dg-end-multiline-output "" } */
+}
+
+bool test_2 (const t1 &inst)
+{
+  return inst.area > 0.0; // { dg-error "did you forget the '\\(\\)'" }
+  /* "t1::area" has additional params, so we don't expect a fix-it hint.  */
+  /* { dg-begin-multiline-output "" }
+   return inst.area > 0.0;
+          ~~~~~^~~~
+     { dg-end-multiline-output "" } */
+}
-- 
1.8.5.3

Reply via email to