+2015-11-19 David Malcolm <dmalcolm@redhat.com>
+
+ * c-typeck.c (lookup_field_fuzzy): Move determination of closest
+ candidate into a new function, find_closest_identifier.
+
2015-11-19 Marek Polacek <polacek@redhat.com>
PR c/68412
lookup_field_fuzzy_find_candidates (type, component,
&candidates);
- /* Now determine which is closest. */
- int i;
- tree identifier;
- tree best_identifier = NULL;
- edit_distance_t best_distance = MAX_EDIT_DISTANCE;
- FOR_EACH_VEC_ELT (candidates, i, identifier)
- {
- gcc_assert (TREE_CODE (identifier) == IDENTIFIER_NODE);
- edit_distance_t dist = levenshtein_distance (component, identifier);
- if (dist < best_distance)
- {
- best_distance = dist;
- best_identifier = identifier;
- }
- }
-
- /* If more than half of the letters were misspelled, the suggestion is
- likely to be meaningless. */
- if (best_identifier)
- {
- unsigned int cutoff = MAX (IDENTIFIER_LENGTH (component),
- IDENTIFIER_LENGTH (best_identifier)) / 2;
- if (best_distance > cutoff)
- return NULL;
- }
-
- return best_identifier;
+ return find_closest_identifier (component, &candidates);
}
/* Make an expression to refer to the COMPONENT field of structure or
+2015-11-19 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h (lookup_member_fuzzy): New decl.
+ * search.c: Include spellcheck.h.
+ (class lookup_field_fuzzy_info): New class.
+ (lookup_field_fuzzy_info::fuzzy_lookup_fnfields): New.
+ (lookup_field_fuzzy_info::fuzzy_lookup_field): New.
+ (lookup_field_fuzzy_r): New.
+ (lookup_member_fuzzy): New.
+ * typeck.c (finish_class_member_access_expr): When issuing
+ a "has no member named" error, call lookup_member_fuzzy, and
+ offer any result as a suggestion.
+
2015-11-19 Torvald Riegel <triegel@redhat.com>
* except.c (do_free_exception): Use transactional wrapper.
extern tree lookup_fnfields (tree, tree, int);
extern tree lookup_member (tree, tree, int, bool,
tsubst_flags_t);
+extern tree lookup_member_fuzzy (tree, tree, bool);
extern int look_for_overrides (tree, tree);
extern void get_pure_virtuals (tree);
extern void maybe_suppress_debug_info (tree);
#include "cp-tree.h"
#include "intl.h"
#include "toplev.h"
+#include "spellcheck.h"
static int is_subobject_of_p (tree, tree);
static tree dfs_lookup_base (tree, void *);
return rval;
}
+/* Helper class for lookup_member_fuzzy. */
+
+class lookup_field_fuzzy_info
+{
+ public:
+ lookup_field_fuzzy_info (bool want_type_p) :
+ m_want_type_p (want_type_p), m_candidates () {}
+
+ void fuzzy_lookup_fnfields (tree type);
+ void fuzzy_lookup_field (tree type);
+
+ /* If true, we are looking for types, not data members. */
+ bool m_want_type_p;
+ /* The result: a vec of identifiers. */
+ auto_vec<tree> m_candidates;
+};
+
+/* Locate all methods within TYPE, append them to m_candidates. */
+
+void
+lookup_field_fuzzy_info::fuzzy_lookup_fnfields (tree type)
+{
+ vec<tree, va_gc> *method_vec;
+ tree fn;
+ size_t i;
+
+ if (!CLASS_TYPE_P (type))
+ return;
+
+ method_vec = CLASSTYPE_METHOD_VEC (type);
+ if (!method_vec)
+ return;
+
+ for (i = 0; vec_safe_iterate (method_vec, i, &fn); ++i)
+ if (fn)
+ m_candidates.safe_push (DECL_NAME (OVL_CURRENT (fn)));
+}
+
+/* Locate all fields within TYPE, append them to m_candidates. */
+
+void
+lookup_field_fuzzy_info::fuzzy_lookup_field (tree type)
+{
+ if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (type) == TYPENAME_TYPE)
+ /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM and
+ BOUND_TEMPLATE_TEMPLATE_PARM are not fields at all;
+ instead TYPE_FIELDS is the TEMPLATE_PARM_INDEX.
+ The TYPE_FIELDS of TYPENAME_TYPE is its TYPENAME_TYPE_FULLNAME. */
+ return;
+
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (!m_want_type_p || DECL_DECLARES_TYPE_P (field))
+ if (DECL_NAME (field))
+ m_candidates.safe_push (DECL_NAME (field));
+ }
+}
+
+
+/* Helper function for lookup_member_fuzzy, called via dfs_walk_all
+ DATA is really a lookup_field_fuzzy_info. Look for a field with
+ the name indicated there in BINFO. Gathers pertinent identifiers into
+ m_candidates. */
+
+static tree
+lookup_field_fuzzy_r (tree binfo, void *data)
+{
+ lookup_field_fuzzy_info *lffi = (lookup_field_fuzzy_info *) data;
+ tree type = BINFO_TYPE (binfo);
+
+ /* First, look for functions. */
+ if (!lffi->m_want_type_p)
+ lffi->fuzzy_lookup_fnfields (type);
+
+ /* Look for data member and types. */
+ lffi->fuzzy_lookup_field (type);
+
+ return NULL_TREE;
+}
+
+/* Like lookup_member, but try to find the closest match for NAME,
+ rather than an exact match, and return an identifier (or NULL_TREE).
+ Do not complain. */
+
+tree
+lookup_member_fuzzy (tree xbasetype, tree name, bool want_type_p)
+{
+ tree type = NULL_TREE, basetype_path = NULL_TREE;
+ struct lookup_field_fuzzy_info lffi (want_type_p);
+
+ /* rval_binfo is the binfo associated with the found member, note,
+ this can be set with useful information, even when rval is not
+ set, because it must deal with ALL members, not just non-function
+ members. It is used for ambiguity checking and the hidden
+ checks. Whereas rval is only set if a proper (not hidden)
+ non-function member is found. */
+
+ if (name == error_mark_node
+ || xbasetype == NULL_TREE
+ || xbasetype == error_mark_node)
+ return NULL_TREE;
+
+ gcc_assert (identifier_p (name));
+
+ if (TREE_CODE (xbasetype) == TREE_BINFO)
+ {
+ type = BINFO_TYPE (xbasetype);
+ basetype_path = xbasetype;
+ }
+ else
+ {
+ if (!RECORD_OR_UNION_CODE_P (TREE_CODE (xbasetype)))
+ return NULL_TREE;
+ type = xbasetype;
+ xbasetype = NULL_TREE;
+ }
+
+ type = complete_type (type);
+
+ /* Make sure we're looking for a member of the current instantiation in the
+ right partial specialization. */
+ if (flag_concepts && dependent_type_p (type))
+ type = currently_open_class (type);
+
+ if (!basetype_path)
+ basetype_path = TYPE_BINFO (type);
+
+ if (!basetype_path)
+ return NULL_TREE;
+
+ /* Populate lffi.m_candidates. */
+ dfs_walk_all (basetype_path, &lookup_field_fuzzy_r, NULL, &lffi);
+
+ return find_closest_identifier (name, &lffi.m_candidates);
+}
+
/* Like lookup_member, except that if we find a function member we
return NULL_TREE. */
if (member == NULL_TREE)
{
if (complain & tf_error)
- error ("%q#T has no member named %qE",
- TREE_CODE (access_path) == TREE_BINFO
- ? TREE_TYPE (access_path) : object_type, name);
+ {
+ tree guessed_id = lookup_member_fuzzy (access_path, name,
+ /*want_type=*/false);
+ if (guessed_id)
+ error ("%q#T has no member named %qE; did you mean %qE?",
+ TREE_CODE (access_path) == TREE_BINFO
+ ? TREE_TYPE (access_path) : object_type, name, guessed_id);
+ else
+ error ("%q#T has no member named %qE",
+ TREE_CODE (access_path) == TREE_BINFO
+ ? TREE_TYPE (access_path) : object_type, name);
+ }
return error_mark_node;
}
if (member == error_mark_node)
IDENTIFIER_POINTER (ident_t),
IDENTIFIER_LENGTH (ident_t));
}
+
+/* Given TARGET, an identifier, and CANDIDATES, a vec of identifiers,
+ determine which element within CANDIDATES has the lowest edit
+ distance to TARGET. If there are multiple elements with the
+ same minimal distance, the first in the vector wins.
+
+ If more than half of the letters were misspelled, the suggestion is
+ likely to be meaningless, so return NULL_TREE for this case. */
+
+tree
+find_closest_identifier (tree target, const auto_vec<tree> *candidates)
+{
+ gcc_assert (TREE_CODE (target) == IDENTIFIER_NODE);
+
+ int i;
+ tree identifier;
+ tree best_identifier = NULL_TREE;
+ edit_distance_t best_distance = MAX_EDIT_DISTANCE;
+ FOR_EACH_VEC_ELT (*candidates, i, identifier)
+ {
+ gcc_assert (TREE_CODE (identifier) == IDENTIFIER_NODE);
+ edit_distance_t dist = levenshtein_distance (target, identifier);
+ if (dist < best_distance)
+ {
+ best_distance = dist;
+ best_identifier = identifier;
+ }
+ }
+
+ /* If more than half of the letters were misspelled, the suggestion is
+ likely to be meaningless. */
+ if (best_identifier)
+ {
+ unsigned int cutoff = MAX (IDENTIFIER_LENGTH (target),
+ IDENTIFIER_LENGTH (best_identifier)) / 2;
+ if (best_distance > cutoff)
+ return NULL_TREE;
+ }
+
+ return best_identifier;
+}
typedef unsigned int edit_distance_t;
const edit_distance_t MAX_EDIT_DISTANCE = UINT_MAX;
+/* spellcheck.c */
extern edit_distance_t
levenshtein_distance (const char *s, int len_s,
const char *t, int len_t);
extern edit_distance_t
levenshtein_distance (const char *s, const char *t);
+/* spellcheck-tree.c */
+
extern edit_distance_t
levenshtein_distance (tree ident_s, tree ident_t);
+extern tree
+find_closest_identifier (tree target, const auto_vec<tree> *candidates);
+
#endif /* GCC_SPELLCHECK_H */
+2015-11-19 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/spellcheck-fields.C: New file.
+
2015-11-19 Aditya Kumar <aditya.k7@samsung.com>
Sebastian Pop <s.pop@samsung.com>