Line data Source code
1 : /* Find near-matches for identifiers.
2 : Copyright (C) 2015-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
6 : GCC is free software; you can redistribute it and/or modify it under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GCC; see the file COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 : #include "config.h"
21 : #include "system.h"
22 : #include "coretypes.h"
23 : #include "tm.h"
24 : #include "tree.h"
25 : #include "cpplib.h"
26 : #include "spellcheck-tree.h"
27 : #include "selftest.h"
28 : #include "stringpool.h"
29 :
30 : /* Calculate edit distance between two identifiers. */
31 :
32 : edit_distance_t
33 0 : get_edit_distance (tree ident_s, tree ident_t)
34 : {
35 0 : gcc_assert (TREE_CODE (ident_s) == IDENTIFIER_NODE);
36 0 : gcc_assert (TREE_CODE (ident_t) == IDENTIFIER_NODE);
37 :
38 0 : return get_edit_distance (IDENTIFIER_POINTER (ident_s),
39 0 : IDENTIFIER_LENGTH (ident_s),
40 0 : IDENTIFIER_POINTER (ident_t),
41 0 : IDENTIFIER_LENGTH (ident_t));
42 : }
43 :
44 : /* Given TARGET, an identifier, and CANDIDATES, a vec of identifiers,
45 : determine which element within CANDIDATES has the lowest edit
46 : distance to TARGET. If there are multiple elements with the
47 : same minimal distance, the first in the vector wins.
48 :
49 : If more than half of the letters were misspelled, the suggestion is
50 : likely to be meaningless, so return NULL_TREE for this case. */
51 :
52 : tree
53 828 : find_closest_identifier (tree target, const auto_vec<tree> *candidates)
54 : {
55 828 : gcc_assert (TREE_CODE (target) == IDENTIFIER_NODE);
56 :
57 828 : best_match<tree, tree> bm (target);
58 828 : int i;
59 828 : tree identifier;
60 3567 : FOR_EACH_VEC_ELT (*candidates, i, identifier)
61 : {
62 1911 : gcc_assert (TREE_CODE (identifier) == IDENTIFIER_NODE);
63 1911 : bm.consider (identifier);
64 : }
65 :
66 828 : return bm.get_best_meaningful_candidate ();
67 : }
68 :
69 : #if CHECKING_P
70 :
71 : namespace selftest {
72 :
73 : /* Selftests. */
74 :
75 : /* Verify that find_closest_identifier is sane. */
76 :
77 : static void
78 4 : test_find_closest_identifier ()
79 : {
80 4 : auto_vec<tree> candidates;
81 :
82 : /* Verify that it can handle an empty vec. */
83 4 : ASSERT_EQ (NULL, find_closest_identifier (get_identifier (""), &candidates));
84 :
85 : /* Verify that it works sanely for non-empty vecs. */
86 4 : tree apple = get_identifier ("apple");
87 4 : tree banana = get_identifier ("banana");
88 4 : tree cherry = get_identifier ("cherry");
89 4 : candidates.safe_push (apple);
90 4 : candidates.safe_push (banana);
91 4 : candidates.safe_push (cherry);
92 :
93 4 : ASSERT_EQ (apple, find_closest_identifier (get_identifier ("app"),
94 : &candidates));
95 4 : ASSERT_EQ (banana, find_closest_identifier (get_identifier ("banyan"),
96 : &candidates));
97 4 : ASSERT_EQ (cherry, find_closest_identifier (get_identifier ("berry"),
98 : &candidates));
99 4 : ASSERT_EQ (NULL,
100 : find_closest_identifier (get_identifier ("not like the others"),
101 : &candidates));
102 4 : }
103 :
104 : /* Run all of the selftests within this file. */
105 :
106 : void
107 4 : spellcheck_tree_cc_tests ()
108 : {
109 4 : test_find_closest_identifier ();
110 4 : }
111 :
112 : } // namespace selftest
113 :
114 : #endif /* #if CHECKING_P */
|