diff --git a/docs/modules/ROOT/pages/extensions/dom-reference.adoc b/docs/modules/ROOT/pages/extensions/dom-reference.adoc index 5d33c440f1..f91799cef5 100644 --- a/docs/modules/ROOT/pages/extensions/dom-reference.adoc +++ b/docs/modules/ROOT/pages/extensions/dom-reference.adoc @@ -76,6 +76,64 @@ The `Symbol` object represents a symbol extracted from the source code. The symb | `Any` | The documentation for the symbol. +| `attributes` +| `<>` +| The C++ attributes attached to the symbol, for example `[[deprecated]]` or `[[nodiscard]]`. + +|=== + +[#attribute-fields] +=== Attribute + +The `Attribute` object represents a single C++ attribute. Every attribute object has these common fields: + +|=== +|Property |Type| Description + +| `kind` +| `string` +| The recognized standard attribute, identified independently of spelling: one of `deprecated`, `nodiscard`, `maybe-unused`, `no-unique-address`, `noreturn`, `carries-dependency`, `fallthrough`, `likely`, `unlikely`, `assume`, `indeterminate`, or `other` for an unrecognized attribute. + +| `name` +| `string` +| The attribute name. Recognized attributes use the normalized spelling (e.g., `deprecated`, `no_unique_address`); unrecognized ones keep the written spelling, including any scope (e.g., `gnu::custom`). + +| `balancedTokens` +| `string[]` +| The arguments as a balanced-token sequence, one per element (e.g., `["printf", "1", "2"]` for `[[gnu::format(printf, 1, 2)]]`). String-literal arguments keep their quotes. Empty for attributes that take no arguments. + +|=== + +Some attribute kinds add a field for an evaluated argument. Templates should branch on `kind` and read these directly (for example, the deprecation notice prints `message`) rather than parsing `balancedTokens`. + +When the attribute kind is `deprecated`, the attribute object has the following additional property: + +|=== +|Property |Type| Description + +| `message` +| `string` +| The deprecation message, without quotes (e.g., `use bar instead` for `[[deprecated("use bar instead")]]`). Empty when no message was given. +|=== + +When the attribute kind is `nodiscard`, the attribute object has the following additional property: + +|=== +|Property |Type| Description + +| `reason` +| `string` +| The reason the result should not be discarded, without quotes (the C++20 `[[nodiscard("reason")]]` form). Empty otherwise. +|=== + +When the attribute kind is `assume`, the attribute object has the following additional property: + +|=== +|Property |Type| Description + +| `expression` +| `string` +| The assumed expression (the C++23 `[[assume(expression)]]` form). |=== Handlebars generators extend each symbol with the following fields: @@ -217,10 +275,6 @@ When the symbol kind is `function`, the symbol object has the following addition | `bool` | Whether the function is deleted as written. -| `isNoReturn` -| `bool` -| Whether the function is noreturn. - | `hasOverrideAttr` | `bool` | Whether the function has the override attribute. @@ -241,10 +295,6 @@ When the symbol kind is `function`, the symbol object has the following addition | `bool` | Whether the function is final. -| `isNodiscard` -| `bool` -| Whether the function is nodiscard. - | `isExplicitObjectMemberFunction` | `bool` | Whether the function is an explicit object member function. @@ -292,10 +342,6 @@ When the symbol kind is `function`, the symbol object has the following addition | `requires` | `string` | The `requires` expression of the function. - -| `attributes` -| `string[]` -| The attributes of the function. |=== When the symbol kind is `typedef`, the symbol object has the following additional properties: @@ -352,10 +398,6 @@ When the symbol kind is `variable`, the symbol object has the following addition | `initializer` | `string` | The initializer of the variable. - -| `attributes` -| `string[]` -| The attributes of the variable. |=== When the symbol kind is `field` (i.e. non-static data members), the symbol object has the following additional properties: @@ -371,14 +413,6 @@ When the symbol kind is `field` (i.e. non-static data members), the symbol objec | `string` | The default value of the field. -| `isMaybeUnused` -| `bool` -| Whether the field is maybe unused. - -| `isDeprecated` -| `bool` -| Whether the field is deprecated. - | `isVariant` | `bool` | Whether the field is a variant. @@ -391,17 +425,9 @@ When the symbol kind is `field` (i.e. non-static data members), the symbol objec | `bool` | Whether the field is a bitfield. -| `hasNoUniqueAddress` -| `string` -| Whether the field has the `[[no_unique_address]]` attribute. - | `bitfieldWidth` | `string` | The width of the bitfield. - -| `attributes` -| `string[]` -| The attributes of the field. |=== When the symbol kind is `friend`, the symbol object has the following additional properties: diff --git a/include/mrdocs/Metadata/Attribute/AssumeAttribute.hpp b/include/mrdocs/Metadata/Attribute/AssumeAttribute.hpp new file mode 100644 index 0000000000..d0361e546d --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/AssumeAttribute.hpp @@ -0,0 +1,41 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_ASSUMEATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_ASSUMEATTRIBUTE_HPP + +#include +#include +#include +#include + +namespace mrdocs { + +/** The `[[assume(expression)]]` attribute (C++23). + + States that the expression always evaluates to true at this point. +*/ +struct AssumeAttribute final + : AttributeCommonBase +{ + /** The assumed expression, as written. + */ + std::string Expression; +}; + +MRDOCS_DESCRIBE_STRUCT( + AssumeAttribute, + (Attribute), + (Expression) +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_ASSUMEATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/AttributeBase.hpp b/include/mrdocs/Metadata/Attribute/AttributeBase.hpp new file mode 100644 index 0000000000..afbeb3e2b9 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/AttributeBase.hpp @@ -0,0 +1,179 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_ATTRIBUTEBASE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_ATTRIBUTEBASE_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace mrdocs { + +class DomCorpus; + +/* Forward declarations + */ +#define INFO(PascalName) struct PascalName##Attribute; +#include + +/** A C++ attribute attached to a symbol. + + This base class stores the information common to every + attribute: the kind, the spelling name, and the raw + balanced-token sequence written between the parentheses. + Derived classes add the evaluated arguments for the + attributes that take them. +*/ +struct Attribute { + /** The kind of attribute. + */ + AttributeKind Kind; + + /** The attribute name as it appears in the standard form. + + For recognized attributes this is the normalized spelling + (e.g. `deprecated`, `no_unique_address`). For unrecognized + attributes (the `Other` kind) it is the spelling as written, + including any scope (e.g. `gnu::custom`). + */ + std::string Name; + + /** The attribute arguments as a balanced-token sequence. + + Each element is one top-level argument as rendered by Clang, + e.g. `{"printf", "1", "2"}` for `[[gnu::format(printf, 1, 2)]]`. + Empty for attributes that take no arguments. This is the raw + token form; derived classes expose evaluated arguments. + */ + std::vector balancedTokens; + + /** View this instance as a const Attribute reference. + */ + constexpr Attribute const& asAttribute() const noexcept + { + return *this; + } + + /** View this instance as a mutable Attribute reference. + */ + constexpr Attribute& asAttribute() noexcept + { + return *this; + } + + #define INFO(PascalName) constexpr bool is##PascalName() const noexcept { \ + return Kind == AttributeKind::PascalName; \ + } +#include + +#define INFO(PascalName) \ + constexpr PascalName##Attribute const& as##PascalName() const noexcept { \ + if (Kind == AttributeKind::PascalName) \ + return reinterpret_cast(*this); \ + MRDOCS_UNREACHABLE(); \ + } +#include + +#define INFO(PascalName) \ + constexpr PascalName##Attribute & as##PascalName() noexcept { \ + if (Kind == AttributeKind::PascalName) \ + return reinterpret_cast(*this); \ + MRDOCS_UNREACHABLE(); \ + } +#include + +#define INFO(PascalName) \ + constexpr PascalName##Attribute const* as##PascalName##Ptr() const noexcept { \ + if (Kind == AttributeKind::PascalName) { return reinterpret_cast(this); } \ + return nullptr; \ + } +#include + +#define INFO(PascalName) \ + constexpr PascalName##Attribute * as##PascalName##Ptr() noexcept { \ + if (Kind == AttributeKind::PascalName) { return reinterpret_cast(this); } \ + return nullptr; \ + } +#include + +protected: + /** Virtual destructor for polymorphic base. + */ + constexpr virtual ~Attribute() = default; + + /** Construct with a concrete attribute kind. + */ + constexpr explicit Attribute(AttributeKind kind) noexcept + : Kind(kind) + { + } +}; + +MRDOCS_DESCRIBE_STRUCT( + Attribute, + (), + (Kind, Name, balancedTokens) +) + +/** Serialize an Attribute into a DOM value. +*/ +MRDOCS_DECL +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + Attribute const& I, + DomCorpus const* domCorpus); + +/** CRTP base that ties a concrete attribute to a fixed AttributeKind. +*/ +template +struct AttributeCommonBase : Attribute { + /** Static discriminator for the concrete attribute. + */ + static constexpr AttributeKind kind_id = K; + + #define INFO(PascalName) \ + static constexpr bool is##PascalName() noexcept { return K == AttributeKind::PascalName; } +#include + + MRDOCS_DESCRIBE_CLASS(AttributeCommonBase, (Attribute), ()) + +protected: + /** Construct the base with the fixed kind. + */ + constexpr AttributeCommonBase() noexcept + : Attribute(K) + { + } +}; + +/** Compare two polymorphic attributes by visitor dispatch. +*/ +MRDOCS_DECL +std::strong_ordering +operator<=>(Polymorphic const&, Polymorphic const&); + +/** Equality for two polymorphic attributes. +*/ +inline bool +operator==(Polymorphic const& a, Polymorphic const& b) +{ + return std::is_eq(a <=> b); +} + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_ATTRIBUTEBASE_HPP diff --git a/include/mrdocs/Metadata/Attribute/AttributeKind.hpp b/include/mrdocs/Metadata/Attribute/AttributeKind.hpp new file mode 100644 index 0000000000..530d5e6de9 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/AttributeKind.hpp @@ -0,0 +1,58 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_ATTRIBUTEKIND_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_ATTRIBUTEKIND_HPP + +#include +#include + +namespace mrdocs { + +/** The kind of a C++ attribute. + + This identifies the standard C++ attributes mrdocs treats + specially, regardless of how they were spelled in the source. + For example, `[[deprecated]]`, `[[gnu::deprecated]]`, and + `__declspec(deprecated)` all share the deprecated kind. + + Attributes mrdocs does not recognize use the `Other` kind. + + @note Like @ref TypeKind, this enum is intentionally NOT registered + with `MRDOCS_DESCRIBE_ENUM`: the reflection-driven XML writer would + otherwise emit a redundant `` child into every attribute + element. Code that needs a string form calls `toString` below. +*/ +enum class AttributeKind { +#define INFO(PascalName) PascalName, +#include +}; + +/** Convert an AttributeKind to its string representation. +*/ +MRDOCS_DECL +dom::String +toString(AttributeKind kind) noexcept; + +/** Map an AttributeKind into a DOM value. +*/ +inline +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + AttributeKind kind) +{ + v = toString(kind); +} + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_ATTRIBUTEKIND_HPP diff --git a/include/mrdocs/Metadata/Attribute/AttributeNodes.inc b/include/mrdocs/Metadata/Attribute/AttributeNodes.inc new file mode 100644 index 0000000000..017e200146 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/AttributeNodes.inc @@ -0,0 +1,40 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef INFO +#define INFO(PascalName) +#endif + +/// An attribute mrdocs does not treat specially. +INFO(Other) +/// `[[noreturn]]` (C++11) +INFO(Noreturn) +/// `[[carries_dependency]]` (C++11) +INFO(CarriesDependency) +/// `[[deprecated]]` / `[[deprecated("reason")]]` (C++14) +INFO(Deprecated) +/// `[[fallthrough]]` (C++17) +INFO(Fallthrough) +/// `[[maybe_unused]]` (C++17) +INFO(MaybeUnused) +/// `[[nodiscard]]` / `[[nodiscard("reason")]]` (C++17) +INFO(Nodiscard) +/// `[[likely]]` (C++20) +INFO(Likely) +/// `[[unlikely]]` (C++20) +INFO(Unlikely) +/// `[[no_unique_address]]` (C++20) +INFO(NoUniqueAddress) +/// `[[assume(expression)]]` (C++23) +INFO(Assume) +/// `[[indeterminate]]` (C++26) +INFO(Indeterminate) + +#undef INFO diff --git a/include/mrdocs/Metadata/Attribute/CarriesDependencyAttribute.hpp b/include/mrdocs/Metadata/Attribute/CarriesDependencyAttribute.hpp new file mode 100644 index 0000000000..f1a9f8a7a3 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/CarriesDependencyAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_CARRIESDEPENDENCYATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_CARRIESDEPENDENCYATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[carries_dependency]]` attribute (C++11): release-consume dependency propagation. +*/ +struct CarriesDependencyAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + CarriesDependencyAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_CARRIESDEPENDENCYATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/DeprecatedAttribute.hpp b/include/mrdocs/Metadata/Attribute/DeprecatedAttribute.hpp new file mode 100644 index 0000000000..6f0866aaf8 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/DeprecatedAttribute.hpp @@ -0,0 +1,45 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_DEPRECATEDATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_DEPRECATEDATTRIBUTE_HPP + +#include +#include +#include +#include + +namespace mrdocs { + +/** The `[[deprecated]]` attribute (C++14). + + Indicates that the use of the entity is allowed but discouraged. +*/ +struct DeprecatedAttribute final + : AttributeCommonBase +{ + /** The deprecation message, if any. + + This is the evaluated string argument, without quotes, e.g. + `use bar instead` for `[[deprecated("use bar instead")]]`. + Empty when no message was given. + */ + std::string Message; +}; + +MRDOCS_DESCRIBE_STRUCT( + DeprecatedAttribute, + (Attribute), + (Message) +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_DEPRECATEDATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/FallthroughAttribute.hpp b/include/mrdocs/Metadata/Attribute/FallthroughAttribute.hpp new file mode 100644 index 0000000000..adc7ebb62f --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/FallthroughAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_FALLTHROUGHATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_FALLTHROUGHATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[fallthrough]]` attribute (C++17): an intentional switch fall-through. +*/ +struct FallthroughAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + FallthroughAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_FALLTHROUGHATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/IndeterminateAttribute.hpp b/include/mrdocs/Metadata/Attribute/IndeterminateAttribute.hpp new file mode 100644 index 0000000000..4a45f7bd00 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/IndeterminateAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_INDETERMINATEATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_INDETERMINATEATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[indeterminate]]` attribute (C++26): the object has an indeterminate value if uninitialized. +*/ +struct IndeterminateAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + IndeterminateAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_INDETERMINATEATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/LikelyAttribute.hpp b/include/mrdocs/Metadata/Attribute/LikelyAttribute.hpp new file mode 100644 index 0000000000..5f0fff7bb5 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/LikelyAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_LIKELYATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_LIKELYATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[likely]]` attribute (C++20): this path is more likely. +*/ +struct LikelyAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + LikelyAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_LIKELYATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/MaybeUnusedAttribute.hpp b/include/mrdocs/Metadata/Attribute/MaybeUnusedAttribute.hpp new file mode 100644 index 0000000000..039ce4ea12 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/MaybeUnusedAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_MAYBEUNUSEDATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_MAYBEUNUSEDATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[maybe_unused]]` attribute (C++17): suppresses unused-entity warnings. +*/ +struct MaybeUnusedAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + MaybeUnusedAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_MAYBEUNUSEDATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/NoUniqueAddressAttribute.hpp b/include/mrdocs/Metadata/Attribute/NoUniqueAddressAttribute.hpp new file mode 100644 index 0000000000..46922f3615 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/NoUniqueAddressAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_NOUNIQUEADDRESSATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_NOUNIQUEADDRESSATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[no_unique_address]]` attribute (C++20): the member need not have a unique address. +*/ +struct NoUniqueAddressAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + NoUniqueAddressAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_NOUNIQUEADDRESSATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/NodiscardAttribute.hpp b/include/mrdocs/Metadata/Attribute/NodiscardAttribute.hpp new file mode 100644 index 0000000000..dec4e1f4d7 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/NodiscardAttribute.hpp @@ -0,0 +1,44 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_NODISCARDATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_NODISCARDATTRIBUTE_HPP + +#include +#include +#include +#include + +namespace mrdocs { + +/** The `[[nodiscard]]` attribute (C++17, reason added in C++20). + + Encourages the compiler to warn if the return value is discarded. +*/ +struct NodiscardAttribute final + : AttributeCommonBase +{ + /** The reason, if any. + + This is the evaluated string argument, without quotes, given + by the C++20 form `[[nodiscard("reason")]]`. Empty otherwise. + */ + std::string Reason; +}; + +MRDOCS_DESCRIBE_STRUCT( + NodiscardAttribute, + (Attribute), + (Reason) +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_NODISCARDATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/NoreturnAttribute.hpp b/include/mrdocs/Metadata/Attribute/NoreturnAttribute.hpp new file mode 100644 index 0000000000..6428671602 --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/NoreturnAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_NORETURNATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_NORETURNATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[noreturn]]` attribute (C++11): the function does not return. +*/ +struct NoreturnAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + NoreturnAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_NORETURNATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/OtherAttribute.hpp b/include/mrdocs/Metadata/Attribute/OtherAttribute.hpp new file mode 100644 index 0000000000..6be7bfa0ce --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/OtherAttribute.hpp @@ -0,0 +1,38 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_OTHERATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_OTHERATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** An attribute mrdocs does not treat specially. + + The spelling is preserved in @ref Attribute::Name and the + arguments in @ref Attribute::balancedTokens. +*/ +struct OtherAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + OtherAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_OTHERATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attribute/UnlikelyAttribute.hpp b/include/mrdocs/Metadata/Attribute/UnlikelyAttribute.hpp new file mode 100644 index 0000000000..5fb5f2b59e --- /dev/null +++ b/include/mrdocs/Metadata/Attribute/UnlikelyAttribute.hpp @@ -0,0 +1,35 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTE_UNLIKELYATTRIBUTE_HPP +#define MRDOCS_API_METADATA_ATTRIBUTE_UNLIKELYATTRIBUTE_HPP + +#include +#include +#include + +namespace mrdocs { + +/** The `[[unlikely]]` attribute (C++20): this path is less likely. +*/ +struct UnlikelyAttribute final + : AttributeCommonBase +{ +}; + +MRDOCS_DESCRIBE_STRUCT( + UnlikelyAttribute, + (Attribute), + () +) + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTE_UNLIKELYATTRIBUTE_HPP diff --git a/include/mrdocs/Metadata/Attributes.hpp b/include/mrdocs/Metadata/Attributes.hpp new file mode 100644 index 0000000000..0aab208404 --- /dev/null +++ b/include/mrdocs/Metadata/Attributes.hpp @@ -0,0 +1,80 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ATTRIBUTES_HPP +#define MRDOCS_API_METADATA_ATTRIBUTES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mrdocs { + +/** Visit an @ref Attribute with the provided callable. + + @param info The attribute instance to visit. + @param fn The callable to dispatch to the concrete attribute. + @param args Additional arguments forwarded to the callable. + @return Whatever the callable returns. +*/ +template< + std::derived_from AttributeTy, + class F, + class... Args> +decltype(auto) +visit( + AttributeTy& info, + F&& fn, + Args&&... args) +{ + auto visitor = makeVisitor( + info, std::forward(fn), + std::forward(args)...); + switch(info.Kind) + { + #define INFO(PascalName) case AttributeKind::PascalName: \ + return visitor.template visit(); +#include + default: + MRDOCS_UNREACHABLE(); + } +} + +/** Serialize a polymorphic attribute into a DOM value. +*/ +inline +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + Polymorphic const& I, + DomCorpus const* domCorpus) +{ + MRDOCS_ASSERT(!I.valueless_after_move()); + tag_invoke(dom::ValueFromTag{}, v, *I, domCorpus); +} + +} // mrdocs + +#endif // MRDOCS_API_METADATA_ATTRIBUTES_HPP diff --git a/include/mrdocs/Metadata/Symbol/Function.hpp b/include/mrdocs/Metadata/Symbol/Function.hpp index 1a2adbab11..fc31fd8c5d 100644 --- a/include/mrdocs/Metadata/Symbol/Function.hpp +++ b/include/mrdocs/Metadata/Symbol/Function.hpp @@ -73,18 +73,12 @@ struct FunctionSymbol final /** True when deleted as written (vs deduced). */ bool IsDeletedAsWritten = false; - /** True when marked [[noreturn]] or equivalent. - */ - bool IsNoReturn = false; /** True when annotated with override. */ bool HasOverrideAttr = false; /** True when using a trailing return type. */ bool HasTrailingReturn = false; - /** True when declared [[nodiscard]]. - */ - bool IsNodiscard = false; /** True when explicit object parameter syntax is used. */ bool IsExplicitObjectMemberFunction = false; @@ -97,9 +91,6 @@ struct FunctionSymbol final /** Storage class specifier. */ StorageClassKind StorageClass = StorageClassKind::None; - /** Collected attributes attached to the declaration. - */ - std::vector Attributes; // CXXMethodDecl /** True when this is a non-static member function. @@ -188,11 +179,11 @@ MRDOCS_DESCRIBE_STRUCT( (SymbolCommonBase), (ReturnType, Params, Template, FuncClass, Noexcept, Requires, IsVariadic, IsDefaulted, IsExplicitlyDefaulted, IsDeleted, - IsDeletedAsWritten, IsNoReturn, HasOverrideAttr, HasTrailingReturn, - IsNodiscard, IsExplicitObjectMemberFunction, Constexpr, + IsDeletedAsWritten, HasOverrideAttr, HasTrailingReturn, + IsExplicitObjectMemberFunction, Constexpr, OverloadedOperator, StorageClass, IsRecordMethod, IsVirtual, IsVirtualAsWritten, IsPure, IsConst, IsVolatile, IsFinal, - RefQualifier, Explicit, Attributes, FunctionObjectImpl, + RefQualifier, Explicit, FunctionObjectImpl, IsListedOnPrimary, Specializations) ) diff --git a/include/mrdocs/Metadata/Symbol/SymbolBase.hpp b/include/mrdocs/Metadata/Symbol/SymbolBase.hpp index b0131abbc4..a9482a904b 100644 --- a/include/mrdocs/Metadata/Symbol/SymbolBase.hpp +++ b/include/mrdocs/Metadata/Symbol/SymbolBase.hpp @@ -13,6 +13,8 @@ #define MRDOCS_API_METADATA_SYMBOL_SYMBOLBASE_HPP #include +#include +#include #include #include #include @@ -90,6 +92,15 @@ struct MRDOCS_VISIBLE Symbol { */ Optional doc; + /** The C++ attributes attached to this declaration. + + These are the attributes as written in the source, + e.g. `[[deprecated]]` or `[[nodiscard]]`, captured for + every symbol kind. See @ref Attribute for the per-attribute + name and arguments. + */ + std::vector> Attributes; + //-------------------------------------------- /** Polymorphic base needs a virtual destructor. @@ -177,7 +188,7 @@ MRDOCS_DESCRIBE_STRUCT( Symbol, (), (Name, Loc, Kind, id, Access, - Extraction, IsCopyFromInherited, Parent, doc) + Extraction, IsCopyFromInherited, Parent, doc, Attributes) ) /** Map a Symbol to a dom::Object with computed extraction properties. diff --git a/include/mrdocs/Metadata/Symbol/Variable.hpp b/include/mrdocs/Metadata/Symbol/Variable.hpp index 6e0799f773..69dc839931 100644 --- a/include/mrdocs/Metadata/Symbol/Variable.hpp +++ b/include/mrdocs/Metadata/Symbol/Variable.hpp @@ -64,22 +64,6 @@ struct VariableSymbol final */ bool IsThreadLocal = false; - /** Raw attribute spellings attached to the variable. - */ - std::vector Attributes; - - /** Whether the variable carries `[[maybe_unused]]`. - */ - bool IsMaybeUnused = false; - - /** Whether the variable is marked deprecated. - */ - bool IsDeprecated = false; - - /** Whether the variable uses [[no_unique_address]]. - */ - bool HasNoUniqueAddress = false; - //-------------------------------------------- // Record fields /** True if this variable is a data member of a record. @@ -121,9 +105,8 @@ MRDOCS_DESCRIBE_STRUCT( VariableSymbol, (SymbolCommonBase), (Type, Template, Initializer, StorageClass, IsInline, - IsConstexpr, IsConstinit, IsThreadLocal, Attributes, IsMaybeUnused, - IsDeprecated, HasNoUniqueAddress, IsRecordField, IsMutable, IsVariant, - IsBitfield, BitfieldWidth) + IsConstexpr, IsConstinit, IsThreadLocal, IsRecordField, IsMutable, + IsVariant, IsBitfield, BitfieldWidth) ) } // mrdocs diff --git a/mrdocs.rnc b/mrdocs.rnc index cd1f9e08c3..9f87ea440e 100644 --- a/mrdocs.rnc +++ b/mrdocs.rnc @@ -142,9 +142,57 @@ grammar element extraction { ExtractionMode }?, element is-copy-from-inherited { Bool }?, element parent { SymbolID }?, - DocComment? + DocComment?, + AnyAttribute* ) + #--------------------------------------------- + # Attributes (polymorphic) + #--------------------------------------------- + + AttributeBase = + ( + element name { text }?, + element balanced-tokens { text }* + ) + + AnyAttribute = + OtherAttribute | NoreturnAttribute | CarriesDependencyAttribute | + DeprecatedAttribute | FallthroughAttribute | MaybeUnusedAttribute | + NodiscardAttribute | LikelyAttribute | UnlikelyAttribute | + NoUniqueAddressAttribute | AssumeAttribute | IndeterminateAttribute + + OtherAttribute = element other-attribute { AttributeBase } + NoreturnAttribute = element noreturn-attribute { AttributeBase } + CarriesDependencyAttribute = element carries-dependency-attribute { AttributeBase } + FallthroughAttribute = element fallthrough-attribute { AttributeBase } + MaybeUnusedAttribute = element maybe-unused-attribute { AttributeBase } + LikelyAttribute = element likely-attribute { AttributeBase } + UnlikelyAttribute = element unlikely-attribute { AttributeBase } + NoUniqueAddressAttribute = element no-unique-address-attribute { AttributeBase } + IndeterminateAttribute = element indeterminate-attribute { AttributeBase } + + DeprecatedAttribute = + element deprecated-attribute + { + AttributeBase, + element message { text }? + } + + NodiscardAttribute = + element nodiscard-attribute + { + AttributeBase, + element reason { text }? + } + + AssumeAttribute = + element assume-attribute + { + AttributeBase, + element expression { text }? + } + #--------------------------------------------- # Types (polymorphic) #--------------------------------------------- @@ -430,10 +478,8 @@ grammar element is-explicitly-defaulted { Bool }?, element is-deleted { Bool }?, element is-deleted-as-written { Bool }?, - element is-no-return { Bool }?, element has-override-attr { Bool }?, element has-trailing-return { Bool }?, - element is-nodiscard { Bool }?, element is-explicit-object-member-function { Bool }?, element constexpr { text }?, element overloaded-operator { text }?, @@ -447,7 +493,6 @@ grammar element is-final { Bool }?, element ref-qualifier { text }?, element explicit { text }?, - element attributes { text }*, element function-object-impl { SymbolID }?, element is-listed-on-primary { Bool }?, element specializations { SymbolID }* @@ -508,10 +553,6 @@ grammar element is-constexpr { Bool }?, element is-constinit { Bool }?, element is-thread-local { Bool }?, - element attributes { text }*, - element is-maybe-unused { Bool }?, - element is-deprecated { Bool }?, - element has-no-unique-address { Bool }?, element is-record-field { Bool }?, element is-mutable { Bool }?, element is-variant { Bool }?, diff --git a/share/mrdocs/addons/generator/adoc/partials/markup/a.adoc.hbs b/share/mrdocs/addons/generator/adoc/partials/markup/a.adoc.hbs index 429b416be4..9a97bbfcf1 100644 --- a/share/mrdocs/addons/generator/adoc/partials/markup/a.adoc.hbs +++ b/share/mrdocs/addons/generator/adoc/partials/markup/a.adoc.hbs @@ -12,5 +12,5 @@ {{~else if (starts_with href ".")~}} xref:{{{href}}}[{{> @partial-block }}] {{~else~}} - {{{href}}}[{{> @partial-block }}] + {{{href}}}[{{> @partial-block }}{{#if blank}}^{{/if}}] {{~/if~}} \ No newline at end of file diff --git a/share/mrdocs/addons/generator/common/partials/symbol.hbs b/share/mrdocs/addons/generator/common/partials/symbol.hbs index e42b42806f..5e0031d93b 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol.hbs @@ -15,6 +15,7 @@ {{#> markup/section name="symbol"}} {{> symbol/section/header}} {{> symbol/section/synopsis}} +{{> symbol/section/attribute-admonitions ~}} {{> symbol/section/function-object-admonition}} {{> symbol/section/description}} {{> symbol/section/base-classes}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/section/attribute-admonitions.hbs b/share/mrdocs/addons/generator/common/partials/symbol/section/attribute-admonitions.hbs new file mode 100644 index 0000000000..1dd1579cf2 --- /dev/null +++ b/share/mrdocs/addons/generator/common/partials/symbol/section/attribute-admonitions.hbs @@ -0,0 +1,22 @@ +{{! An admonition for each recognized standard attribute the symbol carries, linking to cppreference in passing. }} +{{~#each symbol.attributes~}} +{{~#if (eq kind "deprecated")~}} +{{#> markup/admonition kind="warning"}}{{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/deprecated" blank=true}}Deprecated{{/markup/a}}{{#if message}}: {{message}}{{/if}}. Use of this entity is allowed but discouraged.{{/markup/admonition}} +{{~else if (eq kind "maybe-unused")~}} +{{#> markup/admonition kind="note"}}This entity {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/maybe_unused" blank=true}}may be unused{{/markup/a}}, and the compiler will not warn about it.{{/markup/admonition}} +{{~else if (eq kind "no-unique-address")~}} +{{#> markup/admonition kind="note"}}This member {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/no_unique_address" blank=true}}need not have an address distinct from all other non-static data members{{/markup/a}} of its class.{{/markup/admonition}} +{{~else if (eq kind "carries-dependency")~}} +{{#> markup/admonition kind="note"}}This {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/carries_dependency" blank=true}}carries a dependency{{/markup/a}} for release-consume ordering.{{/markup/admonition}} +{{~else if (eq kind "fallthrough")~}} +{{#> markup/admonition kind="note"}}The {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/fallthrough" blank=true}}fall-through{{/markup/a}} from the previous case label is intentional.{{/markup/admonition}} +{{~else if (eq kind "likely")~}} +{{#> markup/admonition kind="note"}}This path is {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/likely" blank=true}}more likely{{/markup/a}} to execute than the alternatives.{{/markup/admonition}} +{{~else if (eq kind "unlikely")~}} +{{#> markup/admonition kind="note"}}This path is {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/likely" blank=true}}less likely{{/markup/a}} to execute than the alternatives.{{/markup/admonition}} +{{~else if (eq kind "assume")~}} +{{#> markup/admonition kind="note"}}The expression{{#if expression}} `{{expression}}`{{/if}} is {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/assume" blank=true}}assumed{{/markup/a}} to always hold at this point.{{/markup/admonition}} +{{~else if (eq kind "indeterminate")~}} +{{#> markup/admonition kind="note"}}If it is not initialized, this object has an {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/indeterminate" blank=true}}indeterminate value{{/markup/a}}.{{/markup/admonition}} +{{~/if~}} +{{~/each~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/section/attribute-return-admonitions.hbs b/share/mrdocs/addons/generator/common/partials/symbol/section/attribute-return-admonitions.hbs new file mode 100644 index 0000000000..321b40da6e --- /dev/null +++ b/share/mrdocs/addons/generator/common/partials/symbol/section/attribute-return-admonitions.hbs @@ -0,0 +1,8 @@ +{{! Admonitions for attributes that describe a function's return behavior, rendered in the Return Value section. }} +{{~#each symbol.attributes~}} +{{~#if (eq kind "nodiscard")~}} +{{#> markup/admonition kind="note"}}The return value {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/nodiscard" blank=true}}should not be discarded{{/markup/a}}{{#if reason}}: {{reason}}{{/if}}.{{/markup/admonition}} +{{~else if (eq kind "noreturn")~}} +{{#> markup/admonition kind="note"}}This function {{#> markup/a href="https://en.cppreference.com/cpp/language/attributes/noreturn" blank=true}}does not return{{/markup/a}}.{{/markup/admonition}} +{{~/if~}} +{{~/each~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/section/return-value.hbs b/share/mrdocs/addons/generator/common/partials/symbol/section/return-value.hbs index 9a9fafc4af..d6bd984984 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/section/return-value.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/section/return-value.hbs @@ -1,7 +1,8 @@ -{{! Return value(s) (@returns). Single returns render inline; multiples render as a list. }} -{{#if symbol.doc.returns}} +{{! Return value(s) (@returns) plus return-related attribute admonitions (nodiscard, noreturn). Single returns render inline; multiples render as a list. }} +{{#if (or (size symbol.doc.returns) (contains_any (pluck symbol.attributes "kind") (arr "nodiscard" "noreturn")))}} {{#> markup/section name="return-value"}} {{#> markup/dynamic-level-h }}Return Value{{/markup/dynamic-level-h~}} +{{#if symbol.doc.returns}} {{#if (eq (size symbol.doc.returns) 1)}} {{#> markup/p}}{{> doc/block/returns symbol.doc.returns.[0]}}{{/markup/p}} {{else}} @@ -11,5 +12,7 @@ {{/each}} {{/markup/ul}} {{/if}} +{{/if}} +{{> symbol/section/attribute-return-admonitions ~}} {{/markup/section}} {{/if}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/attributes.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/attributes.hbs new file mode 100644 index 0000000000..3ba24a8d1c --- /dev/null +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/attributes.hbs @@ -0,0 +1 @@ +{{!-- Renders the symbol's C++ attributes as a `[[...]]` clause. Expects the symbol context (uses `attributes`). --}}{{~ str "[[" ~}}{{~#each attributes~}}{{~#unless @first}}, {{/unless~}}{{~ name ~}}{{~#if balancedTokens}}({{join ", " balancedTokens}}){{/if~}}{{~/each~}}{{~ str "]]" ~}} \ No newline at end of file diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/enum-constant.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/enum-constant.hbs index ed01c62ec9..a964cf24e4 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/enum-constant.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/enum-constant.hbs @@ -1 +1 @@ -{{ name }}{{#if initializer}} = {{initializer}}{{~/if}} \ No newline at end of file +{{ name }}{{#if attributes}} {{>symbol/signature/attributes}}{{/if}}{{#if initializer}} = {{initializer}}{{~/if}} \ No newline at end of file diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/enum.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/enum.hbs index 15240c9e16..9c40d76deb 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/enum.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/enum.hbs @@ -1,2 +1,2 @@ -enum {{#if scoped}}class {{/if}}{{>symbol/name-text .~}} +enum {{#if scoped}}class {{/if}}{{#if attributes}}{{>symbol/signature/attributes}} {{/if}}{{>symbol/name-text .~}} {{#if underlyingType}} : {{>type/declarator underlyingType}}{{/if}}; \ No newline at end of file diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs index 4ffab163fa..3b95a39675 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs @@ -2,7 +2,7 @@ {{/if~}} {{#if isFriend}}friend {{/if~}} -{{#if attributes}}{{#unless isFriend}}{{ str "[[" }}{{join ", " attributes}}{{ str "]]" }} +{{#if attributes}}{{#unless isFriend}}{{>symbol/signature/attributes}} {{/unless}}{{/if~}} {{#if constexpr}}{{constexpr}} {{/if~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/record.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/record.hbs index b21aebd02a..987fa43c65 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/record.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/record.hbs @@ -1,7 +1,7 @@ {{#if template}}{{>template/head template}} {{/if~}} {{#if isFriend}}friend {{/if~}} -{{~keyKind}} {{#if (contains (arr "explicit" "partial") template.kind)~}} +{{~keyKind}} {{#if attributes}}{{>symbol/signature/attributes}} {{/if}}{{#if (contains (arr "explicit" "partial") template.kind)~}} {{!~ If the last part is a template specialization, we include links to primary template and the arguments. ~}} {{!~ If the primary template wasn't correctly extracted for some reason, we just print the name as usual. ~}} {{#if template.primary }}{{~>symbol/name template.primary ~}}{{else}}{{ name }}{{/if}}{{>template/args args=template.args ~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/typedef.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/typedef.hbs index 1469df45ed..3d84df7c99 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/typedef.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/typedef.hbs @@ -1,7 +1,7 @@ {{#if isUsing~}} {{#if template}}{{>template/head template}} {{/if~}} - using {{name}} = {{>type/declarator type}} + using {{name}} {{#if attributes}}{{>symbol/signature/attributes}} {{/if}}= {{>type/declarator type}} {{~else~}} typedef {{>type/declarator type decl-name=name}} {{~/if}}; \ No newline at end of file diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/variable.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/variable.hbs index 06b2837a2e..bf5ab697e4 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/variable.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/variable.hbs @@ -1,4 +1,4 @@ -{{#if attributes}}{{ str "[[" }}{{join ", " attributes}}{{ str "]]" }} +{{#if attributes}}{{>symbol/signature/attributes}} {{/if}} {{#if template}}{{>template/head template}} {{/if~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs b/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs index 1abc410714..0bf2dcad4b 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs @@ -30,4 +30,12 @@ {{~#if isVariant~}} {{#>markup/span class="small"}}[variant member]{{/markup/span}} {{~/if~}} -{{~/if}} \ No newline at end of file +{{~/if~}} +{{!-- Terse attribute tags. These apply to every symbol kind that carries the attribute. --}} +{{~#each attributes~}} +{{~#if (eq kind "deprecated")~}} + {{str ' '}}{{#>markup/span class="small"}}[deprecated]{{/markup/span}} +{{~else if (eq kind "noreturn")~}} + {{str ' '}}{{#>markup/span class="small"}}[noreturn]{{/markup/span}} +{{~/if~}} +{{~/each~}} \ No newline at end of file diff --git a/share/mrdocs/addons/generator/html/partials/markup/a.html.hbs b/share/mrdocs/addons/generator/html/partials/markup/a.html.hbs index fcfdd3283d..53f6547467 100644 --- a/share/mrdocs/addons/generator/html/partials/markup/a.html.hbs +++ b/share/mrdocs/addons/generator/html/partials/markup/a.html.hbs @@ -1,5 +1,5 @@ {{#if (eq href @root.symbol.url)~}} {{{> @partial-block }}} {{~else~}} - {{> @partial-block }} + {{> @partial-block }} {{~/if~}} \ No newline at end of file diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 926e63f591..89390556bc 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -552,6 +552,11 @@ populate(Symbol& I, bool const isNew, DeclTy const* D) populate(I.doc, D); populate(I.Loc, D); + // Attributes are extracted for every symbol kind and may be spread + // across redeclarations, so collect them even when the symbol is + // not new (the helper deduplicates). + populateAttributes(I, D); + // All other information is redundant if the symbol is not new MRDOCS_CHECK_OR(isNew); @@ -893,7 +898,6 @@ populate( I.IsExplicitlyDefaulted |= D->isExplicitlyDefaulted(); I.IsDeleted |= D->isDeleted(); I.IsDeletedAsWritten |= D->isDeletedAsWritten(); - I.IsNoReturn |= D->isNoReturn(); I.HasOverrideAttr |= D->hasAttr(); if (clang::ConstexprSpecKind const CSK = D->getConstexprKind(); @@ -907,7 +911,6 @@ populate( I.StorageClass = toStorageClassKind(SC); } - I.IsNodiscard |= D->hasAttr(); I.IsExplicitObjectMemberFunction |= D->hasCXXExplicitFunctionObjectParameter(); llvm::ArrayRef const params = D->parameters(); @@ -996,8 +999,6 @@ populate( } } } - - populateAttributes(I, D); } void @@ -1171,7 +1172,6 @@ populate( QT.removeLocalConst(); } I.Type = toType(QT); - populateAttributes(I, D); } void @@ -1216,10 +1216,6 @@ populate( I.IsBitfield = true; populate(I.BitfieldWidth, D->getBitWidth()); } - I.HasNoUniqueAddress = D->hasAttr(); - I.IsDeprecated = D->hasAttr(); - I.IsMaybeUnused = D->hasAttr(); - populateAttributes(I, D); } void @@ -1738,26 +1734,280 @@ populate( })); } -template InfoTy> +namespace { +// Split the text inside an attribute's parentheses into its individual +// arguments, breaking on top-level commas while respecting nested +// brackets and string/character literals. +std::vector +splitAttributeArgs(std::string_view s) +{ + std::vector args; + std::string cur; + int depth = 0; + bool inString = false; + bool inChar = false; + for (std::size_t i = 0; i < s.size(); ++i) + { + char const c = s[i]; + if (inString || inChar) + { + cur += c; + if (c == '\\' && i + 1 < s.size()) + { + cur += s[++i]; + } + else if (inString && c == '"') + { + inString = false; + } + else if (inChar && c == '\'') + { + inChar = false; + } + continue; + } + switch (c) + { + case '"': inString = true; break; + case '\'': inChar = true; break; + case '(': case '[': case '{': ++depth; break; + case ')': case ']': case '}': --depth; break; + default: break; + } + if (c == ',' && depth == 0) + { + args.emplace_back(trim(cur)); + cur.clear(); + continue; + } + cur += c; + } + if (std::string_view const last = trim(cur); !last.empty()) + { + args.emplace_back(last); + } + return args; +} + +// Extract the argument tokens from an attribute's pretty-printed form. +// Anchored on the attribute name, so the surrounding `[[ ]]` or +// `__attribute__(( ))` wrapper does not matter. +std::vector +attributeArgs(std::string_view pretty, std::string_view name) +{ + std::size_t const namePos = pretty.find(name); + if (namePos == std::string_view::npos) + { + return {}; + } + std::size_t const open = pretty.find('(', namePos + name.size()); + if (open == std::string_view::npos) + { + return {}; + } + int depth = 0; + bool inString = false; + bool inChar = false; + std::size_t i = open; + for (; i < pretty.size(); ++i) + { + char const c = pretty[i]; + if (inString || inChar) + { + if (c == '\\') { ++i; continue; } + if (inString && c == '"') { inString = false; } + else if (inChar && c == '\'') { inChar = false; } + continue; + } + if (c == '"') { inString = true; } + else if (c == '\'') { inChar = true; } + else if (c == '(') { ++depth; } + else if (c == ')') { if (--depth == 0) { break; } } + } + if (i >= pretty.size()) + { + return {}; + } + return splitAttributeArgs(pretty.substr(open + 1, i - open - 1)); +} + +// Map a Clang attribute kind to the mrdocs attribute kind for the +// standard C++ attributes, identifying by kind rather than spelling. +AttributeKind +toAttributeKind(clang::attr::Kind const kind) +{ + switch (kind) + { + case clang::attr::CXX11NoReturn: + case clang::attr::C11NoReturn: return AttributeKind::Noreturn; + case clang::attr::CarriesDependency: return AttributeKind::CarriesDependency; + case clang::attr::Deprecated: return AttributeKind::Deprecated; + case clang::attr::FallThrough: return AttributeKind::Fallthrough; + case clang::attr::Unused: return AttributeKind::MaybeUnused; + case clang::attr::WarnUnusedResult: return AttributeKind::Nodiscard; + case clang::attr::Likely: return AttributeKind::Likely; + case clang::attr::Unlikely: return AttributeKind::Unlikely; + case clang::attr::NoUniqueAddress: return AttributeKind::NoUniqueAddress; + case clang::attr::CXXAssume: return AttributeKind::Assume; + default: return AttributeKind::Other; + } +} + +// The normalized standard spelling for a recognized attribute kind, +// or empty for AttributeKind::Other. +std::string_view +standardAttributeName(AttributeKind const kind) +{ + switch (kind) + { + case AttributeKind::Noreturn: return "noreturn"; + case AttributeKind::CarriesDependency: return "carries_dependency"; + case AttributeKind::Deprecated: return "deprecated"; + case AttributeKind::Fallthrough: return "fallthrough"; + case AttributeKind::MaybeUnused: return "maybe_unused"; + case AttributeKind::Nodiscard: return "nodiscard"; + case AttributeKind::Likely: return "likely"; + case AttributeKind::Unlikely: return "unlikely"; + case AttributeKind::NoUniqueAddress: return "no_unique_address"; + case AttributeKind::Assume: return "assume"; + case AttributeKind::Indeterminate: return "indeterminate"; + default: return {}; + } +} + +// Construct the concrete attribute object for a kind. +Polymorphic +makeAttribute(AttributeKind const kind) +{ + switch (kind) + { +#define INFO(PascalName) case AttributeKind::PascalName: \ + return Polymorphic(PascalName##Attribute{}); +#include + default: + MRDOCS_UNREACHABLE(); + } +} +} // (anon) + void ASTVisitor:: -populateAttributes(InfoTy& I, clang::Decl const* D) +populateAttributes(Symbol& I, clang::Decl const* D) { - if constexpr (requires { I.Attributes; }) + auto collect = [&](clang::Decl const* Decl) { - MRDOCS_CHECK_OR(D->hasAttrs()); - for (clang::Attr const* attr: D->getAttrs()) + if (!Decl || !Decl->hasAttrs()) + { + return; + } + for (clang::Attr const* attr: Decl->getAttrs()) { - clang::IdentifierInfo const* II = attr->getAttrName(); - if (!II) + // Skip attributes the compiler injected rather than the user wrote. + if (attr->isImplicit()) { continue; } - if (!contains(I.Attributes, II->getName())) + + // Only surface attributes written with a real attribute syntax. + // This excludes context-sensitive keywords such as `override` + // and `final`, which Clang models as attributes but which are + // documented through their own dedicated fields. + if (!attr->isStandardAttributeSyntax() && + !attr->isGNUAttribute() && + !attr->isDeclspecAttribute()) + { + continue; + } + + AttributeKind const kind = toAttributeKind(attr->getKind()); + Polymorphic attribute = makeAttribute(kind); + + // The written name, with scope (e.g. `gnu::custom`). Recognized + // attributes are normalized to their standard spelling; others + // keep the written spelling. + std::string written; + if (clang::IdentifierInfo const* scope = attr->getScopeName()) { - I.Attributes.emplace_back(II->getName()); + written = scope->getName().str(); + written += "::"; + } + std::string spelledName; + if (clang::IdentifierInfo const* II = attr->getAttrName()) + { + spelledName = II->getName().str(); + } + else + { + spelledName = attr->getSpelling(); + } + written += spelledName; + + if (std::string_view const normalized = standardAttributeName(kind); + !normalized.empty()) + { + attribute->Name = normalized; + } + else + { + attribute->Name = std::move(written); + } + + // Render the attribute canonically and read its argument tokens. + // printPretty avoids the fragility of the source spelling (macros, + // raw strings, comments) and normalizes string literals. + std::string pretty; + { + llvm::raw_string_ostream os(pretty); + attr->printPretty(os, context_.getPrintingPolicy()); + } + attribute->balancedTokens = attributeArgs(pretty, spelledName); + // printPretty renders an argument-less `[[deprecated]]` or + // `[[nodiscard]]` as `name("")`; treat a lone empty string + // literal as no arguments. + if (attribute->balancedTokens.size() == 1 && + attribute->balancedTokens.front() == "\"\"") + { + attribute->balancedTokens.clear(); + } + + // Evaluated, typed arguments for the attributes that carry them. + if (auto const* DA = dyn_cast(attr)) + { + attribute->asDeprecated().Message = DA->getMessage().str(); + } + else if (auto const* NA = dyn_cast(attr)) + { + attribute->asNodiscard().Reason = NA->getMessage().str(); + } + else if (kind == AttributeKind::Assume && + !attribute->balancedTokens.empty()) + { + attribute->asAssume().Expression = attribute->balancedTokens.front(); + } + + // Suppress exact duplicates only (same kind, name, and tokens): + // the same attribute may appear on more than one redeclaration or + // on both a template and its templated declaration. A repeated + // attribute with different arguments is kept. + if (std::ranges::none_of( + I.Attributes, + [&](Polymorphic const& other) + { + return other == attribute; + })) + { + I.Attributes.push_back(std::move(attribute)); } } + }; + + collect(D); + + // Attributes such as [[nodiscard]] or [[deprecated]] on a template + // are attached to the templated declaration, not the template itself. + if (auto const* TD = dyn_cast(D)) + { + collect(TD->getTemplatedDecl()); } } diff --git a/src/lib/AST/ASTVisitor.hpp b/src/lib/AST/ASTVisitor.hpp index 0ad6f49226..65e4348cd3 100644 --- a/src/lib/AST/ASTVisitor.hpp +++ b/src/lib/AST/ASTVisitor.hpp @@ -729,10 +729,8 @@ class ASTVisitor std::vector>& result, clang::ASTTemplateArgumentListInfo const* args); - template InfoTy> - static void - populateAttributes(InfoTy& I, clang::Decl const* D); + populateAttributes(Symbol& I, clang::Decl const* D); // ================================================= // Populate function helpers diff --git a/src/lib/Gen/xml/XMLWriter.cpp b/src/lib/Gen/xml/XMLWriter.cpp index de1e2c7e4a..30c382856f 100644 --- a/src/lib/Gen/xml/XMLWriter.cpp +++ b/src/lib/Gen/xml/XMLWriter.cpp @@ -13,10 +13,11 @@ // #include "XMLWriter.hpp" +#include +#include #include -#include #include -#include +#include #include #include #include @@ -270,7 +271,20 @@ XMLWriter::writePolymorphic(T const& value) writeMembers(static_cast(value)); \ tags_.close(toKebabCase(#Name)); \ break; - #include +#include + default: MRDOCS_UNREACHABLE(); + } + } + else if constexpr (std::is_base_of_v<::mrdocs::Attribute, T>) + { + switch (value.Kind) + { + #define INFO(Name) case ::mrdocs::AttributeKind::Name: \ + tags_.open(toKebabCase(#Name) + "-attribute"); \ + writeMembers(value.as##Name()); \ + tags_.close(toKebabCase(#Name) + "-attribute"); \ + break; +#include default: MRDOCS_UNREACHABLE(); } } @@ -283,7 +297,7 @@ XMLWriter::writePolymorphic(T const& value) writeMembers(static_cast(value)); \ tags_.close(toKebabCase(#Name) + "-tparam"); \ break; - #include +#include default: MRDOCS_UNREACHABLE(); } } @@ -296,7 +310,7 @@ XMLWriter::writePolymorphic(T const& value) writeMembers(static_cast(value)); \ tags_.close(toKebabCase(#Name) + "-targ"); \ break; - #include +#include default: MRDOCS_UNREACHABLE(); } } @@ -309,7 +323,7 @@ XMLWriter::writePolymorphic(T const& value) writeMembers(value.as##Name()); \ tags_.close(toKebabCase(#Name)); \ break; - #include +#include default: MRDOCS_UNREACHABLE(); } } @@ -322,7 +336,7 @@ XMLWriter::writePolymorphic(T const& value) writeMembers(value.as##Name()); \ tags_.close(toKebabCase(#Name)); \ break; - #include +#include default: MRDOCS_UNREACHABLE(); } } diff --git a/src/lib/Metadata/Attributes.cpp b/src/lib/Metadata/Attributes.cpp new file mode 100644 index 0000000000..ce6530c238 --- /dev/null +++ b/src/lib/Metadata/Attributes.cpp @@ -0,0 +1,78 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2026 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include +#include +#include +#include + +namespace mrdocs { + +dom::String +toString(AttributeKind kind) noexcept +{ + switch(kind) + { + case AttributeKind::Other: + return "other"; + case AttributeKind::Noreturn: + return "noreturn"; + case AttributeKind::CarriesDependency: + return "carries-dependency"; + case AttributeKind::Deprecated: + return "deprecated"; + case AttributeKind::Fallthrough: + return "fallthrough"; + case AttributeKind::MaybeUnused: + return "maybe-unused"; + case AttributeKind::Nodiscard: + return "nodiscard"; + case AttributeKind::Likely: + return "likely"; + case AttributeKind::Unlikely: + return "unlikely"; + case AttributeKind::NoUniqueAddress: + return "no-unique-address"; + case AttributeKind::Assume: + return "assume"; + case AttributeKind::Indeterminate: + return "indeterminate"; + default: + MRDOCS_UNREACHABLE(); + } +} + +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + Attribute const& I, + DomCorpus const* domCorpus) +{ + visit(I, [&](T const& t) { + v = dom::LazyObject(t, domCorpus); + }); +} + +std::strong_ordering +operator<=>(Polymorphic const& lhs, Polymorphic const& rhs) +{ + MRDOCS_ASSERT(!lhs.valueless_after_move()); + MRDOCS_ASSERT(!rhs.valueless_after_move()); + auto& lhsRef = *lhs; + auto& rhsRef = *rhs; + if (lhsRef.Kind == rhsRef.Kind) + { + return visit(lhsRef, detail::VisitCompareFn(rhsRef)); + } + return lhsRef.Kind <=> rhsRef.Kind; +} + +} // mrdocs diff --git a/src/test/lib/Metadata/Merge.cpp b/src/test/lib/Metadata/Merge.cpp index 0a48bbfbbe..746dc52165 100644 --- a/src/test/lib/Metadata/Merge.cpp +++ b/src/test/lib/Metadata/Merge.cpp @@ -8,13 +8,13 @@ // Official repository: https://github.com/cppalliance/mrdocs // +#include #include #include #include #include #include #include -#include #include #include #include @@ -327,11 +327,19 @@ struct MergeTest void test_func_attributes_dedup() { + auto makeNodiscard = []{ + NodiscardAttribute a; + a.Name = "nodiscard"; + return Polymorphic(a); + }; auto dst = makeFunc(); - dst.Attributes.push_back("nodiscard"); + dst.Attributes.push_back(makeNodiscard()); auto src = makeFunc(); - src.Attributes.push_back("nodiscard"); - src.Attributes.push_back("deprecated"); + src.Attributes.push_back(makeNodiscard()); + DeprecatedAttribute dep; + dep.Name = "deprecated"; + dep.Message = "use bar"; + src.Attributes.push_back(Polymorphic(dep)); merge(dst, std::move(src)); BOOST_TEST(dst.Attributes.size() == 2u); diff --git a/test-files/golden-tests/generator/hbs/attributes/attributes.adoc b/test-files/golden-tests/generator/hbs/attributes/attributes.adoc new file mode 100644 index 0000000000..3c0347da10 --- /dev/null +++ b/test-files/golden-tests/generator/hbs/attributes/attributes.adoc @@ -0,0 +1,357 @@ += Reference +:mrdocs: + +[#index] +== Global namespace + +=== Types + +[cols="1,4"] +|=== +| Name| Description +| link:#Aligned[`Aligned`] +| An over‐aligned type (a single, non‐string attribute argument). +| link:#Gadget[`Gadget`] +| A class whose members carry attributes, to exercise member‐table tags. +| link:#Gnu[`Gnu`] [.small]#[deprecated]# +| A class deprecated via the GNU spelling, normalized to the standard form. +| link:#Widget[`Widget`] [.small]#[deprecated]# +| A deprecated class. +|=== + + +=== Type Aliases + +[cols="1,4"] +|=== +| Name| Description +| link:#extension_type[`extension_type`] [.small]#[deprecated]# +| A deprecated type alias (the motivating case from issue #1233). +|=== + + +=== Enums + +[cols="1,4"] +|=== +| Name| Description +| link:#Color[`Color`] [.small]#[deprecated]# +| A deprecated scoped enum with a deprecated enumerator. +|=== + + +=== Functions + +[cols="1,4"] +|=== +| Name| Description +| link:#annotated[`annotated`] +| A function carrying the same attribute twice with different arguments. +| link:#checked[`checked`] +| A nodiscard function (an attribute with no arguments). +| link:#compute[`compute`] [.small]#[deprecated]# +| A deprecated function with a message. +| link:#log_message[`log_message`] +| A printf‐like function (an attribute with multiple arguments). +|=== + + +=== Variables + +[cols="1,4"] +|=== +| Name| Description +| link:#value[`value`] [.small]#[deprecated]# +| A deprecated variable. +|=== + + +[#extension_type] +== extension_type + +A deprecated type alias (the motivating case from issue #1233). + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +using extension_type [[deprecated("use extent_type")]] = int; +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]: use extent_type. Use of this entity is allowed but discouraged. +==== +[#Aligned] +== Aligned + +An over‐aligned type (a single, non‐string attribute argument). + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +struct [[gnu::aligned(16)]] Aligned; +---- + +[#Gadget] +== Gadget + +A class whose members carry attributes, to exercise member‐table tags. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +struct Gadget; +---- + +=== Member Functions + +[cols="1,4"] +|=== +| Name| Description +| link:#Gadget-fail[`fail`] [.small]#[noreturn]# +| A member function that never returns. +| link:#Gadget-run[`run`] [.small]#[deprecated]# +| A deprecated member function. +|=== + + +=== Data Members + +[cols="1,4"] +|=== +| Name| Description +| link:#Gadget-field[`field`] [.small]#[deprecated]# +| A deprecated data member. +|=== + + +[#Gadget-fail] +== link:#Gadget[Gadget]::fail + +A member function that never returns. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[noreturn]] +void +fail(); +---- + +=== Return Value + +[NOTE] +==== +This function https://en.cppreference.com/cpp/language/attributes/noreturn[does not return^]. +==== +[#Gadget-run] +== link:#Gadget[Gadget]::run + +A deprecated member function. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[deprecated("use run2")]] +void +run(); +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]: use run2. Use of this entity is allowed but discouraged. +==== +[#Gadget-field] +== link:#Gadget[Gadget]::field + +A deprecated data member. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[deprecated]] +int field; +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]. Use of this entity is allowed but discouraged. +==== +[#Gnu] +== Gnu + +A class deprecated via the GNU spelling, normalized to the standard form. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +struct [[deprecated("use Gnu2")]] Gnu; +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]: use Gnu2. Use of this entity is allowed but discouraged. +==== +[#Widget] +== Widget + +A deprecated class. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +struct [[deprecated("use Widget2")]] Widget; +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]: use Widget2. Use of this entity is allowed but discouraged. +==== +[#Color] +== Color + +A deprecated scoped enum with a deprecated enumerator. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +enum class [[deprecated("use Color2")]] Color : int; +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]: use Color2. Use of this entity is allowed but discouraged. +==== +=== Members + +[cols="1"] +|=== +| Name +| `Red` +| `Green` [.small]#[deprecated]# +| `Blue` +|=== + + +[#annotated] +== annotated + +A function carrying the same attribute twice with different arguments. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[clang::annotate("a"), clang::annotate("b")]] +void +annotated(); +---- + +[#checked] +== checked + +A nodiscard function (an attribute with no arguments). + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[nodiscard]] +int +checked(); +---- + +=== Return Value + +[NOTE] +==== +The return value https://en.cppreference.com/cpp/language/attributes/nodiscard[should not be discarded^]. +==== +[#compute] +== compute + +A deprecated function with a message. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[deprecated("use compute2")]] +int +compute(); +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]: use compute2. Use of this entity is allowed but discouraged. +==== +[#log_message] +== log_message + +A printf‐like function (an attribute with multiple arguments). + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[gnu::format(printf, 1, 2)]] +void +log_message(char const* fmt, ...); +---- + +[#value] +== value + +A deprecated variable. + +=== Synopsis + +Declared in `<attributes.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +[[deprecated("use value2")]] +inline int value = 0; +---- + +[WARNING] +==== +https://en.cppreference.com/cpp/language/attributes/deprecated[Deprecated^]: use value2. Use of this entity is allowed but discouraged. +==== + +[.small]#Created with https://www.mrdocs.com[MrDocs]# diff --git a/test-files/golden-tests/generator/hbs/attributes/attributes.cpp b/test-files/golden-tests/generator/hbs/attributes/attributes.cpp new file mode 100644 index 0000000000..deeff9f81a --- /dev/null +++ b/test-files/golden-tests/generator/hbs/attributes/attributes.cpp @@ -0,0 +1,57 @@ +// A generator rendering example: how C++ attributes appear in the +// Handlebars-generated pages (adoc and HTML). +// +// Unlike the XML corpus tests under symbols/, this exercises the +// templates: the `[[...]]` clause in each kind's signature, the +// attribute admonitions, and the `[deprecated]`/`[noreturn]` tags in +// member tables. +// It is deliberately small because the HTML/adoc generators are +// expensive; it just needs to cover the renderable cases once. + +/// A deprecated class. +struct [[deprecated("use Widget2")]] Widget {}; + +/// A class deprecated via the GNU spelling, normalized to the standard form. +struct [[gnu::deprecated("use Gnu2")]] Gnu {}; + +/// An over-aligned type (a single, non-string attribute argument). +struct [[gnu::aligned(16)]] Aligned {}; + +/// A deprecated scoped enum with a deprecated enumerator. +enum class [[deprecated("use Color2")]] Color +{ + Red, + Green [[deprecated("use Blue")]], + Blue +}; + +/// A deprecated type alias (the motivating case from issue #1233). +using extension_type [[deprecated("use extent_type")]] = int; + +/// A nodiscard function (an attribute with no arguments). +[[nodiscard]] int checked(); + +/// A deprecated function with a message. +[[deprecated("use compute2")]] int compute(); + +/// A printf-like function (an attribute with multiple arguments). +[[gnu::format(printf, 1, 2)]] void log_message(char const* fmt, ...); + +/// A function carrying the same attribute twice with different arguments. +[[clang::annotate("a"), clang::annotate("b")]] void annotated(); + +/// A deprecated variable. +[[deprecated("use value2")]] inline int value = 0; + +/// A class whose members carry attributes, to exercise member-table tags. +struct Gadget +{ + /// A deprecated member function. + [[deprecated("use run2")]] void run(); + + /// A member function that never returns. + [[noreturn]] void fail(); + + /// A deprecated data member. + [[deprecated]] int field; +}; diff --git a/test-files/golden-tests/generator/hbs/attributes/attributes.html b/test-files/golden-tests/generator/hbs/attributes/attributes.html new file mode 100644 index 0000000000..4bb99d263c --- /dev/null +++ b/test-files/golden-tests/generator/hbs/attributes/attributes.html @@ -0,0 +1,347 @@ + + +Reference + + + +
+

Reference

+
+
+

Global namespace

+
+

Types

+ + + + + + + + + + +
NameDescription
Aligned An over-aligned type (a single, non-string attribute argument).
Gadget A class whose members carry attributes, to exercise member-table tags.
Gnu [deprecated]A class deprecated via the GNU spelling, normalized to the standard form.
Widget [deprecated]A deprecated class.
+ +

Type Aliases

+ + + + + + + +
NameDescription
extension_type [deprecated]A deprecated type alias (the motivating case from issue #1233).
+ +

Enums

+ + + + + + + +
NameDescription
Color [deprecated]A deprecated scoped enum with a deprecated enumerator.
+ +

Functions

+ + + + + + + + + + +
NameDescription
annotated A function carrying the same attribute twice with different arguments.
checked A nodiscard function (an attribute with no arguments).
compute [deprecated]A deprecated function with a message.
log_message A printf-like function (an attribute with multiple arguments).
+ +

Variables

+ + + + + + + +
NameDescription
value [deprecated]A deprecated variable.
+ +
+
+
+

extension_type

+
+

A deprecated type alias (the motivating case from issue #1233).

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
using extension_type [[deprecated("use extent_type")]] = int;
+
+
+

WARNING

+
+

Deprecated: use extent_type. Use of this entity is allowed but discouraged.

+
+
+
+
+

Aligned

+
+

An over-aligned type (a single, non-string attribute argument).

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
struct [[gnu::aligned(16)]] Aligned;
+
+
+
+
+

Gadget

+
+

A class whose members carry attributes, to exercise member-table tags.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
struct Gadget;
+
+

Member Functions

+ + + + + + + + +
NameDescription
fail [noreturn]A member function that never returns.
run [deprecated]A deprecated member function.
+ +

Data Members

+ + + + + + + +
NameDescription
field [deprecated]A deprecated data member.
+ +
+
+
+

Gadget::fail

+
+

A member function that never returns.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[noreturn]]
+void
+fail();
+
+
+

Return Value

+
+

NOTE

+
+

This function does not return.

+
+
+
+
+
+

Gadget::run

+
+

A deprecated member function.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[deprecated("use run2")]]
+void
+run();
+
+
+

WARNING

+
+

Deprecated: use run2. Use of this entity is allowed but discouraged.

+
+
+
+
+

Gadget::field

+
+

A deprecated data member.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[deprecated]]
+int field;
+
+
+

