Line data Source code
1 : /* Automatic generation of links into GCC's documentation.
2 : Copyright (C) 2023-2026 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 under
8 : the terms of the GNU General Public License as published by the Free
9 : Software Foundation; either version 3, or (at your option) any later
10 : version.
11 :
12 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : 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 : #define INCLUDE_MEMORY
22 : #include "config.h"
23 : #include "system.h"
24 : #include "coretypes.h"
25 : #include "pretty-print.h"
26 : #include "pretty-print-urlifier.h"
27 : #include "gcc-urlifier.h"
28 : #include "opts.h"
29 : #include "options.h"
30 : #include "diagnostic.h"
31 : #include "selftest.h"
32 : #include "target.h"
33 :
34 : /* class attribute_urlifier : public urlifier. */
35 :
36 : /* By default, use the target's documentation name. */
37 :
38 1942308837 : attribute_urlifier::attribute_urlifier ()
39 1942308837 : : m_target_docs_name (targetm.documentation_name)
40 : {
41 1942308837 : }
42 :
43 : /* Explicitly specify a target's documentation name, for use in selftests. */
44 :
45 12 : attribute_urlifier::attribute_urlifier (const char *target_docs_name)
46 12 : : m_target_docs_name (target_docs_name)
47 : {
48 12 : }
49 :
50 : struct attr_url_entry
51 : {
52 : const char *m_name;
53 : const char *m_url_suffix;
54 : const char *m_target_docs_name;
55 : size_t m_name_len;
56 : };
57 :
58 : #include "attr-urls.def"
59 :
60 : /* We look in two passes: first for an exact match on target name (if any).
61 : Otherwise, we look for one with an empty target name. */
62 :
63 : /* Search for STR, LEN in the given TABLE.
64 : If TARGET_DOCS_NAME is non-null, then look for an exact match on target name.
65 : If TARGET_DOCS_NAME is null, then look for an empty string for the
66 : target name. */
67 :
68 :
69 : static const attr_url_entry *
70 34502 : find_attr_url_entry (const char *str,
71 : size_t str_len,
72 : const char *target_docs_name,
73 : const attr_url_entry *table,
74 : size_t table_sz)
75 : {
76 : /* This is linear search, but TABLE_SZ ought not to be very large. */
77 9132980 : for (size_t i = 0; i < table_sz; i++)
78 9102978 : if (str_len == table[i].m_name_len)
79 520413 : if (0 == strncmp (str, table[i].m_name, str_len))
80 : {
81 10137 : if (target_docs_name)
82 : {
83 : /* Reject entries with m_target_docs_name that doesn't match. */
84 5828 : if (strcmp (target_docs_name, table[i].m_target_docs_name))
85 5606 : continue;
86 : }
87 : else
88 : {
89 : /* Reject entries for which m_target_docs_name is non-empty. */
90 4309 : if (table[i].m_target_docs_name[0])
91 31 : continue;
92 : }
93 : return &table[i];
94 : }
95 :
96 : return nullptr;
97 : }
98 :
99 : /* Search for STR, LEN in all of the attribute tables, in order.
100 : TARGET_DOCS_NAME works as above. */
101 :
102 : static const attr_url_entry *
103 34502 : find_attr_url_entry (const char *str,
104 : size_t str_len,
105 : const char *target_docs_name)
106 : {
107 64504 : for (size_t table_idx = 0; table_idx < ARRAY_SIZE (attr_url_tables);
108 : table_idx++)
109 34502 : if (const attr_url_entry *entry
110 34502 : = find_attr_url_entry (str, str_len, target_docs_name,
111 : attr_url_tables[table_idx].m_table,
112 : attr_url_tables[table_idx].m_table_sz))
113 : return entry;
114 :
115 : return nullptr;
116 : }
117 :
118 : char *
119 17314 : attribute_urlifier::get_url_for_quoted_text (const char *p,
120 : size_t sz) const
121 : {
122 17314 : label_text url_suffix = get_url_suffix_for_quoted_text (p, sz);
123 17314 : if (url_suffix.get ())
124 4460 : return make_doc_url (url_suffix.get ());
125 : return nullptr;
126 17314 : }
127 :
128 : label_text
129 17362 : attribute_urlifier::get_url_suffix_for_quoted_text (const char *p,
130 : size_t sz) const
131 : {
132 : /* Skip any text after a non-identifier character, so that
133 : e.g. given "access(read_write, 2, 3)" we only compare
134 : against "access". */
135 148108 : for (size_t i = 0; i < sz; i++)
136 135297 : if (!ISIDNUM (p[i]))
137 : {
138 : /* Truncate to p[0..i). */
139 : sz = i;
140 : break;
141 : }
142 :
143 17362 : if (m_target_docs_name)
144 17362 : if (const attr_url_entry *entry
145 17362 : = find_attr_url_entry (p, sz, m_target_docs_name))
146 222 : return label_text::borrow (entry->m_url_suffix);
147 :
148 17140 : if (const attr_url_entry *entry = find_attr_url_entry (p, sz, nullptr))
149 4278 : return label_text::borrow (entry->m_url_suffix);
150 :
151 12862 : return label_text ();
152 : }
153 :
154 : label_text
155 48 : attribute_urlifier::get_url_suffix_for_quoted_text (const char *p) const
156 : {
157 48 : return get_url_suffix_for_quoted_text (p, strlen (p));
158 : }
159 :
160 : #if CHECKING_P
161 :
162 : namespace selftest {
163 :
164 : /* Selftests. */
165 :
166 : static void
167 4 : test_attribute_urlifier ()
168 : {
169 4 : attribute_urlifier u;
170 :
171 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text ("").get (), nullptr);
172 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text (")").get (), nullptr);
173 :
174 : /* Examples of function attributes. */
175 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("alias").get (),
176 : "gcc/Common-Attributes.html#index-alias");
177 :
178 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text
179 : ("access(read_write, 2, 3)").get (),
180 : "gcc/Common-Attributes.html#index-access");
181 :
182 : /* Example of enumerator attribute. */
183 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("deprecated").get (),
184 : "gcc/Common-Attributes.html#index-deprecated");
185 :
186 : /* Example of statement attribute. */
187 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("assume").get (),
188 : "gcc/Common-Attributes.html#index-assume");
189 :
190 : /* Examples of type attributes. */
191 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("hardbool").get (),
192 : "gcc/Common-Attributes.html#index-hardbool");
193 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("packed").get (),
194 : "gcc/Common-Attributes.html#index-packed");
195 :
196 : /* Example of variable attribute. */
197 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("nonstring").get (),
198 : "gcc/Common-Attributes.html#index-nonstring");
199 :
200 : /* Example of target-specific attributes.
201 : For example, "interrupt" has many target-specific documentation URLs. */
202 4 : {
203 4 : attribute_urlifier u_rl78 ("RL78");
204 4 : attribute_urlifier u_x86 ("x86");
205 4 : attribute_urlifier u_unrecognized ("not-a-target");
206 :
207 4 : ASSERT_STREQ (u_rl78.get_url_suffix_for_quoted_text ("interrupt").get (),
208 : "gcc/RL78-Attributes.html#index-interrupt_002c-RL78");
209 4 : ASSERT_STREQ (u_x86.get_url_suffix_for_quoted_text ("interrupt").get (),
210 : "gcc/x86-Attributes.html#index-interrupt_002c-x86");
211 4 : ASSERT_STREQ (u_unrecognized.get_url_suffix_for_quoted_text
212 : ("interrupt").get (),
213 : "gcc/Common-Attributes.html#index-interrupt");
214 4 : }
215 4 : }
216 :
217 : /* Run all of the selftests within this file. */
218 :
219 : void
220 4 : gcc_attribute_urlifier_cc_tests ()
221 : {
222 4 : test_attribute_urlifier ();
223 4 : }
224 :
225 : } // namespace selftest
226 :
227 : #endif /* #if CHECKING_P */
|