1 /* Sets of function names.
2    Copyright (C) 2019-2020 Free Software Foundation, Inc.
3    Contributed by David Malcolm <dmalcolm@redhat.com>.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "selftest.h"
26 #include "analyzer/function-set.h"
27 
28 #if ENABLE_ANALYZER
29 
30 namespace ana {
31 
32 /* Return true if NAME is within this set.  */
33 
34 bool
contains_name_p(const char * name) const35 function_set::contains_name_p (const char *name) const
36 {
37   /* Binary search.  */
38   int min = 0;
39   int max = m_count - 1;
40   while (true)
41     {
42       if (min > max)
43 	return false;
44       int midpoint = (min + max) / 2;
45       gcc_assert ((size_t)midpoint < m_count);
46       int cmp = strcmp (name, m_names[midpoint]);
47       if (cmp == 0)
48 	return true;
49       else if (cmp < 0)
50 	max = midpoint - 1;
51       else
52 	min = midpoint + 1;
53     }
54 }
55 
56 /* Return true if FNDECL is within this set.  */
57 
58 bool
contains_decl_p(tree fndecl) const59 function_set::contains_decl_p (tree fndecl) const
60 {
61   gcc_assert (fndecl && DECL_P (fndecl));
62   if (!maybe_special_function_p (fndecl))
63     return false;
64   return contains_name_p (IDENTIFIER_POINTER (DECL_NAME (fndecl)));
65 }
66 
67 /* Assert that the list of names is in sorted order.  */
68 
69 void
assert_sorted() const70 function_set::assert_sorted () const
71 {
72 #if CHECKING_P
73   for (size_t idx = 1; idx < m_count; idx++)
74     gcc_assert (strcmp (m_names[idx - 1], m_names[idx]) < 0);
75 #endif /* #if CHECKING_P  */
76 }
77 
78 /* Assert that contains_p is true for all members of the set.  */
79 
80 void
assert_sane() const81 function_set::assert_sane () const
82 {
83 #if CHECKING_P
84   for (size_t i = 0; i < m_count; i++)
85     gcc_assert (contains_name_p (m_names[i]));
86 #endif /* #if CHECKING_P  */
87 }
88 
89 #if CHECKING_P
90 
91 namespace selftest {
92 
93 /* Verify that an empty function_set works as expected.  */
94 
95 static void
test_empty()96 test_empty ()
97 {
98   function_set fs (NULL, 0);
99   fs.assert_sorted ();
100   fs.assert_sane ();
101   ASSERT_FALSE (fs.contains_name_p (""));
102   ASSERT_FALSE (fs.contains_name_p ("haystack"));
103 }
104 
105 /* Verify that a function_set with an odd number of elements works as
106    expected.  */
107 
108 static void
test_odd()109 test_odd ()
110 {
111   static const char * const names[3] = {"alpha", "beta", "gamma"};
112   function_set fs (names, 3);
113   fs.assert_sorted ();
114   fs.assert_sane ();
115   ASSERT_FALSE (fs.contains_name_p (""));
116   ASSERT_FALSE (fs.contains_name_p ("haystack"));
117 }
118 
119 /* Verify that a function_set with an even number of elements works as
120    expected.  */
121 
122 static void
test_even()123 test_even ()
124 {
125   static const char * const names[3] = {"alpha", "beta"};
126   function_set fs (names, 2);
127   fs.assert_sorted ();
128   fs.assert_sane ();
129   ASSERT_FALSE (fs.contains_name_p (""));
130   ASSERT_FALSE (fs.contains_name_p ("haystack"));
131 }
132 
133 /* Verify that a function_set with some nontrivial stdio.h data works as
134    expected.  */
135 
136 static void
test_stdio_example()137 test_stdio_example ()
138 {
139   static const char * const example[] = {
140     "__fbufsize",
141     "__flbf",
142     "__fpending",
143     "__fpurge",
144     "__freadable",
145     "__freading",
146     "__fsetlocking",
147     "__fwritable",
148     "__fwriting",
149     "clearerr_unlocked",
150     "feof_unlocked",
151     "ferror_unlocked",
152     "fflush_unlocked",
153     "fgetc_unlocked",
154     "fgets",
155     "fgets_unlocked",
156     "fgetwc_unlocked",
157     "fgetws_unlocked",
158     "fileno_unlocked",
159     "fputc_unlocked",
160     "fputs_unlocked",
161     "fputwc_unlocked",
162     "fputws_unlocked",
163     "fread_unlocked",
164     "fwrite_unlocked",
165     "getc_unlocked",
166     "getwc_unlocked",
167     "putc_unlocked"
168   };
169   const size_t count = sizeof(example) / sizeof (example[0]);
170   function_set fs (example, count);
171   fs.assert_sorted ();
172   fs.assert_sane ();
173   /* Examples of strings not present: before, after and alongside the
174      sorted list.  */
175   ASSERT_FALSE (fs.contains_name_p ("___"));
176   ASSERT_FALSE (fs.contains_name_p ("Z"));
177   ASSERT_FALSE (fs.contains_name_p ("fgets_WITH_A_PREFIX"));
178 }
179 
180 /* Run all of the selftests within this file.  */
181 
182 void
analyzer_function_set_cc_tests()183 analyzer_function_set_cc_tests ()
184 {
185   test_empty ();
186   test_odd ();
187   test_even ();
188   test_stdio_example ();
189 }
190 
191 } // namespace selftest
192 
193 #endif /* CHECKING_P */
194 
195 } // namespace ana
196 
197 #endif /* #if ENABLE_ANALYZER */
198