WARNING

+
+

Deprecated. Use of this entity is allowed but discouraged.

+
+
+
+
+

Gnu

+
+

A class deprecated via the GNU spelling, normalized to the standard form.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
struct [[deprecated("use Gnu2")]] Gnu;
+
+
+

WARNING

+
+

Deprecated: use Gnu2. Use of this entity is allowed but discouraged.

+
+
+
+
+

Widget

+
+

A deprecated class.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
struct [[deprecated("use Widget2")]] Widget;
+
+
+

WARNING

+
+

Deprecated: use Widget2. Use of this entity is allowed but discouraged.

+
+
+
+
+

Color

+
+

A deprecated scoped enum with a deprecated enumerator.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
enum class [[deprecated("use Color2")]] Color : int;
+
+
+

WARNING

+
+

Deprecated: use Color2. Use of this entity is allowed but discouraged.

+
+

Members

+ + + + + + + + + +
Name
Red
Green [deprecated]
Blue
+ +
+
+
+

annotated

+
+

A function carrying the same attribute twice with different arguments.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[clang::annotate("a"), clang::annotate("b")]]
+void
+annotated();
+
+
+
+
+

checked

+
+

A nodiscard function (an attribute with no arguments).

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[nodiscard]]
+int
+checked();
+
+
+

