mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
243 lines
6.9 KiB
C++
243 lines
6.9 KiB
C++
/* Automatic generation of links into GCC's documentation.
|
|
Copyright (C) 2023-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/>. */
|
|
|
|
#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 "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 */
|