/* Automatic generation of links into GCC's documentation. Copyright (C) 2023-2025 Free Software Foundation, Inc. Contributed by David Malcolm . 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 . */ #define INCLUDE_MEMORY #include "config.h" #include "system.h" #include "coretypes.h" #include "pretty-print.h" #include "pretty-print-urlifier.h" #include "gcc-urlifier.h" #include "opts.h" #include "options.h" #include "diagnostic.h" #include "selftest.h" #include "make-unique.h" #include "target.h" /* class attribute_urlifier : public urlifier. */ /* By default, use the target's documentation name. */ attribute_urlifier::attribute_urlifier () : m_target_docs_name (targetm.documentation_name) { } /* Explicitly specify a target's documentation name, for use in selftests. */ attribute_urlifier::attribute_urlifier (const char *target_docs_name) : m_target_docs_name (target_docs_name) { } struct attr_url_entry { const char *m_name; const char *m_url_suffix; const char *m_target_docs_name; size_t m_name_len; }; #include "attr-urls.def" /* We look in two passes: first for an exact match on target name (if any). Otherwise, we look for one with an empty target name. */ /* Search for STR, LEN in the given TABLE. If TARGET_DOCS_NAME is non-null, then look for an exact match on target name. If TARGET_DOCS_NAME is null, then look for an empty string for the target name. */ static const attr_url_entry * find_attr_url_entry (const char *str, size_t str_len, const char *target_docs_name, const attr_url_entry *table, size_t table_sz) { /* This is linear search, but TABLE_SZ ought not to be very large. */ for (size_t i = 0; i < table_sz; i++) if (str_len == table[i].m_name_len) if (0 == strncmp (str, table[i].m_name, str_len)) { if (target_docs_name) { /* Reject entries with m_target_docs_name that doesn't match. */ if (strcmp (target_docs_name, table[i].m_target_docs_name)) continue; } else { /* Reject entries for which m_target_docs_name is non-empty. */ if (table[i].m_target_docs_name[0]) continue; } return &table[i]; } return nullptr; } /* Search for STR, LEN in all of the attribute tables, in order. TARGET_DOCS_NAME works as above. */ static const attr_url_entry * find_attr_url_entry (const char *str, size_t str_len, const char *target_docs_name) { for (size_t table_idx = 0; table_idx < ARRAY_SIZE (attr_url_tables); table_idx++) if (const attr_url_entry *entry = find_attr_url_entry (str, str_len, target_docs_name, attr_url_tables[table_idx].m_table, attr_url_tables[table_idx].m_table_sz)) return entry; return nullptr; } char * attribute_urlifier::get_url_for_quoted_text (const char *p, size_t sz) const { label_text url_suffix = get_url_suffix_for_quoted_text (p, sz); if (url_suffix.get ()) return make_doc_url (url_suffix.get ()); return nullptr; } label_text attribute_urlifier::get_url_suffix_for_quoted_text (const char *p, size_t sz) const { /* Skip any text after a non-identifier character, so that e.g. given "access(read_write, 2, 3)" we only compare against "access". */ for (size_t i = 0; i < sz; i++) if (!ISIDNUM (p[i])) { /* Truncate to p[0..i). */ sz = i; break; } if (m_target_docs_name) if (const attr_url_entry *entry = find_attr_url_entry (p, sz, m_target_docs_name)) return label_text::borrow (entry->m_url_suffix); if (const attr_url_entry *entry = find_attr_url_entry (p, sz, nullptr)) return label_text::borrow (entry->m_url_suffix); return label_text (); } label_text attribute_urlifier::get_url_suffix_for_quoted_text (const char *p) const { return get_url_suffix_for_quoted_text (p, strlen (p)); } #if CHECKING_P namespace selftest { /* Selftests. */ static void test_attribute_urlifier () { attribute_urlifier u; ASSERT_EQ (u.get_url_suffix_for_quoted_text ("").get (), nullptr); ASSERT_EQ (u.get_url_suffix_for_quoted_text (")").get (), nullptr); /* Examples of function attributes. */ ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("alias").get (), "gcc/Common-Function-Attributes.html" "#index-alias-function-attribute"); ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("access(read_write, 2, 3)").get (), "gcc/Common-Function-Attributes.html" "#index-access-function-attribute"); /* Example of enumerator attribute. */ ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("deprecated").get (), "gcc/Enumerator-Attributes.html" "#index-deprecated-enumerator-attribute"); /* We don't yet have an example of a label attribute, since all label attributes have a matching function attribute of the same name, which is found first. */ /* Example of statement attribute. */ ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("assume").get (), "gcc/Statement-Attributes.html" "#index-assume-statement-attribute"); /* Examples of type attributes. */ ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("hardbool").get (), "gcc/Common-Type-Attributes.html" "#index-hardbool-type-attribute"); ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("packed").get (), "gcc/Common-Type-Attributes.html" "#index-packed-type-attribute"); /* Example of variable attribute. */ ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("nonstring").get (), "gcc/Common-Variable-Attributes.html" "#index-nonstring-variable-attribute"); /* Example of target-specific attributes. For example, "interrupt" has many target-specific documentation URLs. */ { attribute_urlifier u_rl78 ("RL78"); attribute_urlifier u_x86 ("x86"); attribute_urlifier u_unrecognized ("not-a-target"); ASSERT_STREQ (u_rl78.get_url_suffix_for_quoted_text ("interrupt").get (), "gcc/RL78-Function-Attributes.html" "#index-interrupt-function-attribute_002c-RL78"); ASSERT_STREQ (u_x86.get_url_suffix_for_quoted_text ("interrupt").get (), "gcc/x86-Function-Attributes.html" "#index-interrupt-function-attribute_002c-x86"); ASSERT_STREQ (u_unrecognized.get_url_suffix_for_quoted_text ("interrupt").get (), "gcc/Common-Function-Attributes.html" "#index-interrupt-function-attribute"); } } /* Run all of the selftests within this file. */ void gcc_attribute_urlifier_cc_tests () { test_attribute_urlifier (); } } // namespace selftest #endif /* #if CHECKING_P */