Return Value

+
+

NOTE

+
+

The return value should not be discarded.

+
+
+
+
+
+

compute

+
+

A deprecated function with a message.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[deprecated("use compute2")]]
+int
+compute();
+
+
+

WARNING

+
+

Deprecated: use compute2. Use of this entity is allowed but discouraged.

+
+
+
+
+

log_message

+
+

A printf-like function (an attribute with multiple arguments).

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[gnu::format(printf, 1, 2)]]
+void
+log_message(char const* fmt, ...);
+
+
+
+
+

value

+
+

A deprecated variable.

+
+
+

Synopsis

+

Declared in <attributes.cpp>

+
[[deprecated("use value2")]]
+inline int value = 0;
+
+
+

WARNING

+
+

Deprecated: use value2. Use of this entity is allowed but discouraged.

+
+
+ +
+ + + \ No newline at end of file diff --git a/test-files/golden-tests/generator/hbs/attributes/mrdocs.yml b/test-files/golden-tests/generator/hbs/attributes/mrdocs.yml new file mode 100644 index 0000000000..a5c176dfd4 --- /dev/null +++ b/test-files/golden-tests/generator/hbs/attributes/mrdocs.yml @@ -0,0 +1,5 @@ +generator: [adoc, html] +multipage: false +no-default-styles: true +warn-if-undocumented: false +source-root: . diff --git a/test-files/golden-tests/snippets/landing/sqrt.adoc b/test-files/golden-tests/snippets/landing/sqrt.adoc index 9ce8c385ce..658a0e6d27 100644 --- a/test-files/golden-tests/snippets/landing/sqrt.adoc +++ b/test-files/golden-tests/snippets/landing/sqrt.adoc @@ -43,6 +43,10 @@ Returns zero for zero input. The integer square root of `value`. +[NOTE] +==== +The return value https://en.cppreference.com/cpp/language/attributes/nodiscard[should not be discarded^]. +==== === Template Parameters [cols="1,4"] diff --git a/test-files/golden-tests/snippets/landing/sqrt.html b/test-files/golden-tests/snippets/landing/sqrt.html index a39fff0135..9352ad2eaa 100644 --- a/test-files/golden-tests/snippets/landing/sqrt.html +++ b/test-files/golden-tests/snippets/landing/sqrt.html @@ -42,7 +42,12 @@

