diff options
author | David Malcolm <dmalcolm@redhat.com> | 2017-01-20 14:36:46 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2017-01-20 14:36:46 +0000 |
commit | ebed71751b2c030de7f1ad9d284b54b34cfe0a20 (patch) | |
tree | e9e719aafb0644febd2b61d586b0ac4595d5db90 /gcc | |
parent | d40036b846df9d07f679d593c55f0090f513bb24 (diff) | |
download | gcc-ebed71751b2c030de7f1ad9d284b54b34cfe0a20.zip gcc-ebed71751b2c030de7f1ad9d284b54b34cfe0a20.tar.gz gcc-ebed71751b2c030de7f1ad9d284b54b34cfe0a20.tar.bz2 |
C++: fix fix-it hints for misspellings within explicit namespaces
gcc/cp/ChangeLog:
PR c++/77829
PR c++/78656
* cp-tree.h (suggest_alternatives_for): Add bool param.
(suggest_alternative_in_explicit_scope): New decl.
* error.c (qualified_name_lookup_error): When SCOPE is a namespace
that isn't the global one, call new function
suggest_alternative_in_explicit_scope, only calling
suggest_alternatives_for if it fails, and disabling near match
searches fort that case. When SCOPE is the global namespace,
pass true for new param to suggest_alternatives_for to allow for
fuzzy name lookups.
* lex.c (unqualified_name_lookup_error): Pass true for new param
to suggest_alternatives_for.
* name-lookup.c (consider_binding_level): Add forward decl.
(suggest_alternatives_for): Add "suggest_misspellings" param,
using it to conditionalize the fuzzy name-lookup code.
(suggest_alternative_in_explicit_scope): New function.
* parser.c (cp_parser_primary_expression): When calling
finish_id_expression, pass location of id_expression rather
than that of id_expr_token.
(cp_parser_id_expression): Convert local "unqualified_id" from
tree to cp_expr to avoid implicitly dropping location information.
gcc/testsuite/ChangeLog:
PR c++/77829
PR c++/78656
* g++.dg/spellcheck-pr77829.C: New test case.
* g++.dg/spellcheck-pr78656.C: New test case.
From-SVN: r244715
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 3 | ||||
-rw-r--r-- | gcc/cp/error.c | 5 | ||||
-rw-r--r-- | gcc/cp/lex.c | 2 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 55 | ||||
-rw-r--r-- | gcc/cp/parser.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/spellcheck-pr77829.C | 167 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/spellcheck-pr78656.C | 39 |
9 files changed, 293 insertions, 14 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6554cb7..9b71c90 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2017-01-20 David Malcolm <dmalcolm@redhat.com> + + PR c++/77829 + PR c++/78656 + * cp-tree.h (suggest_alternatives_for): Add bool param. + (suggest_alternative_in_explicit_scope): New decl. + * error.c (qualified_name_lookup_error): When SCOPE is a namespace + that isn't the global one, call new function + suggest_alternative_in_explicit_scope, only calling + suggest_alternatives_for if it fails, and disabling near match + searches fort that case. When SCOPE is the global namespace, + pass true for new param to suggest_alternatives_for to allow for + fuzzy name lookups. + * lex.c (unqualified_name_lookup_error): Pass true for new param + to suggest_alternatives_for. + * name-lookup.c (consider_binding_level): Add forward decl. + (suggest_alternatives_for): Add "suggest_misspellings" param, + using it to conditionalize the fuzzy name-lookup code. + (suggest_alternative_in_explicit_scope): New function. + * parser.c (cp_parser_primary_expression): When calling + finish_id_expression, pass location of id_expression rather + than that of id_expr_token. + (cp_parser_id_expression): Convert local "unqualified_id" from + tree to cp_expr to avoid implicitly dropping location information. + 2017-01-20 Marek Polacek <polacek@redhat.com> PR c/64279 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f7c7a35..b4c4dfa 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6937,7 +6937,8 @@ extern tree cp_fully_fold (tree); extern void clear_fold_cache (void); /* in name-lookup.c */ -extern void suggest_alternatives_for (location_t, tree); +extern void suggest_alternatives_for (location_t, tree, bool); +extern bool suggest_alternative_in_explicit_scope (location_t, tree, tree); extern tree strip_using_decl (tree); /* in constraint.cc */ diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 72044a9..4f4c11d 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3777,11 +3777,12 @@ qualified_name_lookup_error (tree scope, tree name, else if (scope != global_namespace) { error_at (location, "%qD is not a member of %qD", name, scope); - suggest_alternatives_for (location, name); + if (!suggest_alternative_in_explicit_scope (location, name, scope)) + suggest_alternatives_for (location, name, false); } else { error_at (location, "%<::%D%> has not been declared", name); - suggest_alternatives_for (location, name); + suggest_alternatives_for (location, name, true); } } diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 797dd96..60a70e9 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -441,7 +441,7 @@ unqualified_name_lookup_error (tree name, location_t loc) if (!objc_diagnose_private_ivar (name)) { error_at (loc, "%qD was not declared in this scope", name); - suggest_alternatives_for (loc, name); + suggest_alternatives_for (loc, name, true); } /* Prevent repeated error messages by creating a VAR_DECL with this NAME in the innermost block scope. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 3c7559f..4004640 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -48,6 +48,10 @@ static bool lookup_using_namespace (tree, struct scope_binding *, tree, tree, int); static bool qualified_lookup_using_namespace (tree, tree, struct scope_binding *, int); +static void consider_binding_level (tree name, best_match <tree, tree> &bm, + cp_binding_level *lvl, + bool look_within_fields, + enum lookup_name_fuzzy_kind kind); static tree lookup_type_current_level (tree); static tree push_using_directive (tree); static tree lookup_extern_c_fun_in_all_ns (tree); @@ -4431,10 +4435,13 @@ remove_hidden_names (tree fns) /* Suggest alternatives for NAME, an IDENTIFIER_NODE for which name lookup failed. Search through all available namespaces and print out - possible candidates. */ + possible candidates. If no exact matches are found, and + SUGGEST_MISSPELLINGS is true, then also look for near-matches and + suggest the best near-match, if there is one. */ void -suggest_alternatives_for (location_t location, tree name) +suggest_alternatives_for (location_t location, tree name, + bool suggest_misspellings) { vec<tree> candidates = vNULL; vec<tree> namespaces_to_search = vNULL; @@ -4481,13 +4488,16 @@ suggest_alternatives_for (location_t location, tree name) or do nothing. */ if (candidates.is_empty ()) { - const char *fuzzy_name = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME); - if (fuzzy_name) + if (suggest_misspellings) { - gcc_rich_location richloc (location); - richloc.add_fixit_replace (fuzzy_name); - inform_at_rich_loc (&richloc, "suggested alternative: %qs", - fuzzy_name); + const char *fuzzy_name = lookup_name_fuzzy (name, FUZZY_LOOKUP_NAME); + if (fuzzy_name) + { + gcc_rich_location richloc (location); + richloc.add_fixit_replace (fuzzy_name); + inform_at_rich_loc (&richloc, "suggested alternative: %qs", + fuzzy_name); + } } return; } @@ -4502,6 +4512,35 @@ suggest_alternatives_for (location_t location, tree name) candidates.release (); } +/* Look for alternatives for NAME, an IDENTIFIER_NODE for which name + lookup failed within the explicitly provided SCOPE. Suggest the + the best meaningful candidates (if any) as a fix-it hint. + Return true iff a suggestion was provided. */ + +bool +suggest_alternative_in_explicit_scope (location_t location, tree name, + tree scope) +{ + cp_binding_level *level = NAMESPACE_LEVEL (scope); + + best_match <tree, tree> bm (name); + consider_binding_level (name, bm, level, false, FUZZY_LOOKUP_NAME); + + /* See if we have a good suggesion for the user. */ + tree best_id = bm.get_best_meaningful_candidate (); + if (best_id) + { + const char *fuzzy_name = IDENTIFIER_POINTER (best_id); + gcc_rich_location richloc (location); + richloc.add_fixit_replace (fuzzy_name); + inform_at_rich_loc (&richloc, "suggested alternative: %qs", + fuzzy_name); + return true; + } + + return false; +} + /* Unscoped lookup of a global: iterate over current namespaces, considering using-directives. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 29dcfea..4ab0b69 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5332,7 +5332,7 @@ cp_parser_primary_expression (cp_parser *parser, template_p, done, address_p, template_arg_p, &error_msg, - id_expr_token->location)); + id_expression.get_location ())); if (error_msg) cp_parser_error (parser, error_msg); decl.set_location (id_expr_token->location); @@ -5425,7 +5425,7 @@ cp_parser_id_expression (cp_parser *parser, tree saved_scope; tree saved_object_scope; tree saved_qualifying_scope; - tree unqualified_id; + cp_expr unqualified_id; bool is_template; /* See if the next token is the `template' keyword. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 201395d..fde9328 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-01-20 David Malcolm <dmalcolm@redhat.com> + + PR c++/77829 + PR c++/78656 + * g++.dg/spellcheck-pr77829.C: New test case. + * g++.dg/spellcheck-pr78656.C: New test case. + 2017-01-20 Marek Polacek <polacek@redhat.com> PR c/64279 diff --git a/gcc/testsuite/g++.dg/spellcheck-pr77829.C b/gcc/testsuite/g++.dg/spellcheck-pr77829.C new file mode 100644 index 0000000..2f75779 --- /dev/null +++ b/gcc/testsuite/g++.dg/spellcheck-pr77829.C @@ -0,0 +1,167 @@ +// { dg-options "-fdiagnostics-show-caret" } + +/* Various tests of name lookup within a namespace, both within an explicitly + given namespace, or implicitly. */ + +namespace detail { + /* Various things to look for. */ + + typedef int some_typedef; + + int _foo(int i) { return i; } + + template <typename T> + T something_else (T i) { return i; } +} + +/* Tests of lookup of a typedef. */ + +void fn_1_explicit () +{ + detail::some_type i; // { dg-error ".some_type. is not a member of .detail." } + // { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + detail::some_type i; + ^~~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + detail::some_type i; + ^~~~~~~~~ + some_typedef + { dg-end-multiline-output "" } */ +} + +namespace detail { + +void fn_1_implicit () +{ + some_type i; // { dg-error ".some_type. was not declared in this scope" } + // { dg-message "suggested alternative: .some_typedef." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + some_type i; + ^~~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + some_type i; + ^~~~~~~~~ + some_typedef + { dg-end-multiline-output "" } */ +} + +} // namespace detail + + +/* Tests of lookup of a function. */ + +void fn_2_explicit (int i) { + detail::foo(i); // { dg-error ".foo. is not a member of .detail." } + // { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + detail::foo(i); + ^~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + detail::foo(i); + ^~~ + _foo + { dg-end-multiline-output "" } */ +} + +namespace detail { + +void fn_2_implicit (int i) { + foo(i); // { dg-error ".foo. was not declared in this scope" } + // { dg-message "suggested alternative: ._foo." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + foo(i); + ^~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + foo(i); + ^~~ + _foo + { dg-end-multiline-output "" } */ +} + +} // namespace detail + + +/* Examples using a template. */ + +void fn_3_explicit (int i) { + detail::something_els(i); // { dg-error ".something_els. is not a member of .detail." } + // { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + detail::something_els(i); + ^~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + /* { dg-begin-multiline-output "" } + detail::something_els(i); + ^~~~~~~~~~~~~ + something_else + { dg-end-multiline-output "" } */ +} + +namespace detail { + +void fn_3_implicit (int i) { + something_els(i); // { dg-error ".something_els. was not declared in this scope" } + // { dg-message "suggested alternative: .something_else." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + something_els(i); + ^~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + + /* { dg-begin-multiline-output "" } + something_els(i); + ^~~~~~~~~~~~~ + something_else + { dg-end-multiline-output "" } */ +} + +} // namespace detail + + +/* Tests of lookup for which no hint is available. */ + +void fn_4_explicit (int i) { + detail::not_recognized(i); // { dg-error ".not_recognized. is not a member of .detail." } + /* { dg-begin-multiline-output "" } + detail::not_recognized(i); + ^~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +namespace detail { + +void fn_4_implicit (int i) +{ + not_recognized(i); // { dg-error ".not_recognized. was not declared in this scope" } + /* { dg-begin-multiline-output "" } + not_recognized(i); + ^~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +} // namespace detail + + +/* Test for failed lookup explicitly within global namespace. */ + +typedef int another_typedef; + +void fn_5 () +{ + ::another_type i; // { dg-error ".::another_type. has not been declared" } + // { dg-message "suggested alternative: .another_typedef." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + ::another_type i; + ^~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + ::another_type i; + ^~~~~~~~~~~~ + another_typedef + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/g++.dg/spellcheck-pr78656.C b/gcc/testsuite/g++.dg/spellcheck-pr78656.C new file mode 100644 index 0000000..ded4bb6 --- /dev/null +++ b/gcc/testsuite/g++.dg/spellcheck-pr78656.C @@ -0,0 +1,39 @@ +// { dg-options "-fdiagnostics-show-caret" } + +#include <memory> + +void* allocate(std::size_t n) +{ + return std::allocate<char>().allocate(n); // { dg-error ".allocate. is not a member of .std." } + // { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + return std::allocate<char>().allocate(n); + ^~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + return std::allocate<char>().allocate(n); + ^~~~~~~~ + allocator + { dg-end-multiline-output "" } */ + + // Various errors follow that we don't care about; suppress them: + // { dg-excess-errors "7: " } +} + +void* test_2(std::size_t n) +{ + return std::alocator<char>().allocate(n); // { dg-error ".alocator. is not a member of .std." } + // { dg-message "suggested alternative: .allocator." "" { target *-*-* } .-1 } + /* { dg-begin-multiline-output "" } + return std::alocator<char>().allocate(n); + ^~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + return std::alocator<char>().allocate(n); + ^~~~~~~~ + allocator + { dg-end-multiline-output "" } */ + + // Various errors follow that we don't care about; suppress them: + // { dg-excess-errors "25: " } +} |