mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-21 16:00:58 +08:00
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
This commit is contained in:
parent
d40036b846
commit
ebed71751b
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
167
gcc/testsuite/g++.dg/spellcheck-pr77829.C
Normal file
167
gcc/testsuite/g++.dg/spellcheck-pr77829.C
Normal file
@ -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 "" } */
|
||||
}
|
39
gcc/testsuite/g++.dg/spellcheck-pr78656.C
Normal file
39
gcc/testsuite/g++.dg/spellcheck-pr78656.C
Normal file
@ -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: " }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user