diff gcc/spellcheck-tree.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/spellcheck-tree.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,144 @@
+/* Find near-matches for identifiers.
+   Copyright (C) 2015-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "cpplib.h"
+#include "spellcheck-tree.h"
+#include "selftest.h"
+#include "stringpool.h"
+
+/* Calculate Levenshtein distance between two identifiers.  */
+
+edit_distance_t
+levenshtein_distance (tree ident_s, tree ident_t)
+{
+  gcc_assert (TREE_CODE (ident_s) == IDENTIFIER_NODE);
+  gcc_assert (TREE_CODE (ident_t) == IDENTIFIER_NODE);
+
+  return levenshtein_distance (IDENTIFIER_POINTER (ident_s),
+			       IDENTIFIER_LENGTH (ident_s),
+			       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);
+
+  best_match<tree, tree> bm (target);
+  int i;
+  tree identifier;
+  FOR_EACH_VEC_ELT (*candidates, i, identifier)
+    {
+      gcc_assert (TREE_CODE (identifier) == IDENTIFIER_NODE);
+      bm.consider (identifier);
+    }
+
+  return bm.get_best_meaningful_candidate ();
+}
+
+/* A callback for cpp_forall_identifiers, for use by best_macro_match's ctor.
+   Process HASHNODE and update the best_macro_match instance pointed to be
+   USER_DATA.  */
+
+static int
+find_closest_macro_cpp_cb (cpp_reader *, cpp_hashnode *hashnode,
+			   void *user_data)
+{
+  if (hashnode->type != NT_MACRO)
+    return 1;
+
+  best_macro_match *bmm = (best_macro_match *)user_data;
+  bmm->consider (hashnode);
+
+  /* Keep iterating.  */
+  return 1;
+}
+
+/* Constructor for best_macro_match.
+   Use find_closest_macro_cpp_cb to find the closest matching macro to
+   NAME within distance < best_distance_so_far. */
+
+best_macro_match::best_macro_match (tree goal,
+				    edit_distance_t best_distance_so_far,
+				    cpp_reader *reader)
+: best_match <goal_t, candidate_t> (goal, best_distance_so_far)
+{
+  cpp_forall_identifiers (reader, find_closest_macro_cpp_cb, this);
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests.  */
+
+/* Verify that find_closest_identifier is sane.  */
+
+static void
+test_find_closest_identifier ()
+{
+  auto_vec<tree> candidates;
+
+  /* Verify that it can handle an empty vec.  */
+  ASSERT_EQ (NULL, find_closest_identifier (get_identifier (""), &candidates));
+
+  /* Verify that it works sanely for non-empty vecs.  */
+  tree apple = get_identifier ("apple");
+  tree banana = get_identifier ("banana");
+  tree cherry = get_identifier ("cherry");
+  candidates.safe_push (apple);
+  candidates.safe_push (banana);
+  candidates.safe_push (cherry);
+
+  ASSERT_EQ (apple, find_closest_identifier (get_identifier ("app"),
+					     &candidates));
+  ASSERT_EQ (banana, find_closest_identifier (get_identifier ("banyan"),
+					      &candidates));;
+  ASSERT_EQ (cherry, find_closest_identifier (get_identifier ("berry"),
+					      &candidates));
+  ASSERT_EQ (NULL,
+	     find_closest_identifier (get_identifier ("not like the others"),
+				      &candidates));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+spellcheck_tree_c_tests ()
+{
+  test_find_closest_identifier ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */