c++: Make spell corrections consistent
My change to namespace-scope spell corrections ignored the issue that different targets might have different builtins, and therefore perturb iteration order. This fixes it by using an intermediate array of identifier, which we sort before considering. gcc/cp/ * name-lookup.c (maybe_add_fuzzy_decl): New. (maybe_add_fuzzy_binding): New. (consider_binding_level): Use intermediate sortable vector for namespace bindings. gcc/testsuite/ * c-c++-common/spellcheck-reserved.c: Restore diagnostic.
This commit is contained in:
parent
bf490f0636
commit
255aa06d40
2 changed files with 95 additions and 25 deletions
|
@ -6077,6 +6077,9 @@ qualified_namespace_lookup (tree scope, name_lookup *lookup)
|
|||
return found;
|
||||
}
|
||||
|
||||
/* If DECL is suitably visible to the user, consider its name for
|
||||
spelling correction. */
|
||||
|
||||
static void
|
||||
consider_decl (tree decl, best_match <tree, const char *> &bm,
|
||||
bool consider_impl_names)
|
||||
|
@ -6110,6 +6113,65 @@ consider_decl (tree decl, best_match <tree, const char *> &bm,
|
|||
bm.consider (suggestion_str);
|
||||
}
|
||||
|
||||
/* If DECL is suitably visible to the user, add its name to VEC and
|
||||
return true. Otherwise return false. */
|
||||
|
||||
static bool
|
||||
maybe_add_fuzzy_decl (auto_vec<tree> &vec, tree decl)
|
||||
{
|
||||
/* Skip compiler-generated variables (e.g. __for_begin/__for_end
|
||||
within range for). */
|
||||
if (TREE_CODE (decl) == VAR_DECL && DECL_ARTIFICIAL (decl))
|
||||
return false;
|
||||
|
||||
tree suggestion = DECL_NAME (decl);
|
||||
if (!suggestion)
|
||||
return false;
|
||||
|
||||
/* Don't suggest names that are for anonymous aggregate types, as
|
||||
they are an implementation detail generated by the compiler. */
|
||||
if (IDENTIFIER_ANON_P (suggestion))
|
||||
return false;
|
||||
|
||||
vec.safe_push (suggestion);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Examing the namespace binding BINDING, and add at most one instance
|
||||
of the name, if it contains a visible entity of interest. */
|
||||
|
||||
void
|
||||
maybe_add_fuzzy_binding (auto_vec<tree> &vec, tree binding,
|
||||
lookup_name_fuzzy_kind kind)
|
||||
{
|
||||
tree value = NULL_TREE;
|
||||
|
||||
if (STAT_HACK_P (binding))
|
||||
{
|
||||
if (!STAT_TYPE_HIDDEN_P (binding)
|
||||
&& STAT_TYPE (binding))
|
||||
{
|
||||
if (maybe_add_fuzzy_decl (vec, STAT_TYPE (binding)))
|
||||
return;
|
||||
}
|
||||
else if (!STAT_DECL_HIDDEN_P (binding))
|
||||
value = STAT_DECL (binding);
|
||||
}
|
||||
else
|
||||
value = binding;
|
||||
|
||||
value = ovl_skip_hidden (value);
|
||||
if (value)
|
||||
{
|
||||
value = OVL_FIRST (value);
|
||||
if (kind != FUZZY_LOOKUP_TYPENAME
|
||||
|| TREE_CODE (STRIP_TEMPLATE (value)) == TYPE_DECL)
|
||||
if (maybe_add_fuzzy_decl (vec, value))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function for lookup_name_fuzzy.
|
||||
Traverse binding level LVL, looking for good name matches for NAME
|
||||
(and BM). */
|
||||
|
@ -6157,38 +6219,46 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* Iterate over the namespace hash table, that'll have fewer
|
||||
entries than the decl list. */
|
||||
/* We need to iterate over the namespace hash table, in order to
|
||||
not mention hidden entities. But hash table iteration is
|
||||
(essentially) unpredictable, our correction-distance measure
|
||||
is very granular, and we pick the first of equal distances.
|
||||
Hence, we need to call the distance-measurer in a predictable
|
||||
order. So, iterate over the namespace hash, inserting
|
||||
visible names into a vector. Then sort the vector. Then
|
||||
determine spelling distance. */
|
||||
|
||||
tree ns = lvl->this_entity;
|
||||
auto_vec<tree> vec;
|
||||
|
||||
hash_table<named_decl_hash>::iterator end
|
||||
(DECL_NAMESPACE_BINDINGS (ns)->end ());
|
||||
for (hash_table<named_decl_hash>::iterator iter
|
||||
(DECL_NAMESPACE_BINDINGS (ns)->begin ()); iter != end; ++iter)
|
||||
{
|
||||
tree binding = *iter;
|
||||
tree value = NULL_TREE;
|
||||
maybe_add_fuzzy_binding (vec, *iter, kind);
|
||||
|
||||
if (STAT_HACK_P (binding))
|
||||
{
|
||||
if (!STAT_TYPE_HIDDEN_P (binding)
|
||||
&& STAT_TYPE (binding))
|
||||
consider_decl (STAT_TYPE (binding), bm,
|
||||
consider_implementation_names);
|
||||
else if (!STAT_DECL_HIDDEN_P (binding))
|
||||
value = STAT_DECL (binding);
|
||||
}
|
||||
else
|
||||
value = binding;
|
||||
vec.qsort ([] (const void *a_, const void *b_)
|
||||
{
|
||||
return strcmp (IDENTIFIER_POINTER (*(const tree *)a_),
|
||||
IDENTIFIER_POINTER (*(const tree *)b_));
|
||||
});
|
||||
|
||||
/* Examine longest to shortest. */
|
||||
for (unsigned ix = vec.length (); ix--;)
|
||||
{
|
||||
const char *str = IDENTIFIER_POINTER (vec[ix]);
|
||||
|
||||
/* Ignore internal names with spaces in them. */
|
||||
if (strchr (str, ' '))
|
||||
continue;
|
||||
|
||||
value = ovl_skip_hidden (value);
|
||||
if (value)
|
||||
{
|
||||
value = OVL_FIRST (value);
|
||||
if (!(kind == FUZZY_LOOKUP_TYPENAME
|
||||
&& TREE_CODE (STRIP_TEMPLATE (value)) != TYPE_DECL))
|
||||
consider_decl (value, bm, consider_implementation_names);
|
||||
}
|
||||
/* Don't suggest names that are reserved for use by the
|
||||
implementation, unless NAME began with an underscore. */
|
||||
if (!consider_implementation_names
|
||||
&& name_reserved_for_implementation_p (str))
|
||||
continue;
|
||||
|
||||
bm.consider (str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ void test (const char *buf, char ch)
|
|||
{
|
||||
__builtin_strtchr (buf, ch); /* { dg-line misspelled_reserved } */
|
||||
/* { dg-warning "did you mean '__builtin_strchr'" "" { target c } misspelled_reserved } */
|
||||
/* { dg-error "'__builtin_strtchr' was not declared in this scope; did you mean '__builtin_strchr'\\?" "" { target c++ } misspelled_reserved } */
|
||||
/* { dg-error "'__builtin_strtchr' was not declared in this scope; did you mean '__builtin_strrchr'\\?" "" { target c++ } misspelled_reserved } */
|
||||
}
|
||||
|
||||
/* Similarly for a name that begins with a single underscore. */
|
||||
|
|
Loading…
Add table
Reference in a new issue