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