1*38fd1498Szrj /* Find near-matches for macros.
2*38fd1498Szrj    Copyright (C) 2016-2018 Free Software Foundation, Inc.
3*38fd1498Szrj 
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj 
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
7*38fd1498Szrj the terms of the GNU General Public License as published by the Free
8*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
9*38fd1498Szrj version.
10*38fd1498Szrj 
11*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*38fd1498Szrj for more details.
15*38fd1498Szrj 
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
19*38fd1498Szrj 
20*38fd1498Szrj #include "config.h"
21*38fd1498Szrj #include "system.h"
22*38fd1498Szrj #include "coretypes.h"
23*38fd1498Szrj #include "tm.h"
24*38fd1498Szrj #include "tree.h"
25*38fd1498Szrj #include "cpplib.h"
26*38fd1498Szrj #include "spellcheck-tree.h"
27*38fd1498Szrj #include "c-family/c-spellcheck.h"
28*38fd1498Szrj #include "selftest.h"
29*38fd1498Szrj 
30*38fd1498Szrj /* Return true iff STR begin with an underscore and either an uppercase
31*38fd1498Szrj    letter or another underscore, and is thus, for C and C++, reserved for
32*38fd1498Szrj    use by the implementation.  */
33*38fd1498Szrj 
34*38fd1498Szrj bool
name_reserved_for_implementation_p(const char * str)35*38fd1498Szrj name_reserved_for_implementation_p (const char *str)
36*38fd1498Szrj {
37*38fd1498Szrj   if (str[0] != '_')
38*38fd1498Szrj     return false;
39*38fd1498Szrj   return (str[1] == '_' || ISUPPER(str[1]));
40*38fd1498Szrj }
41*38fd1498Szrj 
42*38fd1498Szrj /* Return true iff HASHNODE is a macro that should be offered as a
43*38fd1498Szrj    suggestion for a misspelling.  */
44*38fd1498Szrj 
45*38fd1498Szrj static bool
should_suggest_as_macro_p(cpp_hashnode * hashnode)46*38fd1498Szrj should_suggest_as_macro_p (cpp_hashnode *hashnode)
47*38fd1498Szrj {
48*38fd1498Szrj   if (hashnode->type != NT_MACRO)
49*38fd1498Szrj     return false;
50*38fd1498Szrj 
51*38fd1498Szrj   /* Don't suggest names reserved for the implementation, but do suggest the builtin
52*38fd1498Szrj      macros such as __FILE__, __LINE__ etc.  */
53*38fd1498Szrj   if (name_reserved_for_implementation_p ((const char *)hashnode->ident.str)
54*38fd1498Szrj       && !(hashnode->flags & NODE_BUILTIN))
55*38fd1498Szrj     return false;
56*38fd1498Szrj 
57*38fd1498Szrj   return true;
58*38fd1498Szrj }
59*38fd1498Szrj 
60*38fd1498Szrj /* A callback for cpp_forall_identifiers, for use by best_macro_match's ctor.
61*38fd1498Szrj    Process HASHNODE and update the best_macro_match instance pointed to be
62*38fd1498Szrj    USER_DATA.  */
63*38fd1498Szrj 
64*38fd1498Szrj static int
find_closest_macro_cpp_cb(cpp_reader *,cpp_hashnode * hashnode,void * user_data)65*38fd1498Szrj find_closest_macro_cpp_cb (cpp_reader *, cpp_hashnode *hashnode,
66*38fd1498Szrj 			   void *user_data)
67*38fd1498Szrj {
68*38fd1498Szrj   if (!should_suggest_as_macro_p (hashnode))
69*38fd1498Szrj     return 1;
70*38fd1498Szrj 
71*38fd1498Szrj   best_macro_match *bmm = (best_macro_match *)user_data;
72*38fd1498Szrj   bmm->consider (hashnode);
73*38fd1498Szrj 
74*38fd1498Szrj   /* Keep iterating.  */
75*38fd1498Szrj   return 1;
76*38fd1498Szrj }
77*38fd1498Szrj 
78*38fd1498Szrj /* Constructor for best_macro_match.
79*38fd1498Szrj    Use find_closest_macro_cpp_cb to find the closest matching macro to
80*38fd1498Szrj    NAME within distance < best_distance_so_far. */
81*38fd1498Szrj 
best_macro_match(tree goal,edit_distance_t best_distance_so_far,cpp_reader * reader)82*38fd1498Szrj best_macro_match::best_macro_match (tree goal,
83*38fd1498Szrj 				    edit_distance_t best_distance_so_far,
84*38fd1498Szrj 				    cpp_reader *reader)
85*38fd1498Szrj : best_match <goal_t, candidate_t> (goal, best_distance_so_far)
86*38fd1498Szrj {
87*38fd1498Szrj   cpp_forall_identifiers (reader, find_closest_macro_cpp_cb, this);
88*38fd1498Szrj }
89*38fd1498Szrj 
90*38fd1498Szrj #if CHECKING_P
91*38fd1498Szrj 
92*38fd1498Szrj namespace selftest {
93*38fd1498Szrj 
94*38fd1498Szrj /* Selftests.  */
95*38fd1498Szrj 
96*38fd1498Szrj /* Verify that name_reserved_for_implementation_p is sane.  */
97*38fd1498Szrj 
98*38fd1498Szrj static void
test_name_reserved_for_implementation_p()99*38fd1498Szrj test_name_reserved_for_implementation_p ()
100*38fd1498Szrj {
101*38fd1498Szrj   ASSERT_FALSE (name_reserved_for_implementation_p (""));
102*38fd1498Szrj   ASSERT_FALSE (name_reserved_for_implementation_p ("foo"));
103*38fd1498Szrj   ASSERT_FALSE (name_reserved_for_implementation_p ("_"));
104*38fd1498Szrj   ASSERT_FALSE (name_reserved_for_implementation_p ("_foo"));
105*38fd1498Szrj   ASSERT_FALSE (name_reserved_for_implementation_p ("_42"));
106*38fd1498Szrj   ASSERT_TRUE (name_reserved_for_implementation_p ("_Foo"));
107*38fd1498Szrj   ASSERT_TRUE (name_reserved_for_implementation_p ("__"));
108*38fd1498Szrj   ASSERT_TRUE (name_reserved_for_implementation_p ("__foo"));
109*38fd1498Szrj }
110*38fd1498Szrj 
111*38fd1498Szrj /* Run all of the selftests within this file.  */
112*38fd1498Szrj 
113*38fd1498Szrj void
c_spellcheck_cc_tests()114*38fd1498Szrj c_spellcheck_cc_tests ()
115*38fd1498Szrj {
116*38fd1498Szrj   test_name_reserved_for_implementation_p ();
117*38fd1498Szrj }
118*38fd1498Szrj 
119*38fd1498Szrj } // namespace selftest
120*38fd1498Szrj 
121*38fd1498Szrj #endif /* #if CHECKING_P */
122