NOTE

Return Value

The integer square root of value.

-
+
+

NOTE

+
+

The return value should not be discarded.

+
+

Template Parameters

diff --git a/test-files/golden-tests/snippets/terminate.adoc b/test-files/golden-tests/snippets/terminate.adoc index 8ab1e82383..cd55e0221a 100644 --- a/test-files/golden-tests/snippets/terminate.adoc +++ b/test-files/golden-tests/snippets/terminate.adoc @@ -27,5 +27,11 @@ This function does not return. ==== +=== Return Value + +[NOTE] +==== +This function https://en.cppreference.com/cpp/language/attributes/noreturn[does not return^]. +==== [.small]#Created with https://www.mrdocs.com[MrDocs]# diff --git a/test-files/golden-tests/symbols/enum/attributes.cpp b/test-files/golden-tests/symbols/enum/attributes.cpp new file mode 100644 index 0000000000..af847cd312 --- /dev/null +++ b/test-files/golden-tests/symbols/enum/attributes.cpp @@ -0,0 +1,6 @@ +// Attributes are captured on enums and their enumerators. +enum class [[deprecated("use Color2")]] Color { + Red, + Green [[deprecated("use Blue")]], + Blue +}; diff --git a/test-files/golden-tests/symbols/enum/attributes.xml b/test-files/golden-tests/symbols/enum/attributes.xml new file mode 100644 index 0000000000..65206b37b4 --- /dev/null +++ b/test-files/golden-tests/symbols/enum/attributes.xml @@ -0,0 +1,94 @@ + + + + + + namespace + //////////////////////////8= + regular + + 8ys5YHCZzogRGq/E/f61InZlmOE= + + + + Color + + + attributes.cpp + attributes.cpp + 2 + 1 + + + enum + 8ys5YHCZzogRGq/E/f61InZlmOE= + regular + //////////////////////////8= + + deprecated + "use Color2" + use Color2 + + 1 + + + identifier + int + + + BBOAF6yhnTvCHkG9Jr5y9fvtD58= + Lx0D7a81JkdDRHL9+a9QPTM4Np0= + kd2nnOQJJwznL3PIvdJxDbGUmr4= + + + Red + + + attributes.cpp + attributes.cpp + 3 + 5 + + + enum-constant + BBOAF6yhnTvCHkG9Jr5y9fvtD58= + regular + 8ys5YHCZzogRGq/E/f61InZlmOE= + + + Green + + + attributes.cpp + attributes.cpp + 4 + 5 + + + enum-constant + Lx0D7a81JkdDRHL9+a9QPTM4Np0= + regular + 8ys5YHCZzogRGq/E/f61InZlmOE= + + deprecated + "use Blue" + use Blue + + + + Blue + + + attributes.cpp + attributes.cpp + 5 + 5 + + + enum-constant + kd2nnOQJJwznL3PIvdJxDbGUmr4= + regular + 8ys5YHCZzogRGq/E/f61InZlmOE= + + diff --git a/test-files/golden-tests/symbols/function/attributes-2.xml b/test-files/golden-tests/symbols/function/attributes-2.xml index f8322d6e10..501beb5eea 100644 --- a/test-files/golden-tests/symbols/function/attributes-2.xml +++ b/test-files/golden-tests/symbols/function/attributes-2.xml @@ -25,6 +25,9 @@ e/hP0+mSSe5Ju83w/5pueMcFgLQ=regular//////////////////////////8= + + nodiscard + identifier @@ -39,7 +42,5 @@ normal - 1 - nodiscard diff --git a/test-files/golden-tests/symbols/function/attributes-3.cpp b/test-files/golden-tests/symbols/function/attributes-3.cpp new file mode 100644 index 0000000000..9ddf7b6a97 --- /dev/null +++ b/test-files/golden-tests/symbols/function/attributes-3.cpp @@ -0,0 +1,11 @@ +// A deprecated function with a message, and an attribute with multiple arguments. +[[deprecated("use compute2")]] int compute(); + +[[gnu::format(printf, 1, 2)]] void log_message(char const* fmt, ...); + +// The same attribute repeated with different arguments is kept, not deduplicated. +[[clang::annotate("a"), clang::annotate("b")]] void annotated(); + +// A raw string literal with an inner comma stays a single argument +// (printPretty renders it as a normal string literal). +[[deprecated(R"(use a, b)")]] void raw_message(); diff --git a/test-files/golden-tests/symbols/function/attributes-3.xml b/test-files/golden-tests/symbols/function/attributes-3.xml new file mode 100644 index 0000000000..058ee6e50d --- /dev/null +++ b/test-files/golden-tests/symbols/function/attributes-3.xml @@ -0,0 +1,142 @@ + + + + + + namespace + //////////////////////////8= + regular + + 6BYUopzX+DBqDbRJLP2dm/2e0PI= + 1EwAic4Ry+EDiChtdDEPDw/vEtQ= + K/UYck54RmD14h3yIN/RSUyOvEg= + TC/uKMv0qxSXX9JNVZ+KVi1ZvMU= + + + + annotated + + + attributes-3.cpp + attributes-3.cpp + 7 + 48 + + + function + 6BYUopzX+DBqDbRJLP2dm/2e0PI= + regular + //////////////////////////8= + + clang::annotate + "a" + + + clang::annotate + "b" + + + + identifier + void + + + normal + + + compute + + + attributes-3.cpp + attributes-3.cpp + 2 + 32 + + + function + 1EwAic4Ry+EDiChtdDEPDw/vEtQ= + regular + //////////////////////////8= + + deprecated + "use compute2" + use compute2 + + + + identifier + int + + + normal + + + log_message + + + attributes-3.cpp + attributes-3.cpp + 4 + 31 + + + function + K/UYck54RmD14h3yIN/RSUyOvEg= + regular + //////////////////////////8= + + gnu::format + printf + 1 + 2 + + + + identifier + void + + + + + + 1 + + identifier + char + + + + fmt + + normal + 1 + + + raw_message + + + attributes-3.cpp + attributes-3.cpp + 11 + 31 + + + function + TC/uKMv0qxSXX9JNVZ+KVi1ZvMU= + regular + //////////////////////////8= + + deprecated + "use a, b" + use a, b + + + + identifier + void + + + normal + + diff --git a/test-files/golden-tests/symbols/function/attributes_1.xml b/test-files/golden-tests/symbols/function/attributes_1.xml index 0d2333c000..4dcb707c0b 100644 --- a/test-files/golden-tests/symbols/function/attributes_1.xml +++ b/test-files/golden-tests/symbols/function/attributes_1.xml @@ -25,6 +25,9 @@ s6nsa+zVhpzzrN+yUVPP5rvdXqs= regular //////////////////////////8= + + nodiscard + identifier @@ -32,7 +35,5 @@ normal - 1 - nodiscard diff --git a/test-files/golden-tests/symbols/function/noreturn.xml b/test-files/golden-tests/symbols/function/noreturn.xml index 30e5f99d32..7142dc4b25 100644 --- a/test-files/golden-tests/symbols/function/noreturn.xml +++ b/test-files/golden-tests/symbols/function/noreturn.xml @@ -55,6 +55,9 @@ TkBjWwqMDycyUbq+TJZ9qfUhSn0= regular CgGNdHpW5mG/i5741WPYQDw28OQ= + + noreturn + identifier @@ -62,9 +65,7 @@ normal - 1 1 - noreturn f2 @@ -80,6 +81,9 @@ QjsWLydQujVa097RP8f2Lq3nLQ4= regular CgGNdHpW5mG/i5741WPYQDw28OQ= + + noreturn + identifier @@ -87,9 +91,7 @@ normal - 1 1 - noreturn f1 @@ -105,6 +107,9 @@ CnO51rIKTzfiVKHkR3TdPa0eo+8= regular //////////////////////////8= + + noreturn + identifier @@ -112,7 +117,5 @@ normal - 1 - noreturn diff --git a/test-files/golden-tests/symbols/namespace/attributes.cpp b/test-files/golden-tests/symbols/namespace/attributes.cpp new file mode 100644 index 0000000000..82e777c0ec --- /dev/null +++ b/test-files/golden-tests/symbols/namespace/attributes.cpp @@ -0,0 +1,4 @@ +// Attributes are captured on namespaces. +namespace [[deprecated("use modern")]] legacy_ns { + int helper(); +} diff --git a/test-files/golden-tests/symbols/namespace/attributes.xml b/test-files/golden-tests/symbols/namespace/attributes.xml new file mode 100644 index 0000000000..88f81f1553 --- /dev/null +++ b/test-files/golden-tests/symbols/namespace/attributes.xml @@ -0,0 +1,59 @@ + + + + + + namespace + //////////////////////////8= + regular + + vpR4zjT6foxXlZ9V8mKO1WZYP60= + + + + legacy_ns + + + attributes.cpp + attributes.cpp + 2 + 1 + + + namespace + vpR4zjT6foxXlZ9V8mKO1WZYP60= + regular + //////////////////////////8= + + deprecated + "use modern" + use modern + + + MGjnNpl1DGvioJk9Sr4NgYgDIAo= + + + + helper + + + attributes.cpp + attributes.cpp + 3 + 5 + + + function + MGjnNpl1DGvioJk9Sr4NgYgDIAo= + regular + vpR4zjT6foxXlZ9V8mKO1WZYP60= + + + identifier + int + + + normal + + diff --git a/test-files/golden-tests/symbols/record/attributes.cpp b/test-files/golden-tests/symbols/record/attributes.cpp new file mode 100644 index 0000000000..048ef87630 --- /dev/null +++ b/test-files/golden-tests/symbols/record/attributes.cpp @@ -0,0 +1,5 @@ +// Attributes are captured on record symbols. +struct [[deprecated("use Widget2")]] Widget {}; + +// A scoped attribute with a single argument. +struct [[gnu::aligned(16)]] Aligned {}; diff --git a/test-files/golden-tests/symbols/record/attributes.xml b/test-files/golden-tests/symbols/record/attributes.xml new file mode 100644 index 0000000000..7aa2848b97 --- /dev/null +++ b/test-files/golden-tests/symbols/record/attributes.xml @@ -0,0 +1,72 @@ + + + + + + namespace + //////////////////////////8= + regular + + PQ4j8n/T0THRVULn+iM+q2WWHP4= + 9thLmlNjyEVo7oVvsZ1FMMqUUjg= + + + + Aligned + + + attributes.cpp + attributes.cpp + 5 + 1 + + + record + PQ4j8n/T0THRVULn+iM+q2WWHP4= + regular + //////////////////////////8= + + gnu::aligned + 16 + + struct + + + + + + + + + + + Widget + + + attributes.cpp + attributes.cpp + 2 + 1 + + + record + 9thLmlNjyEVo7oVvsZ1FMMqUUjg= + regular + //////////////////////////8= + + deprecated + "use Widget2" + use Widget2 + + struct + + + + + + + + + + diff --git a/test-files/golden-tests/symbols/typedef/attributes.cpp b/test-files/golden-tests/symbols/typedef/attributes.cpp new file mode 100644 index 0000000000..a596123a4b --- /dev/null +++ b/test-files/golden-tests/symbols/typedef/attributes.cpp @@ -0,0 +1,2 @@ +// A deprecated type alias (the motivating case from issue #1233). +using extension_type [[deprecated("use extent_type")]] = int; diff --git a/test-files/golden-tests/symbols/typedef/attributes.xml b/test-files/golden-tests/symbols/typedef/attributes.xml new file mode 100644 index 0000000000..9af74aab42 --- /dev/null +++ b/test-files/golden-tests/symbols/typedef/attributes.xml @@ -0,0 +1,41 @@ + + + + + + namespace + //////////////////////////8= + regular + + Nz16WgwQioPGG3IEr5zgZyHBaR4= + + + + extension_type + + + attributes.cpp + attributes.cpp + 2 + 1 + + + typedef + Nz16WgwQioPGG3IEr5zgZyHBaR4= + regular + //////////////////////////8= + + deprecated + "use extent_type" + use extent_type + + + + identifier + int + + + 1 + + diff --git a/test-files/golden-tests/symbols/variable/no_unique_address.xml b/test-files/golden-tests/symbols/variable/no_unique_address.xml index 2cc5a9fc5d..2b6c8920bb 100644 --- a/test-files/golden-tests/symbols/variable/no_unique_address.xml +++ b/test-files/golden-tests/symbols/variable/no_unique_address.xml @@ -76,6 +76,12 @@ h2j8f921HD+Fyaokcs4ndGM/yNk= regular CgGNdHpW5mG/i5741WPYQDw28OQ= + + deprecated + + + maybe_unused + identifier @@ -84,10 +90,6 @@ Empty{} - deprecated - maybe_unused - 1 - 1 1