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