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 : #include "config.h"
22 : #include "system.h"
23 : #include "coretypes.h"
24 : #include "pretty-print.h"
25 : #include "pretty-print-urlifier.h"
26 : #include "gcc-urlifier.h"
27 : #include "opts.h"
28 : #include "options.h"
29 : #include "diagnostic.h"
30 : #include "selftest.h"
31 :
32 : char *
33 18794 : make_doc_url (const char *doc_url_suffix)
34 : {
35 18794 : if (!doc_url_suffix)
36 : return nullptr;
37 :
38 18794 : return concat (DOCUMENTATION_ROOT_URL, doc_url_suffix, nullptr);
39 : }
40 :
41 : namespace {
42 :
43 : /* Concrete subclass of urlifier for generating links into
44 : GCC's HTML documentation. */
45 :
46 0 : class gcc_urlifier : public urlifier
47 : {
48 : public:
49 579711 : gcc_urlifier (unsigned int lang_mask)
50 579707 : : m_lang_mask (lang_mask)
51 : {}
52 :
53 : char *get_url_for_quoted_text (const char *p, size_t sz) const final override;
54 :
55 : label_text get_url_suffix_for_quoted_text (const char *p, size_t sz) const;
56 : /* We use ATTRIBUTE_UNUSED as this helper is called only from ASSERTs. */
57 : label_text get_url_suffix_for_quoted_text (const char *p) const ATTRIBUTE_UNUSED;
58 :
59 : private:
60 : label_text get_url_suffix_for_option (const char *p, size_t sz) const;
61 :
62 : unsigned int m_lang_mask;
63 : };
64 :
65 : /* class gcc_urlifier : public urlifier. */
66 :
67 : /* Manage a hard-coded mapping from quoted string to URL suffixes
68 : in gcc-urlifier.def */
69 :
70 : #define DOC_URL(QUOTED_TEXT, URL_SUFFIX) \
71 : { (QUOTED_TEXT), (URL_SUFFIX) }
72 :
73 : static const struct
74 : {
75 : const char *quoted_text;
76 : const char *url_suffix;
77 : } doc_urls[] = {
78 :
79 : #include "gcc-urlifier.def"
80 :
81 : };
82 :
83 : /* Implementation of urlifier::get_url_for_quoted_text vfunc for GCC
84 : diagnostics. */
85 :
86 : char *
87 865912 : gcc_urlifier::get_url_for_quoted_text (const char *p, size_t sz) const
88 : {
89 865912 : label_text url_suffix = get_url_suffix_for_quoted_text (p, sz);
90 865912 : if (url_suffix.get ())
91 14334 : return make_doc_url (url_suffix.get ());
92 : return nullptr;
93 865912 : }
94 :
95 : /* Look for a URL for the quoted string (P, SZ).
96 : Return the url suffix if found, or nullptr otherwise. */
97 :
98 : label_text
99 866004 : gcc_urlifier::get_url_suffix_for_quoted_text (const char *p, size_t sz) const
100 : {
101 866004 : if (sz == 0)
102 4 : return label_text ();
103 :
104 : /* If this is an option, look up the option and see if we have
105 : a URL for it. */
106 866000 : if (p[0] == '-')
107 : {
108 29087 : label_text suffix = get_url_suffix_for_option (p, sz);
109 29087 : if (suffix.get ())
110 14173 : return suffix;
111 29087 : }
112 :
113 : /* Otherwise, look within the hard-coded data table in gcc-urlifier.def.
114 :
115 : Binary search. This assumes that the quoted_text fields of doc_urls
116 : are in sorted order. */
117 851827 : int min = 0;
118 851827 : int max = ARRAY_SIZE (doc_urls) - 1;
119 5105432 : while (true)
120 : {
121 5105432 : if (min > max)
122 851586 : return label_text ();
123 4253846 : int midpoint = (min + max) / 2;
124 4253846 : gcc_assert ((size_t)midpoint < ARRAY_SIZE (doc_urls));
125 4253846 : int cmp = strncmp (p, doc_urls[midpoint].quoted_text, sz);
126 4253846 : if (cmp == 0)
127 : {
128 810 : if (doc_urls[midpoint].quoted_text[sz] == '\0')
129 241 : return label_text::borrow (doc_urls[midpoint].url_suffix);
130 : else
131 569 : max = midpoint - 1;
132 : }
133 4253036 : else if (cmp < 0)
134 13484 : max = midpoint - 1;
135 : else
136 4239552 : min = midpoint + 1;
137 : }
138 :
139 : /* Not found. */
140 : return label_text ();
141 : }
142 :
143 : /* For use in selftests. */
144 :
145 : label_text
146 92 : gcc_urlifier::get_url_suffix_for_quoted_text (const char *p) const
147 : {
148 92 : return get_url_suffix_for_quoted_text (p, strlen (p));
149 : }
150 :
151 : /* Look for a URL for the quoted string (P, SZ) that appears to be
152 : an option.
153 : Return the url suffix if found, or nullptr otherwise. */
154 :
155 : label_text
156 29087 : gcc_urlifier::get_url_suffix_for_option (const char *p, size_t sz) const
157 : {
158 : /* Look up this option
159 :
160 : find_opt does a binary search, taking a 0-terminated string,
161 : and skipping the leading '-'.
162 :
163 : We have a (pointer,size) pair that doesn't necessarily have a
164 : terminator.
165 : Additionally, we could have one of the e.g. "-Wno-" variants of
166 : the option, which find_opt doesn't handle.
167 :
168 : Hence we need to create input for find_opt in a temporary buffer. */
169 29087 : char *option_buffer;
170 :
171 29087 : const char *new_prefix;
172 29087 : if (const char *old_prefix = get_option_prefix_remapping (p, sz, &new_prefix))
173 : {
174 : /* We have one of the variants; generate a buffer containing a copy
175 : that maps from the old prefix to the new prefix
176 : e.g. given "-Wno-suffix", generate "-Wsuffix". */
177 9908 : gcc_assert (old_prefix[0] == '-');
178 9908 : gcc_assert (new_prefix);
179 9908 : gcc_assert (new_prefix[0] == '-');
180 :
181 9908 : const size_t old_prefix_len = strlen (old_prefix);
182 9908 : gcc_assert (old_prefix_len <= sz);
183 9908 : const size_t suffix_len = sz - old_prefix_len;
184 9908 : const size_t new_prefix_len = strlen (new_prefix);
185 9908 : const size_t new_sz = new_prefix_len + suffix_len + 1;
186 :
187 9908 : option_buffer = (char *)xmalloc (new_sz);
188 9908 : memcpy (option_buffer, new_prefix, new_prefix_len);
189 : /* Copy suffix. */
190 9908 : memcpy (option_buffer + new_prefix_len, p + old_prefix_len, suffix_len);
191 : /* Terminate. */
192 9908 : option_buffer[new_prefix_len + suffix_len] = '\0';
193 : }
194 : else
195 : {
196 : /* Otherwise we can simply create a 0-terminated clone of the string. */
197 19179 : gcc_assert (sz > 0);
198 19179 : gcc_assert (p[0] == '-');
199 19179 : option_buffer = xstrndup (p, sz);
200 : }
201 :
202 29087 : size_t opt = find_opt (option_buffer + 1, m_lang_mask);
203 29087 : free (option_buffer);
204 :
205 29087 : if (opt >= N_OPTS)
206 : /* Option not recognized. */
207 2869 : return label_text ();
208 :
209 26218 : return get_option_url_suffix (opt, m_lang_mask);
210 : }
211 :
212 : } // anonymous namespace
213 :
214 : std::unique_ptr<urlifier>
215 579707 : make_gcc_urlifier (unsigned int lang_mask)
216 : {
217 579707 : return std::make_unique<gcc_urlifier> (lang_mask);
218 : }
219 :
220 : /* class auto_override_urlifier. */
221 :
222 1942308833 : auto_override_urlifier::auto_override_urlifier (const urlifier &new_urlifier)
223 : {
224 1942308833 : global_dc->push_borrowed_urlifier (new_urlifier);
225 1942308833 : }
226 :
227 1942308832 : auto_override_urlifier::~auto_override_urlifier ()
228 : {
229 1942308832 : global_dc->pop_urlifier ();
230 1942308832 : }
231 :
232 : #if CHECKING_P
233 :
234 : namespace selftest {
235 :
236 : /* Selftests. */
237 :
238 : static void
239 4 : test_gcc_urlifier ()
240 : {
241 : /* Check that doc_urls.quoted_text is sorted. */
242 68 : for (size_t idx = 1; idx < ARRAY_SIZE (doc_urls); idx++)
243 64 : gcc_assert (strcmp (doc_urls[idx - 1].quoted_text,
244 : doc_urls[idx].quoted_text)
245 : < 0);
246 :
247 4 : gcc_urlifier u (0);
248 :
249 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text ("").get (), nullptr);
250 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text (")").get (), nullptr);
251 :
252 4 : ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("#pragma message").get (),
253 : "gcc/Diagnostic-Pragmas.html");
254 :
255 : // Incomplete prefix of a quoted_text
256 4 : ASSERT_EQ (u.get_url_suffix_for_quoted_text ("#pragma mess").get (), nullptr);
257 :
258 : /* Check that every element is findable. */
259 72 : for (size_t idx = 0; idx < ARRAY_SIZE (doc_urls); idx++)
260 68 : ASSERT_STREQ
261 : (u.get_url_suffix_for_quoted_text (doc_urls[idx].quoted_text).get (),
262 : doc_urls[idx].url_suffix);
263 :
264 : /* Check an option. */
265 4 : const char *s1 = u.get_url_suffix_for_quoted_text ("-fpack-struct").get ();
266 4 : ASSERT_TRUE (!strcmp (s1,
267 : "gcc/Code-Gen-Options.html#index-fno-pack-struct")
268 : || !strcmp (s1,
269 : "gcc/Code-Gen-Options.html#index-fpack-struct"));
270 :
271 : /* Check a "-fno-" variant of an option. */
272 4 : const char *s2 = u.get_url_suffix_for_quoted_text ("-fno-inline").get ();
273 4 : ASSERT_TRUE (!strcmp (s2,
274 : "gcc/Optimize-Options.html#index-fno-inline")
275 : || !strcmp (s2,
276 : "gcc/Optimize-Options.html#index-finline"));
277 4 : }
278 :
279 : /* Run all of the selftests within this file. */
280 :
281 : void
282 4 : gcc_urlifier_cc_tests ()
283 : {
284 4 : test_gcc_urlifier ();
285 4 : }
286 :
287 : } // namespace selftest
288 :
289 : #endif /* #if CHECKING_P */
|