| /* Sets of function names. | |
| Copyright (C) 2019-2026 Free Software Foundation, Inc. | |
| Contributed by David Malcolm <dmalcolm@redhat.com>. | |
| 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 "tree.h" | |
| #include "selftest.h" | |
| #include "analyzer/function-set.h" | |
| #if ENABLE_ANALYZER | |
| namespace ana { | |
| /* Return true if NAME is within this set. */ | |
| bool | |
| function_set::contains_name_p (const char *name) const | |
| { | |
| /* Binary search. */ | |
| int min = 0; | |
| int max = m_count - 1; | |
| while (true) | |
| { | |
| if (min > max) | |
| return false; | |
| int midpoint = (min + max) / 2; | |
| gcc_assert ((size_t)midpoint < m_count); | |
| int cmp = strcmp (name, m_names[midpoint]); | |
| if (cmp == 0) | |
| return true; | |
| else if (cmp < 0) | |
| max = midpoint - 1; | |
| else | |
| min = midpoint + 1; | |
| } | |
| } | |
| /* Return true if FNDECL is within this set. */ | |
| bool | |
| function_set::contains_decl_p (tree fndecl) const | |
| { | |
| gcc_assert (fndecl && DECL_P (fndecl)); | |
| if (!maybe_special_function_p (fndecl)) | |
| return false; | |
| return contains_name_p (IDENTIFIER_POINTER (DECL_NAME (fndecl))); | |
| } | |
| /* Assert that the list of names is in sorted order. */ | |
| void | |
| function_set::assert_sorted () const | |
| { | |
| #if CHECKING_P | |
| for (size_t idx = 1; idx < m_count; idx++) | |
| gcc_assert (strcmp (m_names[idx - 1], m_names[idx]) < 0); | |
| #endif /* #if CHECKING_P */ | |
| } | |
| /* Assert that contains_p is true for all members of the set. */ | |
| void | |
| function_set::assert_sane () const | |
| { | |
| #if CHECKING_P | |
| for (size_t i = 0; i < m_count; i++) | |
| gcc_assert (contains_name_p (m_names[i])); | |
| #endif /* #if CHECKING_P */ | |
| } | |
| #if CHECKING_P | |
| namespace selftest { | |
| /* Verify that an empty function_set works as expected. */ | |
| static void | |
| test_empty () | |
| { | |
| function_set fs (nullptr, 0); | |
| fs.assert_sorted (); | |
| fs.assert_sane (); | |
| ASSERT_FALSE (fs.contains_name_p ("")); | |
| ASSERT_FALSE (fs.contains_name_p ("haystack")); | |
| } | |
| /* Verify that a function_set with an odd number of elements works as | |
| expected. */ | |
| static void | |
| test_odd () | |
| { | |
| static const char * const names[3] = {"alpha", "beta", "gamma"}; | |
| function_set fs (names, 3); | |
| fs.assert_sorted (); | |
| fs.assert_sane (); | |
| ASSERT_FALSE (fs.contains_name_p ("")); | |
| ASSERT_FALSE (fs.contains_name_p ("haystack")); | |
| } | |
| /* Verify that a function_set with an even number of elements works as | |
| expected. */ | |
| static void | |
| test_even () | |
| { | |
| static const char * const names[3] = {"alpha", "beta"}; | |
| function_set fs (names, 2); | |
| fs.assert_sorted (); | |
| fs.assert_sane (); | |
| ASSERT_FALSE (fs.contains_name_p ("")); | |
| ASSERT_FALSE (fs.contains_name_p ("haystack")); | |
| } | |
| /* Verify that a function_set with some nontrivial stdio.h data works as | |
| expected. */ | |
| static void | |
| test_stdio_example () | |
| { | |
| static const char * const example[] = { | |
| "__fbufsize", | |
| "__flbf", | |
| "__fpending", | |
| "__fpurge", | |
| "__freadable", | |
| "__freading", | |
| "__fsetlocking", | |
| "__fwritable", | |
| "__fwriting", | |
| "clearerr_unlocked", | |
| "feof_unlocked", | |
| "ferror_unlocked", | |
| "fflush_unlocked", | |
| "fgetc_unlocked", | |
| "fgets", | |
| "fgets_unlocked", | |
| "fgetwc_unlocked", | |
| "fgetws_unlocked", | |
| "fileno_unlocked", | |
| "fputc_unlocked", | |
| "fputs_unlocked", | |
| "fputwc_unlocked", | |
| "fputws_unlocked", | |
| "fread_unlocked", | |
| "fwrite_unlocked", | |
| "getc_unlocked", | |
| "getwc_unlocked", | |
| "putc_unlocked" | |
| }; | |
| const size_t count = ARRAY_SIZE (example); | |
| function_set fs (example, count); | |
| fs.assert_sorted (); | |
| fs.assert_sane (); | |
| /* Examples of strings not present: before, after and alongside the | |
| sorted list. */ | |
| ASSERT_FALSE (fs.contains_name_p ("___")); | |
| ASSERT_FALSE (fs.contains_name_p ("Z")); | |
| ASSERT_FALSE (fs.contains_name_p ("fgets_WITH_A_PREFIX")); | |
| } | |
| /* Run all of the selftests within this file. */ | |
| void | |
| analyzer_function_set_cc_tests () | |
| { | |
| test_empty (); | |
| test_odd (); | |
| test_even (); | |
| test_stdio_example (); | |
| } | |
| } // namespace selftest | |
| #endif /* CHECKING_P */ | |
| } // namespace ana | |
| #endif /* #if ENABLE_ANALYZER */ |