1 | /* Sets of function names. |
2 | Copyright (C) 2019-2024 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 |
35 | 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 (s1: name, s2: 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 |
59 | 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 |
70 | 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 |
81 | 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 |
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 |
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 |
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 |
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 = ARRAY_SIZE (example); |
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 |
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 | |