diff --git a/.gitattributes b/.gitattributes index 95e84f1eb5..9fb3b4e6fa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ test-files/**/*.xml binary +test-files/golden-tests/** text eol=lf diff --git a/docs/mrdocs.schema.json b/docs/mrdocs.schema.json index 17ff4f5e8d..f92abfd400 100644 --- a/docs/mrdocs.schema.json +++ b/docs/mrdocs.schema.json @@ -10,6 +10,10 @@ "anonymous-namespaces": { "default": true, "description": "Determine whether symbols in anonymous namespaces should be extracted. When set to `always`, symbols in anonymous namespaces are always extracted. When set to `dependency`, symbols in anonymous namespaces are extracted only if they are referenced by the source code. When set to `never`, symbols in anonymous namespaces are never extracted.", + "enum": [ + true, + false + ], "title": "Extraction policy for anonymous namespaces", "type": "boolean" }, @@ -43,6 +47,10 @@ "embedded": { "default": false, "description": "Output an embeddable document, which excludes the header, the footer, and everything outside the body of the document. This option is useful for producing documents that can be inserted into an external template.", + "enum": [ + true, + false + ], "title": "Output an embeddable document", "type": "boolean" }, @@ -106,12 +114,20 @@ "ignore-failures": { "default": false, "description": "When set to true, MrDocs continues to generate the documentation even if there are AST visitation failures. AST visitation failures occur when the source code contains constructs that are not supported by MrDocs.", + "enum": [ + true, + false + ], "title": "Whether AST visitation failures should not stop the program", "type": "boolean" }, "ignore-map-errors": { "default": false, "description": "When set to true, MrDocs continues to generate the documentation even if some files are not mapped correctly. Files are not mapped correctly when the source file is not found or the compilation database does not contain the compiler flags for the source file.", + "enum": [ + true, + false + ], "title": "Continue if files are not mapped correctly", "type": "boolean" }, @@ -156,6 +172,10 @@ "legible-names": { "default": true, "description": "Use legible names for ids in the documentation. When set to true, MrDocs uses legible names for symbols in the documentation. These are symbols that are legible but still safe for URLs. When the option is set to false, MrDocs uses a hash of the symbol ID.", + "enum": [ + true, + false + ], "title": "Use legible names", "type": "boolean" }, @@ -173,6 +193,10 @@ "multipage": { "default": true, "description": "Generates a multipage documentation. The output directory must be a directory. This option acts as a hint to the generator to create a multipage documentation. Whether the hint is followed or not depends on the generator.", + "enum": [ + true, + false + ], "title": "Generate a multipage documentation", "type": "boolean" }, @@ -185,18 +209,30 @@ "private-bases": { "default": true, "description": "Determine whether private base classes should be extracted", + "enum": [ + true, + false + ], "title": "Extraction policy for private base classes", "type": "boolean" }, "private-members": { "default": false, "description": "Determine whether private class members should be extracted", + "enum": [ + true, + false + ], "title": "Extraction policy for private class members", "type": "boolean" }, "recursive": { "default": true, "description": "Recursively include files. When set to true, MrDocs includes files in subdirectories of the input directories. When set to false, MrDocs includes only the files in the input directories.", + "enum": [ + true, + false + ], "title": "Recursively include files from \"input\" paths", "type": "boolean" }, @@ -210,16 +246,20 @@ }, "see-below": { "default": [], - "description": "Symbols that match one of these filters are tagged as \"see-below\" in the documentation, and so do symbols in scopes tagged as \"see-below\". This option is used to remove details about symbols that are considered part of the private API of the project. In the documentation page for this symbol, the synopsis of the implementation is rendered as \"see-below\" and members of scopes (such as a namespace or record) are not listed. The rest of the documentation is rendered as usual. See the documentation for \"include-symbol\" for the pattern syntax.", + "description": "Symbols that match one of these filters are tagged as \"see-below\" in the documentation, and so do symbols in scopes tagged as \"see-below\". This option is used to remove details about symbols that are considered part of the private API of the project but the user might need to interact with. In the documentation page for this symbol, the symbol is exposition only: the synopsis of the implementation is rendered as \"see-below\" and members of scopes (such as a namespace or record) are not listed. The rest of the documentation is rendered as usual to explain the symbol. See the documentation for \"include-symbol\" for the pattern syntax.", "items": { "type": "string" }, - "title": "Symbols rendered as \"see-below\"", + "title": "Exposition only symbols rendered as \"see-below\".", "type": "array" }, "sfinae": { "default": true, "description": "When set to true, MrDocs detects SFINAE expressions in the source code and extracts them as part of the documentation. Expressions such as `std::enable_if<...>` are detected, removed, and documented as a requirement. MrDocs uses an algorithm that extracts SFINAE infomation from types by identifying inspecting the primary template and specializations to detect the result type and the controlling expressions in a specialization.", + "enum": [ + true, + false + ], "title": "Detect and reduce SFINAE expressions", "type": "boolean" }, @@ -259,18 +299,30 @@ "use-system-libc": { "default": false, "description": "To achieve reproducible results, MrDocs bundles the LibC headers with its definitions. To use the C standard library available in the system instead, set this option to true.", + "enum": [ + true, + false + ], "title": "Use the system C standard library", "type": "boolean" }, "use-system-stdlib": { "default": false, "description": "To achieve reproducible results, MrDocs bundles the LibC++ headers. To use the C++ standard library available in the system instead, set this option to true.", + "enum": [ + true, + false + ], "title": "Use the system C++ standard library", "type": "boolean" }, "verbose": { "default": false, "description": "Verbose output. When set to true, MrDocs outputs additional information during the generation of the documentation.", + "enum": [ + true, + false + ], "title": "Verbose output", "type": "boolean" } diff --git a/include/mrdocs/ADT/Optional.hpp b/include/mrdocs/ADT/Optional.hpp index db7f791b96..d6d1540f92 100644 --- a/include/mrdocs/ADT/Optional.hpp +++ b/include/mrdocs/ADT/Optional.hpp @@ -16,9 +16,9 @@ #include #include #include +#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** The default empty predicate. @@ -27,21 +27,23 @@ namespace mrdocs { */ struct DefaultEmptyPredicate { - template - constexpr bool operator()(T const& t) const noexcept - requires requires - { - { t.empty() } -> std::convertible_to; - } + template + constexpr + bool + operator()(T const& t) const noexcept { - return t.empty(); + return std::ranges::empty(t); } template - constexpr bool operator()(T const& t) const noexcept + constexpr + bool + operator()(T const& t) const noexcept { - return ! t; + return !t; } + + }; /** A compact optional. @@ -138,7 +140,6 @@ class Optional } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/ADT/PolymorphicValue.hpp b/include/mrdocs/ADT/PolymorphicValue.hpp new file mode 100644 index 0000000000..0e5155f79f --- /dev/null +++ b/include/mrdocs/ADT/PolymorphicValue.hpp @@ -0,0 +1,881 @@ +// +// This is a derivative work. originally part of the LLVM Project. +// 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) 2025 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_ADT_POLYMORPHICVALUE_HPP +#define MRDOCS_API_ADT_POLYMORPHICVALUE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace clang::mrdocs { + +/** Default copier for PolymorphicValue. + + This class template is used as the + default copier for the class + template PolymorphicValue. +*/ +template +struct DefaultDeleter +{ + constexpr + void + operator()(Base const* p) const noexcept + { + delete p; + } +}; + +/** Default copier for PolymorphicValue. + + This class template is used as the + default copier for the class + template PolymorphicValue. +*/ +template +struct DefaultCopier +{ + Base* + operator()(Base const& t) const + { + return new Base(t); + } +}; + +/** Exception thrown when a polymorphic value + cannot be constructed. + + This exception is thrown when a polymorphic + value cannot be constructed. This can happen + when the type `T` is abstract or when the + type `T` is not publicly derived from the + type of the object being constructed. +*/ +class BadPolymorphicValueConstruction + : public std::exception +{ +public: + BadPolymorphicValueConstruction() noexcept = default; + const char* what() const noexcept override { + return "bad polymorphic value construction"; + } +}; + +template +class PolymorphicValue; + +template +struct IsPolymorphicValue : std::false_type {}; + +template +struct IsPolymorphicValue> : std::true_type {}; + +template +inline constexpr bool IsPolymorphicValue_v = IsPolymorphicValue::value; + +/** A polymorphic value-type. + + This class supports polymorphic objects + with value-like semantics. + + It works like std::optional in the sense + that it can be engaged or disengaged. It can + also be copied and moved. + + It also works like std::unique_ptr in the + sense that it can be used to manage the + lifetime of a polymorphic object. A + PolymorphicValue can be hold an object + of any class publicly derived from T + and copying the PolymorphicValue will + copy the object of the derived class. + + This combination also allows for a + class that uses PolymorphicValue as + a member to be copyable, movable, + default constructible, default destructible, + and comparable. + + These properties make ownership of members + of composite objects clear and explicit. + It also allows for the use of polymorphism + with value-like semantics and default copy, + move, assignment, destruction, and comparisons + all available by default, without replicating + boilerplate code in all derived classes. + + @par Deep copies + + To copy polymorphic objects, the class uses the + copy constructor of the owned derived-type + object when copying to another value. + Similarly, to allow correct destruction of + derived objects, it uses the destructor of + the owned derived-type object in the + destructor. + + @par Constructors + + A value can be constructed from a derived-type, + a pointer to a derived type, and a pointer + to a derived type with a custom copier and deleter + function. When not supplied, a custom copier and + deleter are provided. The value can also be + constructed from a `std::unique_ptr`. A value + cannot be constructed from an abstract class + even if `T` is abstract. + + @par Default copier and deleter + + The standard library already provides a standard + deleter for `std::unique_ptr`. The default copier + is a pointer to a function using the copy + constructor of the derived-type object. + + @par Empty State + + A value can be in an empty state. The state is + useful for cheap default construction and + for later assignment. + + This implementation is inspired + by p0201r5. +*/ +template +class PolymorphicValue +{ + // + // Assertions + // + static_assert(!std::is_union_v); + static_assert(std::is_class_v); + + // + // Members + // + + // Block containing all the information about the object, copier + // and deleter in a single allocation + detail::PolymorphicStorage* s_{nullptr}; + + // Local pointer to the object for convenience / performance + Base* ptr_{nullptr}; + + // + // Friends + // + template + friend class PolymorphicValue; + + template < + class BaseU, + std::derived_from Derived, + class... Args> + requires std::constructible_from + friend + constexpr + PolymorphicValue + MakePolymorphicValue(Args&&... args); + + template + requires std::derived_from + friend + constexpr + PolymorphicValue + DynamicCast(PolymorphicValue&& other); + +public: + using element_type = Base; + + /** Default constructor. + + Ensures: *this is empty. + */ + constexpr + PolymorphicValue() noexcept = default; + + /** Constructs an empty PolymorphicValue. + + Ensures: *this is empty. + */ + constexpr + PolymorphicValue(std::nullptr_t) noexcept {} + + /** Constructs a PolymorphicValue which owns an object of type V. + + Constructs a PolymorphicValue which owns an object of type V, + direct-non-list-initialized with std::forward(u), where + V is remove_cvref_t. + + Throws: Any exception thrown by the selected constructor of V + or bad_alloc if required storage cannot be obtained. + + Constraints: V* is convertible to T*. + + @tparam Derived The type of the object to be owned. + @param other The object to be owned. + + @throws std::bad_alloc if required storage cannot be obtained. + */ + template Derived> + requires (!IsPolymorphicValue_v) + explicit constexpr + PolymorphicValue(Derived&& other) + : PolymorphicValue( + std::in_place_type>, + std::forward(other)) {} + + /** Constructs a PolymorphicValue which owns the object pointed to by p. + + If p is null, creates an empty object. + If p is non-null creates an object that owns the object *p, with + a copier and deleter initialized from std::move(c) and std::move(d). + + If p is non-null then the expression c(*p) has type U*. + The expression d(p) is well-formed, has well-defined behavior, + and does not throw exceptions. + + Move-initialization of objects of type C and D does not + exit via an exception. + + A copier and deleter are said to be present in a non-empty + object initialized with this constructor. + + Constraints: U* is convertible to T*. + + Expects: C and D meet the C++17 CopyConstructible and C++17 + Destructible requirements. + + @tparam Derived The type of the object to be owned. + @tparam Copier The type of the copier. + @tparam Deleter The type of the deleter. + @param p Pointer to the object to be owned. + @param c The copier. + @param d The deleter. + + @throws std::bad_alloc if required storage cannot be obtained. + @throws BadPolymorphicValueConstruction if + std::same_as>, std::same_as> + and typeid(*p)!=typeid(U) are all true. + */ + template < + std::derived_from Derived, + class Copier = DefaultCopier, + class Deleter = DefaultDeleter> + requires + std::is_default_constructible_v && + std::is_default_constructible_v && + (!std::is_pointer_v) && + std::copy_constructible && + std::destructible && + std::is_nothrow_move_constructible_v && + std::is_nothrow_move_constructible_v + explicit constexpr + PolymorphicValue(Derived* p, Copier c, Deleter d) + { + // If p is null, creates an empty object. + if (!p) + { + return; + } + + // If using the default copier and deleter, check if the type of the object is correct + if constexpr (std::same_as> && std::same_as>) + { + if (typeid(*p) != typeid(Derived)) + { + throw BadPolymorphicValueConstruction(); + } + } + + // Create a control block that stores the pointer, deleter, and copier + using CBT = detail::PointerPolymorphicStorage; + s_ = new CBT(std::move(p), std::move(c), std::move(d)); + ptr_ = s_->ptr(); + } + + /// @copydoc PolymorphicValue(Derived*, Copier, Deleter) + template < + std::derived_from Derived, + class Copier = DefaultCopier> + requires + std::is_default_constructible_v && + std::copy_constructible && + std::destructible && + std::is_nothrow_move_constructible_v + explicit constexpr + PolymorphicValue(Derived* p, Copier c) + : PolymorphicValue(p, c, DefaultDeleter{}) {} + + /// @copydoc PolymorphicValue(Derived*, Copier, Deleter) + template Derived> + explicit constexpr + PolymorphicValue(Derived* p) + : PolymorphicValue(p, DefaultCopier{}, DefaultDeleter{}) {} + + /** Copy constructor. + + If pv is empty, constructs an empty object. Otherwise, creates an object + that owns a copy of the object managed by pv. + + If a copier and deleter are present in pv then the copy + is created by the copier in pv. + + Otherwise, the copy is created by copy construction of the owned + object. + + If a copier and deleter are present in pv then the copier and + deleter of the object constructed are copied from those in pv. + + Throws: Any exception thrown by invocation of the copier, + copying the copier and deleter, or bad_alloc if required + storage cannot be obtained. + + @post bool(*this) == bool(pv). + + @param other The PolymorphicValue to copy from. + + @throws std::bad_alloc if required storage cannot be obtained. + */ + constexpr + PolymorphicValue(PolymorphicValue const& other) + { + if (!other) + { + return; + } + auto* tmp = other.s_->clone(); + ptr_ = tmp->ptr(); + s_ = std::move(tmp); + } + + /** Copy constructor. + + If pv is empty, constructs an empty object. Otherwise, creates an object + that owns a copy of the object managed by pv. + + If a copier and deleter are present in pv then the copy + is created by the copier in pv. + + Otherwise, the copy is created by copy construction of the owned + object. + + If a copier and deleter are present in pv then the copier and + deleter of the object constructed are copied from those in pv. + + Throws: Any exception thrown by invocation of the copier, + copying the copier and deleter, or bad_alloc if required + storage cannot be obtained. + + Constraints: U* is convertible to T*. + + @post bool(*this) == bool(pv). + + @param other The PolymorphicValue to copy from. + + @throws std::bad_alloc if required storage cannot be obtained. + */ + template Derived> + requires (!std::same_as) + explicit constexpr + PolymorphicValue(PolymorphicValue const& other) + { + if (!other) + { + return; + } + auto tmp = other.s_->clone(); + using CBT = detail::DelegatingPolymorphicStorage; + s_ = new CBT(tmp); + ptr_ = s_->ptr(); + } + + /** Move constructor. + + If pv is empty, constructs an empty object. + Otherwise, the object owned by pv is transferred to the + constructed object. + + If a copier and deleter are present in pv then the + copier and deleter are transferred to the + constructed object. + + @post *this owns the object previously owned by pv (if any). pv is empty. + + @param other The PolymorphicValue to move from. + */ + constexpr + PolymorphicValue(PolymorphicValue&& other) noexcept + { + ptr_ = std::exchange(other.ptr_, nullptr); + s_ = std::exchange(other.s_, nullptr); + } + + /** Move constructor. + + If pv is empty, constructs an empty object. + Otherwise, the object owned by pv is transferred to the + constructed object. + + If a copier and deleter are present in pv then the + copier and deleter are transferred to the + constructed object. + + Constraints: U* is convertible to T* + + @post *this owns the object previously owned by pv (if any). pv is empty. + + @param other The PolymorphicValue to move from. + */ + template Derived> + requires (!std::same_as) + explicit constexpr + PolymorphicValue(PolymorphicValue&& other) noexcept + { + if (!other) + { + return; + } + using CBT = detail::DelegatingPolymorphicStorage; + s_ = new CBT(std::exchange(other.s_, nullptr)); + ptr_ = s_->ptr(); + other.ptr_ = nullptr; + } + + /** In-place constructor. + */ + template + requires + std::derived_from, Base> && + (!IsPolymorphicValue_v>) && + std::constructible_from + explicit constexpr + PolymorphicValue( + std::in_place_type_t, + Args&&... args) + : s_(new detail::DirectPolymorphicStorage(std::forward(args)...)) + , ptr_(s_->ptr()) + {} + + /** Destructor. + + If a copier c and a deleter d are present, evaluates + d(operator->()) and destroys c and d. + + Otherwise, destroys the owned object (if any). + */ + constexpr + ~PolymorphicValue() + { + delete s_; + ptr_ = nullptr; + s_ = nullptr; + } + + /** Copy assignment operator. + + Equivalent to `PolymorphicValue(pv).swap(*this)`. + + No effects if an exception is thrown. + + Throws: Any exception thrown by the copier or bad_alloc if required storage cannot be obtained. + + @post The state of *this is as if copy constructed from pv. + + @param other The PolymorphicValue to copy from. + @return Reference to *this. + + @throws std::bad_alloc if required storage cannot be obtained. + */ + constexpr + PolymorphicValue& + operator=(PolymorphicValue const& other) + { + if (&other == this) + { + return *this; + } + + if (!other) + { + delete s_; + s_ = nullptr; + ptr_ = nullptr; + return *this; + } + + auto* tmp = other.s_->clone(); + s_ = std::move(tmp); + ptr_ = s_->ptr(); + return *this; + } + + /** Move assignment operator. + + Equivalent to `PolymorphicValue(pv).swap(*this)`. + + @post The state of *this is as if copy constructed from pv. + + @param other The PolymorphicValue to copy from. + @return Reference to *this. + + @throws std::bad_alloc if required storage cannot be obtained. + */ + constexpr + PolymorphicValue& + operator=(PolymorphicValue&& other) noexcept + { + if (&other == this) + { + return *this; + } + + s_ = std::exchange(other.s_, nullptr); + ptr_ = std::exchange(other.ptr_, nullptr); + return *this; + } + + /** Move assignment operator. + + Assign directly from a derived object. + + Equivalent to `PolymorphicValue(std::move(other)).swap(*this)`. + + This is an extension to the standard that + extremely useful in MrDocs because it allows + us to construct the object of the derived type + on the stack and then assign it to a PolymorphicValue + member of a class. + + @post The state of *this is as if copy constructed from other. + + @param other The derived object to copy from. + @return Reference to *this. + + @throws std::bad_alloc if required storage cannot be obtained. + */ + template + requires std::derived_from, Base> + constexpr + PolymorphicValue& + operator=(Derived&& other) noexcept + { + *this = PolymorphicValue( + std::in_place_type>, + std::forward(other)); + return *this; + } + + /** Exchanges the state of p and *this. + + @param other The PolymorphicValue to swap with. + */ + constexpr + void + swap(PolymorphicValue& other) noexcept + { + using std::swap; + swap(ptr_, other.ptr_); + swap(s_, other.s_); + } + + /** Returns a reference to the owned object. + + @return Reference to the owned object. + + @pre bool(*this) is true. + */ + Base const& + operator*() const noexcept(noexcept(*std::declval())) + { + MRDOCS_ASSERT(ptr_); + return *ptr_; + } + + /** Returns a reference to the owned object. + + @return Reference to the owned object. + + @pre bool(*this) is true. + */ + Base& + operator*() noexcept(noexcept(*std::declval())) + { + MRDOCS_ASSERT(ptr_); + return *ptr_; + } + + /** Returns a pointer to the owned object. + + @return Pointer to the owned object. + + @pre bool(*this) is true. + */ + Base const* + operator->() const noexcept + { + return ptr_; + } + + /** Returns a pointer to the owned object. + + @return Pointer to the owned object. + + @pre bool(*this) is true. + */ + Base* + operator->() noexcept + { + return ptr_; + } + + /** Checks if the PolymorphicValue owns an object. + + @return true if the PolymorphicValue owns an object, otherwise false. + */ + explicit + operator + bool() const noexcept + { + return static_cast(ptr_); + } +}; + +/** Creates a PolymorphicValue owning an object of type U. + + @tparam Base The type of the PolymorphicValue. + @tparam Derived The type of the object to be owned, defaults to T. + @tparam Args The types of the arguments to forward to the constructor of U. + @param args The arguments to forward to the constructor of U. + @return A PolymorphicValue owning an object of type U direct-non-list-initialized with std::forward(ts)... + */ +template < + class Base, + std::derived_from Derived = Base, + class... Args> +requires std::constructible_from +constexpr +PolymorphicValue +MakePolymorphicValue(Args&&... args) +{ + PolymorphicValue p; + using BCT = detail::DirectPolymorphicStorage; + p.s_ = new BCT(std::forward(args)...); + p.ptr_ = p.s_->ptr(); + return p; +} + +/** Dynamically cast the object owned by a PolymorphicValue. + + @tparam Derived The type to cast to. + @tparam Base The type of the PolymorphicValue. + @param other The PolymorphicValue to cast. + @return A pointer to the object owned by other cast to Derived, or nullptr if the cast fails. + */ +template +requires std::derived_from +constexpr +PolymorphicValue +DynamicCast(PolymorphicValue&& other) +{ + if (!other) + { + return {}; + } + if (auto ptr = dynamic_cast(other.ptr_)) + { + PolymorphicValue result; + using CBT = detail::DelegatingPolymorphicStorage; + result.s_ = new CBT(std::move(other.s_)); + result.ptr_ = result.s_->ptr(); + other.s_ = nullptr; + other.ptr_ = nullptr; + return result; + } + other = {}; + return {}; +} + +/** Exchanges the state of two PolymorphicValue objects. + + @tparam Base The type of the PolymorphicValue. + @param lhs The first PolymorphicValue to swap. + @param rhs The second PolymorphicValue to swap. + + Effects: Equivalent to p.swap(u). + */ +template +constexpr +void +swap(PolymorphicValue& lhs, PolymorphicValue& rhs) noexcept +{ + lhs.swap(rhs); +} + +/** Determine if a PolymorphicValue is of a given type. + + @tparam Derived The type to check for. + @tparam Base The type of the PolymorphicValue. + @param pv The PolymorphicValue to check. + @return true if pv owns an object of type Derived, otherwise false. + */ +template +requires std::derived_from +bool +IsA(PolymorphicValue const& pv) +{ + if (!pv) + { + return false; + } + return dynamic_cast(std::addressof(*pv)); +} + +/** Retrieves the value of the PolymorphicValue as a qualified Derived type. + + This function can retrieve the value as a pointer, reference, or type name, + and can handle const-qualified versions. + + If the requested type is not const, the input type should be mutable. + If the requested type is const, the input type can be mutable or const. + + The function validates the derived type. + If the object is not of the derived type, the pointer versions return + `nullptr` and the reference/type name versions throw an exception. + + @tparam T The requested type (e.g., DerivedTypeName*, DerivedTypeName&, or DerivedTypeName). + @tparam Base The base type of the PolymorphicValue. + @param pv The PolymorphicValue to retrieve the value from. + @return The value of the PolymorphicValue as the requested type. + @throws std::bad_cast if the requested type is a reference or type name and the object is not of the derived type. + */ +template +requires + std::is_pointer_v && + std::derived_from, Base> +T +get(PolymorphicValue& pv) +{ + return dynamic_cast(pv.operator->()); +} + +/// @copydoc get +template +requires + std::is_reference_v && + std::derived_from, Base> +T +get(PolymorphicValue& pv) +{ + if (auto* ptr = dynamic_cast*>(pv.operator->())) + { + return *ptr; + } + throw std::bad_cast(); +} + +/// @copydoc get +template +requires + (!std::is_pointer_v) && + (!std::is_reference_v) && + std::derived_from, Base> +T& +get(PolymorphicValue& pv) +{ + return get(pv); +} + +/// @copydoc get +template +requires + std::is_pointer_v && + std::derived_from, Base> +std::add_const_t>* +get(PolymorphicValue const& pv) +{ + return dynamic_cast>*>(pv.operator->()); +} + +/// @copydoc get +template +requires + std::is_reference_v && + std::derived_from, Base> +std::add_const_t>& +get(PolymorphicValue const& pv) +{ + if (auto* ptr = dynamic_cast>*>(pv.operator->())) + { + return *ptr; + } + throw std::bad_cast(); +} + +/// @copydoc get +template +requires + (!std::is_pointer_v) && + (!std::is_reference_v) && + std::derived_from, Base> +std::add_const_t& +get(PolymorphicValue const& pv) +{ + return get(pv); +} + +/** Compares two PolymorphicValue that have visit functions + + This function compares two PolymorphicValue objects that + have visit functions for the Base type. + + The visit function is used to compare the two objects + if they are of the same derived type. + + If the two objects are of different derived types, the + comparison is based on the type_info of the derived types. + + If any of the objects is empty, the comparison is based + on the emptiness of the objects. + + @tparam Base The type of the PolymorphicValue. + @param lhs The first PolymorphicValue to compare. + @param rhs The second PolymorphicValue to compare. + @return true if the two PolymorphicValue objects are equal, otherwise false. + */ +template +requires detail::CanVisitCompare +auto +CompareDerived( + PolymorphicValue const& lhs, + PolymorphicValue const& rhs) +{ + if (lhs && rhs) + { + if (lhs->Kind == rhs->Kind) + { + return visit(*lhs, detail::VisitCompareFn(*rhs)); + } + return lhs->Kind <=> rhs->Kind; + } + return !lhs ? std::strong_ordering::less + : std::strong_ordering::greater; +} + +} // clang::mrdocs + +#endif diff --git a/include/mrdocs/ADT/detail/PolymorphicValue.hpp b/include/mrdocs/ADT/detail/PolymorphicValue.hpp new file mode 100644 index 0000000000..7891be7c09 --- /dev/null +++ b/include/mrdocs/ADT/detail/PolymorphicValue.hpp @@ -0,0 +1,178 @@ +// +// This is a derivative work. originally part of the LLVM Project. +// 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) 2025 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_ADT_DETAIL_POLYMORPHICVALUE_HPP +#define MRDOCS_API_ADT_DETAIL_POLYMORPHICVALUE_HPP + +#include +#include +#include +#include +#include + +namespace clang::mrdocs::detail { + +// Abstract base class for control blocks +// A control block is a block of storage to hold the derived +// object and a virtual function to delete it. +// The object is stored in a unique_ptr so it already contains +// the delete operation. +// The copies are implemented with clone(). +template +struct PolymorphicStorage +{ + constexpr virtual ~PolymorphicStorage() = default; + + // Clone the control block. + // Deallocation happens though the destroy function implemented + // in the derived class. + constexpr virtual + PolymorphicStorage* + clone() const = 0; + + constexpr virtual Base* ptr() = 0; +}; + +// Control block that holds the object directly as a member +template +class DirectPolymorphicStorage final + : public PolymorphicStorage +{ + static_assert(!std::is_reference_v); + Derived u_; + +public: + constexpr ~DirectPolymorphicStorage() override = default; + + template + constexpr explicit + DirectPolymorphicStorage(Args&&... args) + : u_(Derived(std::forward(args)...)) {} + + constexpr + PolymorphicStorage* + clone() const override + { + return new DirectPolymorphicStorage(*this); + } + + constexpr + Base* + ptr() override + { + return std::addressof(u_); + } +}; + +// Control block that holds the object in a unique_ptr +// and stores a copier function +// This is the main control block type used +// by the PolymorphicValue class +template +class PointerPolymorphicStorage final + : public PolymorphicStorage + , public Copier +{ + Derived* p_{nullptr}; + Copier c_; + Deleter d_; + +public: + // Virtual destructor + constexpr + ~PointerPolymorphicStorage() override + { + d_(p_); + } + + constexpr + explicit + PointerPolymorphicStorage(Derived* u, Copier c, Deleter d) + : p_(u), c_(std::move(c)), d_(std::move(d)) {} + + constexpr + PolymorphicStorage* + clone() const override + { + MRDOCS_ASSERT(p_); + return new PointerPolymorphicStorage(c_(*p_), c_, d_); + } + + constexpr + Base* + ptr() override + { + return p_; + } +}; + +// Control block that delegates to another control block +// This is necessary to implement conversions +template +class DelegatingPolymorphicStorage final + : public PolymorphicStorage +{ + PolymorphicStorage* delegate_{nullptr}; + +public: + // virtual destructor + constexpr + ~DelegatingPolymorphicStorage() override + { + delete delegate_; + } + + constexpr + explicit + DelegatingPolymorphicStorage(PolymorphicStorage* b) + : delegate_(std::move(b)) + {} + + constexpr + PolymorphicStorage* + clone() const override + { + return new DelegatingPolymorphicStorage(delegate_->clone()); + } + + constexpr + Base* + ptr() override { + return dynamic_cast(delegate_->ptr()); + } +}; + +// A function to compare two polymorphic objects that +// store the same derived type +template +struct VisitCompareFn { + Base const& rhs; + + template + auto + operator()(Derived const& lhsDerived) + { + auto const& rhsDerived = dynamic_cast(rhs); + return lhsDerived <=> rhsDerived; + } +}; + +/** Determines if a type can be visited with VisitCompareFn + */ +template +concept CanVisitCompare = requires(Base const& b) +{ + visit(b, VisitCompareFn{b}); +}; + +} // clang::mrdocs + +#endif diff --git a/include/mrdocs/Metadata.hpp b/include/mrdocs/Metadata.hpp index 55e8757f66..765d491bd7 100644 --- a/include/mrdocs/Metadata.hpp +++ b/include/mrdocs/Metadata.hpp @@ -17,29 +17,29 @@ // All headers related to // metadata extracted from AST -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include #include #include #include #include -#include -#include -#include -#include #include -#include #include #include #include -#include #include -#include #endif diff --git a/include/mrdocs/Metadata/DomCorpus.hpp b/include/mrdocs/Metadata/DomCorpus.hpp index ee9b8831e8..11af1e4205 100644 --- a/include/mrdocs/Metadata/DomCorpus.hpp +++ b/include/mrdocs/Metadata/DomCorpus.hpp @@ -20,8 +20,7 @@ #include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Front-end factory for producing Dom nodes. @@ -117,7 +116,6 @@ class MRDOCS_DECL getJavadoc(Javadoc const& jd) const; }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Expression.hpp b/include/mrdocs/Metadata/Expression.hpp index 890ab68137..444ca8c5b0 100644 --- a/include/mrdocs/Metadata/Expression.hpp +++ b/include/mrdocs/Metadata/Expression.hpp @@ -11,19 +11,19 @@ #ifndef MRDOCS_API_METADATA_EXPRESSION_HPP #define MRDOCS_API_METADATA_EXPRESSION_HPP -#include #include #include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Represents an expression */ struct ExprInfo { /** The expression, as written */ std::string Written; + + auto operator<=>(ExprInfo const&) const = default; }; /** Represents an expression with a (possibly known) value */ @@ -41,11 +41,12 @@ struct ConstantExprInfo */ std::optional Value; + auto operator<=>(ConstantExprInfo const&) const = default; + static_assert(std::integral, "expression type must be integral"); }; -} // clang -} // mrdocs +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/ExtractionMode.hpp b/include/mrdocs/Metadata/ExtractionMode.hpp index 4eb8f088ad..e5bfdbfc6d 100644 --- a/include/mrdocs/Metadata/ExtractionMode.hpp +++ b/include/mrdocs/Metadata/ExtractionMode.hpp @@ -12,9 +12,7 @@ #ifndef MRDOCS_API_METADATA_EXTRACTIONMODE_HPP #define MRDOCS_API_METADATA_EXTRACTIONMODE_HPP -#include #include -#include namespace clang::mrdocs { diff --git a/include/mrdocs/Metadata/Info.hpp b/include/mrdocs/Metadata/Info.hpp index 5e65ebdc60..30826f9c9a 100644 --- a/include/mrdocs/Metadata/Info.hpp +++ b/include/mrdocs/Metadata/Info.hpp @@ -12,15 +12,16 @@ #ifndef MRDOCS_API_METADATA_INFO_HPP #define MRDOCS_API_METADATA_INFO_HPP -#include +#include +#include +#include #include +#include #include #include #include -#include +#include #include -#include -#include namespace clang::mrdocs { @@ -107,11 +108,12 @@ struct MRDOCS_VISIBLE /** The extracted javadoc for this declaration. */ - std::unique_ptr javadoc; + std::optional javadoc; //-------------------------------------------- virtual ~Info() = default; + Info(Info const& Other) = delete; /** Move constructor. diff --git a/include/mrdocs/Metadata/Concept.hpp b/include/mrdocs/Metadata/Info/Concept.hpp similarity index 85% rename from include/mrdocs/Metadata/Concept.hpp rename to include/mrdocs/Metadata/Info/Concept.hpp index be13fd2e22..abe14ab376 100644 --- a/include/mrdocs/Metadata/Concept.hpp +++ b/include/mrdocs/Metadata/Info/Concept.hpp @@ -11,18 +11,16 @@ #ifndef MRDOCS_API_METADATA_CONCEPT_HPP #define MRDOCS_API_METADATA_CONCEPT_HPP -#include #include #include #include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Info for concepts. */ -struct ConceptInfo +struct ConceptInfo final : InfoCommonBase , SourceInfo { @@ -36,13 +34,12 @@ struct ConceptInfo //-------------------------------------------- - explicit ConceptInfo(SymbolID ID) noexcept + explicit ConceptInfo(SymbolID const &ID) noexcept : InfoCommonBase(ID) { } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Enum.hpp b/include/mrdocs/Metadata/Info/Enum.hpp similarity index 64% rename from include/mrdocs/Metadata/Enum.hpp rename to include/mrdocs/Metadata/Info/Enum.hpp index 101ecfc494..cfda1d96ae 100644 --- a/include/mrdocs/Metadata/Enum.hpp +++ b/include/mrdocs/Metadata/Info/Enum.hpp @@ -12,23 +12,15 @@ #ifndef MRDOCS_API_METADATA_ENUM_HPP #define MRDOCS_API_METADATA_ENUM_HPP -#include -#include -#include -#include +#include +#include #include +#include #include -#include -#include -#include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { -// TODO: Expand to allow for documenting templating. -// Info for types. -struct EnumInfo +struct EnumInfo final : InfoCommonBase , SourceInfo , ScopeInfo @@ -36,10 +28,10 @@ struct EnumInfo // Indicates whether this enum is scoped (e.g. enum class). bool Scoped = false; - // Set to nonempty to the type when this is an explicitly typed enum. For + // Set too nonempty to the type when this is an explicitly typed enum. For // enum Foo : short { ... }; // this will be "short". - std::unique_ptr UnderlyingType; + PolymorphicValue UnderlyingType; //-------------------------------------------- @@ -49,7 +41,6 @@ struct EnumInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/EnumConstant.hpp b/include/mrdocs/Metadata/Info/EnumConstant.hpp similarity index 83% rename from include/mrdocs/Metadata/EnumConstant.hpp rename to include/mrdocs/Metadata/Info/EnumConstant.hpp index 85eba8cf64..8a24bd25ba 100644 --- a/include/mrdocs/Metadata/EnumConstant.hpp +++ b/include/mrdocs/Metadata/Info/EnumConstant.hpp @@ -11,19 +11,15 @@ #ifndef MRDOCS_API_METADATA_ENUMCONSTANT_HPP #define MRDOCS_API_METADATA_ENUMCONSTANT_HPP -#include #include #include #include -#include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Info for enum constants. */ -struct EnumConstantInfo +struct EnumConstantInfo final : InfoCommonBase , SourceInfo { @@ -39,7 +35,6 @@ struct EnumConstantInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Field.hpp b/include/mrdocs/Metadata/Info/Field.hpp similarity index 91% rename from include/mrdocs/Metadata/Field.hpp rename to include/mrdocs/Metadata/Info/Field.hpp index c03c019fd0..946aa5789c 100644 --- a/include/mrdocs/Metadata/Field.hpp +++ b/include/mrdocs/Metadata/Info/Field.hpp @@ -14,26 +14,23 @@ #ifndef MRDOCS_API_METADATA_FIELD_HPP #define MRDOCS_API_METADATA_FIELD_HPP -#include #include #include #include #include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Info for fields (i.e. non-static data members) Non-static data members cannot be redeclared. */ -struct FieldInfo +struct FieldInfo final : InfoCommonBase , SourceInfo { /** Type of the field */ - std::unique_ptr Type; + PolymorphicValue Type; /** The default member initializer, if any. */ @@ -69,7 +66,6 @@ struct FieldInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Friend.hpp b/include/mrdocs/Metadata/Info/Friend.hpp similarity index 83% rename from include/mrdocs/Metadata/Friend.hpp rename to include/mrdocs/Metadata/Info/Friend.hpp index bd4944d7db..926e78bcfb 100644 --- a/include/mrdocs/Metadata/Friend.hpp +++ b/include/mrdocs/Metadata/Info/Friend.hpp @@ -11,18 +11,15 @@ #ifndef MRDOCS_API_METADATA_FRIEND_HPP #define MRDOCS_API_METADATA_FRIEND_HPP -#include #include #include #include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Info for friend declarations. */ -struct FriendInfo +struct FriendInfo final : InfoCommonBase , SourceInfo { @@ -32,7 +29,7 @@ struct FriendInfo /** Befriended type. */ - std::unique_ptr FriendType; + PolymorphicValue FriendType; //-------------------------------------------- @@ -42,7 +39,6 @@ struct FriendInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Function.hpp b/include/mrdocs/Metadata/Info/Function.hpp similarity index 88% rename from include/mrdocs/Metadata/Function.hpp rename to include/mrdocs/Metadata/Info/Function.hpp index 9638f03a9a..9b21eae445 100644 --- a/include/mrdocs/Metadata/Function.hpp +++ b/include/mrdocs/Metadata/Info/Function.hpp @@ -15,20 +15,21 @@ #define MRDOCS_API_METADATA_FUNCTION_HPP #include -#include +#include +#include +#include #include -#include #include -#include +#include #include #include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Return the name of an operator as a string. + @param kind The kind of operator. @param include_keyword Whether the name should be prefixed with the `operator` keyword. */ @@ -47,6 +48,7 @@ getShortOperatorName( /** Return the safe name of an operator as a string. + @param kind The kind of operator. @param include_keyword Whether the name should be prefixed with `operator_`. */ @@ -75,7 +77,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - FunctionClass kind) + FunctionClass const kind) { v = toString(kind); } @@ -87,7 +89,7 @@ tag_invoke( struct Param { /** The type of this parameter */ - std::unique_ptr Type; + PolymorphicValue Type; /** The parameter name. @@ -101,14 +103,13 @@ struct Param Param() = default; Param( - std::unique_ptr&& type, + PolymorphicValue&& type, std::string&& name, std::string&& def_arg) : Type(std::move(type)) , Name(std::move(name)) , Default(std::move(def_arg)) - { - } + {} }; /** Return the Param as a @ref dom::Value object. @@ -123,12 +124,12 @@ tag_invoke( // TODO: Expand to allow for documenting templating and default args. // Info for functions. -struct FunctionInfo +struct FunctionInfo final : InfoCommonBase , SourceInfo { /// Info about the return type of this function. - std::unique_ptr ReturnType; + PolymorphicValue ReturnType; /// List of parameters. std::vector Params; @@ -171,7 +172,7 @@ struct FunctionInfo //-------------------------------------------- - explicit FunctionInfo(SymbolID ID) noexcept + explicit FunctionInfo(SymbolID const& ID) noexcept : InfoCommonBase(ID) { } @@ -179,7 +180,6 @@ struct FunctionInfo //------------------------------------------------ -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Guide.hpp b/include/mrdocs/Metadata/Info/Guide.hpp similarity index 83% rename from include/mrdocs/Metadata/Guide.hpp rename to include/mrdocs/Metadata/Info/Guide.hpp index 9c616d70ac..ba2b779916 100644 --- a/include/mrdocs/Metadata/Guide.hpp +++ b/include/mrdocs/Metadata/Info/Guide.hpp @@ -11,22 +11,17 @@ #ifndef MRDOCS_API_METADATA_GUIDE_HPP #define MRDOCS_API_METADATA_GUIDE_HPP -#include -#include #include #include #include #include -#include -#include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Info for deduction guides. */ -struct GuideInfo +struct GuideInfo final : InfoCommonBase , SourceInfo { @@ -34,7 +29,7 @@ struct GuideInfo This is always a SpecializationTypeInfo. */ - std::unique_ptr Deduced; + PolymorphicValue Deduced; /** Template head, if any. */ @@ -56,7 +51,6 @@ struct GuideInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Namespace.hpp b/include/mrdocs/Metadata/Info/Namespace.hpp similarity index 86% rename from include/mrdocs/Metadata/Namespace.hpp rename to include/mrdocs/Metadata/Info/Namespace.hpp index eab6b870ee..d6402ce176 100644 --- a/include/mrdocs/Metadata/Namespace.hpp +++ b/include/mrdocs/Metadata/Info/Namespace.hpp @@ -12,17 +12,15 @@ #ifndef MRDOCS_API_METADATA_NAMESPACE_HPP #define MRDOCS_API_METADATA_NAMESPACE_HPP -#include -#include -#include #include +#include +#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Describes a namespace. */ -struct NamespaceInfo +struct NamespaceInfo final : InfoCommonBase , ScopeInfo { @@ -41,7 +39,6 @@ struct NamespaceInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/NamespaceAlias.hpp b/include/mrdocs/Metadata/Info/NamespaceAlias.hpp similarity index 73% rename from include/mrdocs/Metadata/NamespaceAlias.hpp rename to include/mrdocs/Metadata/Info/NamespaceAlias.hpp index e11ebd6910..8d0e20a59a 100644 --- a/include/mrdocs/Metadata/NamespaceAlias.hpp +++ b/include/mrdocs/Metadata/Info/NamespaceAlias.hpp @@ -11,33 +11,28 @@ #ifndef MRDOCS_API_METADATA_NAMESPACEALIAS_HPP #define MRDOCS_API_METADATA_NAMESPACEALIAS_HPP -#include #include #include -#include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Info for namespace aliases. */ -struct NamespaceAliasInfo +struct NamespaceAliasInfo final : InfoCommonBase , SourceInfo { /** The aliased symbol. */ - std::unique_ptr AliasedSymbol; + PolymorphicValue AliasedSymbol; //-------------------------------------------- - explicit NamespaceAliasInfo(SymbolID ID) noexcept + explicit NamespaceAliasInfo(SymbolID const &ID) noexcept : InfoCommonBase(ID) { } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Overloads.hpp b/include/mrdocs/Metadata/Info/Overloads.hpp similarity index 93% rename from include/mrdocs/Metadata/Overloads.hpp rename to include/mrdocs/Metadata/Info/Overloads.hpp index 553d7344d0..9994a1fc72 100644 --- a/include/mrdocs/Metadata/Overloads.hpp +++ b/include/mrdocs/Metadata/Info/Overloads.hpp @@ -11,14 +11,10 @@ #ifndef MRDOCS_API_METADATA_OVERLOADS_HPP #define MRDOCS_API_METADATA_OVERLOADS_HPP -#include -#include -#include #include -#include +#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Represents a set of function overloads. @@ -88,7 +84,6 @@ tag_invoke( OverloadSet const& overloads, DomCorpus const* domCorpus); -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Record.hpp b/include/mrdocs/Metadata/Info/Record.hpp similarity index 86% rename from include/mrdocs/Metadata/Record.hpp rename to include/mrdocs/Metadata/Info/Record.hpp index 362f261c7c..0c6058471d 100644 --- a/include/mrdocs/Metadata/Record.hpp +++ b/include/mrdocs/Metadata/Info/Record.hpp @@ -12,34 +12,31 @@ #ifndef MRDOCS_API_METADATA_RECORD_HPP #define MRDOCS_API_METADATA_RECORD_HPP -#include +#include +#include #include -#include +#include #include #include -#include -#include -#include -#include #include +#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Metadata for a direct base. */ struct BaseInfo { - std::unique_ptr Type; + PolymorphicValue Type; AccessKind Access = AccessKind::Public; bool IsVirtual = false; BaseInfo() = default; BaseInfo( - std::unique_ptr&& type, - AccessKind access, - bool is_virtual) + PolymorphicValue&& type, + AccessKind const access, + bool const is_virtual) : Type(std::move(type)) , Access(access) , IsVirtual(is_virtual) @@ -76,7 +73,7 @@ tag_invoke( /** Metadata for struct, class, or union. */ -struct RecordInfo +struct RecordInfo final : InfoCommonBase , SourceInfo , ScopeInfo @@ -104,7 +101,7 @@ struct RecordInfo //-------------------------------------------- - explicit RecordInfo(SymbolID ID) noexcept + explicit RecordInfo(SymbolID const& ID) noexcept : InfoCommonBase(ID) { } @@ -127,8 +124,6 @@ getDefaultAccessString( } } - -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Scope.hpp b/include/mrdocs/Metadata/Info/Scope.hpp similarity index 97% rename from include/mrdocs/Metadata/Scope.hpp rename to include/mrdocs/Metadata/Info/Scope.hpp index 7b6de6acbb..04716c399f 100644 --- a/include/mrdocs/Metadata/Scope.hpp +++ b/include/mrdocs/Metadata/Info/Scope.hpp @@ -12,12 +12,10 @@ #ifndef MRDOCS_API_METADATA_SCOPE_HPP #define MRDOCS_API_METADATA_SCOPE_HPP -#include #include -#include -#include #include #include +#include namespace clang::mrdocs { diff --git a/include/mrdocs/Metadata/Specialization.hpp b/include/mrdocs/Metadata/Info/Specialization.hpp similarity index 77% rename from include/mrdocs/Metadata/Specialization.hpp rename to include/mrdocs/Metadata/Info/Specialization.hpp index e79630bc0f..c1c5fdf8c8 100644 --- a/include/mrdocs/Metadata/Specialization.hpp +++ b/include/mrdocs/Metadata/Info/Specialization.hpp @@ -11,23 +11,19 @@ #ifndef MRDOCS_API_METADATA_SPECIALIZATION_HPP #define MRDOCS_API_METADATA_SPECIALIZATION_HPP -#include -#include -#include -#include +#include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Specialization info for members of implicit instantiations */ -struct SpecializationInfo +struct SpecializationInfo final : InfoCommonBase , ScopeInfo { /** The template arguments the parent template is specialized for */ - std::vector> Args; + std::vector> Args; /** ID of the template to which the arguments pertain */ SymbolID Primary = SymbolID::invalid; @@ -38,7 +34,6 @@ struct SpecializationInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Typedef.hpp b/include/mrdocs/Metadata/Info/Typedef.hpp similarity index 87% rename from include/mrdocs/Metadata/Typedef.hpp rename to include/mrdocs/Metadata/Info/Typedef.hpp index 03ca1c3844..84684036a2 100644 --- a/include/mrdocs/Metadata/Typedef.hpp +++ b/include/mrdocs/Metadata/Info/Typedef.hpp @@ -13,21 +13,18 @@ #ifndef MRDOCS_API_METADATA_TYPEDEF_HPP #define MRDOCS_API_METADATA_TYPEDEF_HPP -#include #include #include #include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { // Info for typedef and using statements. -struct TypedefInfo +struct TypedefInfo final : InfoCommonBase , SourceInfo { - std::unique_ptr Type; + PolymorphicValue Type; // Indicates if this is a new C++ "using"-style typedef: // using MyVector = std::vector @@ -45,7 +42,6 @@ struct TypedefInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Variable.hpp b/include/mrdocs/Metadata/Info/Variable.hpp similarity index 85% rename from include/mrdocs/Metadata/Variable.hpp rename to include/mrdocs/Metadata/Info/Variable.hpp index af0f21c627..b4b3486d54 100644 --- a/include/mrdocs/Metadata/Variable.hpp +++ b/include/mrdocs/Metadata/Info/Variable.hpp @@ -12,27 +12,24 @@ #ifndef MRDOCS_API_METADATA_VARIABLE_HPP #define MRDOCS_API_METADATA_VARIABLE_HPP -#include #include #include #include #include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** A variable. This includes variables at namespace scope, and static variables at class scope. */ -struct VariableInfo +struct VariableInfo final : InfoCommonBase , SourceInfo { /** The type of the variable */ - std::unique_ptr Type; + PolymorphicValue Type; std::optional Template; @@ -52,13 +49,12 @@ struct VariableInfo //-------------------------------------------- - explicit VariableInfo(SymbolID ID) noexcept + explicit VariableInfo(SymbolID const &ID) noexcept : InfoCommonBase(ID) { } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Interface.hpp b/include/mrdocs/Metadata/Interface.hpp index fd6b31c114..73c85efa67 100644 --- a/include/mrdocs/Metadata/Interface.hpp +++ b/include/mrdocs/Metadata/Interface.hpp @@ -12,16 +12,12 @@ #ifndef MRDOCS_API_METADATA_INTERFACE_HPP #define MRDOCS_API_METADATA_INTERFACE_HPP -#include -#include -#include #include -#include -#include #include +#include +#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** A group of children that have the same access specifier. @@ -58,8 +54,7 @@ struct Tranche @return The tranche. - @param Derived The namespace to build the tranche for. - + @param Namespace The namespace to build the tranche for. @param corpus The complete metadata. */ MRDOCS_DECL @@ -146,9 +141,6 @@ class Interface @return The interface. @param I The interface to store the results in. - - @param Derived The most derived record to start from. - @param corpus The complete metadata. */ MRDOCS_DECL @@ -167,7 +159,6 @@ tag_invoke( std::shared_ptr const& sp, DomCorpus const* domCorpus); -} // mrdocs -} // clang +} // mrdocs::clang #endif diff --git a/include/mrdocs/Metadata/Javadoc.hpp b/include/mrdocs/Metadata/Javadoc.hpp index 4f63407485..506ff38fd0 100644 --- a/include/mrdocs/Metadata/Javadoc.hpp +++ b/include/mrdocs/Metadata/Javadoc.hpp @@ -14,18 +14,17 @@ #define MRDOCS_API_METADATA_JAVADOC_HPP #include -#include #include -#include #include +#include +#include #include #include #include #include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Javadoc related types and functions. @@ -54,13 +53,7 @@ namespace doc { struct Node; -using String = std::string; - -template -requires std::derived_from -using List = std::vector>; - -/** The kind of a node. +/** The kind of node. This includes tags and block types. @@ -226,13 +219,13 @@ struct MRDOCS_DECL */ struct Text : Node { - String string; + std::string string; static constexpr Kind static_kind = Kind::text; explicit Text( - String string_ = String()) noexcept + std::string string_ = std::string()) noexcept : Node(Kind::text) , string(std::move(string_)) { @@ -247,12 +240,12 @@ struct Text : Node bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } protected: Text( - String string_, + std::string string_, Kind kind_) : Node(kind_) , string(std::move(string_)) @@ -262,14 +255,14 @@ struct Text : Node /** A piece of styled text. */ -struct Styled : Text +struct Styled final : Text { Style style; static constexpr Kind static_kind = Kind::styled; Styled( - String string_ = String(), + std::string string_ = std::string(), Style style_ = Style::none) noexcept : Text(std::move(string_), Kind::styled) , style(style_) @@ -280,7 +273,7 @@ struct Styled : Text bool equals(Node const& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -289,14 +282,14 @@ struct Styled : Text */ struct Link : Text { - String href; + std::string href; static constexpr Kind static_kind = Kind::link; explicit Link( - String string_ = String(), - String href_ = String()) noexcept + std::string string_ = std::string(), + std::string href_ = std::string()) noexcept : Text(std::move(string_), Kind::link) , href(std::move(href_)) { @@ -306,7 +299,7 @@ struct Link : Text bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -320,7 +313,7 @@ struct Reference : Text explicit Reference( - String string_ = String()) noexcept + std::string string_ = std::string()) noexcept : Text(std::move(string_), Kind::reference) { } @@ -329,12 +322,12 @@ struct Reference : Text bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } protected: Reference( - String string_, + std::string string_, Kind kind_) noexcept : Text(std::move(string_), kind_) { @@ -350,7 +343,7 @@ struct Copied : Reference static constexpr Kind static_kind = Kind::copied; Copied( - String string_ = String(), + std::string string_ = std::string(), Parts parts_ = Parts::all) noexcept : Reference(std::move(string_), Kind::copied) , parts(parts_) @@ -361,7 +354,7 @@ struct Copied : Reference bool equals(Node const& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -380,7 +373,7 @@ struct Copied : Reference struct MRDOCS_DECL Block : Node { - List children; + std::vector> children; bool isBlock() const noexcept final { @@ -409,7 +402,7 @@ struct MRDOCS_DECL bool equals(Node const& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } template T> @@ -419,22 +412,22 @@ struct MRDOCS_DECL std::make_unique(std::forward(text)))); } - void append(List&& blocks); + void append(std::vector>&& blocks); - void append(List const& otherChildren); + void append(std::vector> const& otherChildren); protected: explicit Block( Kind kind_, - List children_ = {}) noexcept + std::vector> children_ = {}) noexcept : Node(kind_) , children(std::move(children_)) { } private: - Text& emplace_back(std::unique_ptr text); + Text& emplace_back(PolymorphicValue text); }; /** A manually specified section heading. @@ -443,10 +436,10 @@ struct Heading : Block { static constexpr Kind static_kind = Kind::heading; - String string; + std::string string; Heading( - String string_ = String()) noexcept + std::string string_ = std::string()) noexcept : Block(Kind::heading) , string(std::move(string_)) { @@ -475,14 +468,14 @@ struct Paragraph : Block bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } protected: explicit Paragraph( Kind kind, - List children_ = {}) noexcept + std::vector> children_ = {}) noexcept : Block(kind, std::move(children_)) { } @@ -557,67 +550,90 @@ struct Code : Paragraph /** An item in a list */ -struct ListItem : Paragraph +struct ListItem final : Paragraph { - static constexpr Kind static_kind = Kind::list_item; + static constexpr auto static_kind = Kind::list_item; ListItem() : Paragraph(Kind::list_item) - { - } + {} - bool operator==(const ListItem&) - const noexcept = default; + bool + operator==(const ListItem&) const noexcept = default; - bool equals(const Node& other) const noexcept override + bool + equals(const Node& other) const noexcept override { - return kind == other.kind && - *this == dynamic_cast(other); + auto* p = dynamic_cast(&other); + if (!p) + { + return false; + } + if (this == &other) + { + return true; + } + return *this == *p; } }; /** A list of list items */ -struct UnorderedList : Paragraph +struct UnorderedList final : Paragraph { - static constexpr Kind static_kind = Kind::unordered_list; + static constexpr auto static_kind = Kind::unordered_list; - // Vector of list items - List items; + std::vector items; UnorderedList() : Paragraph(Kind::unordered_list) { } - bool operator==(const UnorderedList&) - const noexcept = default; + bool + operator==(const UnorderedList&) const noexcept = default; - bool equals(const Node& other) const noexcept override + bool + equals(const Node& other) const noexcept override { - return kind == other.kind && - *this == dynamic_cast(other); + auto* p = dynamic_cast(&other); + if (!p) + { + return false; + } + if (this == &other) + { + return true; + } + return *this == *p; } }; /** A @details paragraph */ -struct Details : Paragraph +struct Details final : Paragraph { - static constexpr Kind static_kind = Kind::details; + static constexpr auto static_kind = Kind::details; Details() : Paragraph(Kind::details) - { - } + {} - bool operator==(const Details&) - const noexcept = default; + bool + operator==(const Details&) const noexcept = default; bool equals(const Node& other) const noexcept override { - return kind == other.kind && - *this == static_cast(other); + auto* p = dynamic_cast(&other); + if (!p) + { + return false; + } + if (this == &other) + { + return true; + } + return *this == *p; } }; @@ -638,7 +654,7 @@ struct See : Paragraph bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -646,13 +662,13 @@ struct See : Paragraph */ struct Param : Paragraph { - String name; + std::string name; ParamDirection direction; static constexpr Kind static_kind = Kind::param; Param( - String name_ = String(), + std::string name_ = std::string(), Paragraph details_ = Paragraph(), ParamDirection direction_ = ParamDirection::none) : Paragraph( @@ -669,7 +685,7 @@ struct Param : Paragraph bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -691,7 +707,7 @@ struct Returns : Paragraph bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -699,7 +715,7 @@ struct Returns : Paragraph */ struct TParam : Paragraph { - String name; + std::string name; static constexpr Kind static_kind = Kind::tparam; @@ -712,7 +728,7 @@ struct TParam : Paragraph bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -725,7 +741,7 @@ struct Throws : Paragraph static constexpr Kind static_kind = Kind::throws; Throws( - String exception_ = String(), + std::string exception_ = std::string(), Paragraph details_ = Paragraph()) : Paragraph( Kind::throws, @@ -740,7 +756,7 @@ struct Throws : Paragraph bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -762,7 +778,7 @@ struct Precondition : Paragraph bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -784,7 +800,7 @@ struct Postcondition : Paragraph bool equals(const Node& other) const noexcept override { return kind == other.kind && - *this == static_cast(other); + *this == dynamic_cast(other); } }; @@ -849,7 +865,7 @@ visit( /** Visit a node. @param node The node to visit. - @param f The function to call for each node. + @param fn The function to call for each node. @param args Additional arguments to pass to the function. */ template< @@ -944,7 +960,9 @@ struct Overview std::vector postconditions; }; -MRDOCS_DECL dom::String toString(Style style) noexcept; +MRDOCS_DECL +dom::String +toString(Style style) noexcept; } // doc @@ -957,7 +975,7 @@ class Corpus; struct MRDOCS_DECL Javadoc { - doc::List blocks_; + std::vector> blocks_; /** Constructor. */ @@ -968,7 +986,7 @@ struct MRDOCS_DECL */ explicit Javadoc( - doc::List blocks); + std::vector> blocks); /** Return true if this is empty */ @@ -983,12 +1001,12 @@ struct MRDOCS_DECL doc::Paragraph const* getBrief(Corpus const& corpus) const noexcept; - doc::List const& + std::vector> const& getDescription(Corpus const& corpus) const noexcept; /** Return the list of top level blocks. */ - doc::List const& + std::vector> const& getBlocks() const noexcept { return blocks_; @@ -996,7 +1014,7 @@ struct MRDOCS_DECL // VFALCO This is unfortunately necessary for // the deserialization from bitcode... - doc::List& + std::vector>& getBlocks() noexcept { return blocks_; @@ -1044,7 +1062,7 @@ struct MRDOCS_DECL std::string emplace_back(T&& block) { - return emplace_back(std::make_unique(std::forward(block))); + return emplace_back(MakePolymorphicValue(std::forward(block))); } /** Append blocks from another javadoc to this. @@ -1053,10 +1071,12 @@ struct MRDOCS_DECL /** Append blocks from a list to this. */ - void append(doc::List&& blocks); + void + append(std::vector>&& blocks); private: - std::string emplace_back(std::unique_ptr); + std::string + emplace_back(PolymorphicValue); }; /** Return the Javadoc as a @ref dom::Value. @@ -1069,7 +1089,6 @@ tag_invoke( Javadoc const& I, DomCorpus const* domCorpus); -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Name.hpp b/include/mrdocs/Metadata/Name.hpp index b18f81651d..68e2d06780 100644 --- a/include/mrdocs/Metadata/Name.hpp +++ b/include/mrdocs/Metadata/Name.hpp @@ -47,6 +47,12 @@ tag_invoke( It also includes the symbol ID of the named type, so that it can be referenced in the documentation. + + This allows the `TypeInfo` to store either a + `NameInfo` or a `SpecializationNameInfo`, + which contains the arguments for a template specialization + without requiring the application to extract an + unnecessary symbol. */ struct NameInfo { @@ -76,7 +82,7 @@ struct NameInfo and the template arguments. */ - std::unique_ptr Prefix; + PolymorphicValue Prefix; constexpr bool isIdentifier() const noexcept { return Kind == NameKind::Identifier; } constexpr bool isSpecialization() const noexcept { return Kind == NameKind::Specialization; } @@ -87,32 +93,46 @@ struct NameInfo explicit constexpr - NameInfo(NameKind kind) noexcept + NameInfo(NameKind const kind) noexcept : Kind(kind) {} - virtual ~NameInfo() = default; + constexpr virtual ~NameInfo() = default; + + std::strong_ordering + operator<=>(NameInfo const& other) const; }; /** Represents a (possibly qualified) symbol name with template arguments. */ -struct SpecializationNameInfo +struct SpecializationNameInfo final : NameInfo { /** The template arguments. */ - std::vector> TemplateArgs; + std::vector> TemplateArgs; constexpr SpecializationNameInfo() noexcept : NameInfo(NameKind::Specialization) {} + + auto + operator<=>(SpecializationNameInfo const& other) const + { + if (auto const r = + dynamic_cast(*this) <=> dynamic_cast(other); + !std::is_eq(r)) + { + return r; + } + return TemplateArgs <=> other.TemplateArgs; + } }; template< - class NameInfoTy, + std::derived_from NameInfoTy, class Fn, class... Args> - requires std::derived_from decltype(auto) visit( NameInfoTy& info, @@ -120,8 +140,7 @@ visit( Args&&... args) { auto visitor = makeVisitor( - info, std::forward(fn), - std::forward(args)...); + info, std::forward(fn), std::forward(args)...); switch(info.Kind) { case NameKind::Identifier: @@ -133,6 +152,19 @@ visit( } } +inline +std::strong_ordering +operator<=>(PolymorphicValue const& lhs, PolymorphicValue const& rhs) +{ + return CompareDerived(lhs, rhs); +} + +inline +bool +operator==(PolymorphicValue const& lhs, PolymorphicValue const& rhs) { + return lhs <=> rhs == std::strong_ordering::equal; +} + MRDOCS_DECL std::string toString(const NameInfo& N); @@ -150,7 +182,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - std::unique_ptr const& I, + PolymorphicValue const& I, DomCorpus const* domCorpus) { if(! I) diff --git a/include/mrdocs/Metadata/Source.hpp b/include/mrdocs/Metadata/Source.hpp index b331958e1e..27b6f4fa46 100644 --- a/include/mrdocs/Metadata/Source.hpp +++ b/include/mrdocs/Metadata/Source.hpp @@ -17,10 +17,8 @@ #include #include #include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { enum class FileKind { @@ -126,6 +124,8 @@ struct MRDOCS_DECL */ std::vector Loc; + constexpr virtual ~SourceInfo() = default; + protected: SourceInfo() = default; }; @@ -136,7 +136,6 @@ tag_invoke( dom::Value& v, SourceInfo const& I); -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Specifiers.hpp b/include/mrdocs/Metadata/Specifiers.hpp index f85640929d..01c00bac80 100644 --- a/include/mrdocs/Metadata/Specifiers.hpp +++ b/include/mrdocs/Metadata/Specifiers.hpp @@ -14,10 +14,8 @@ #include #include #include -#include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Access specifier. @@ -111,6 +109,8 @@ struct NoexceptInfo /** The operand of the noexcept-specifier, if any. */ std::string Operand; + + auto operator<=>(NoexceptInfo const&) const = default; }; /** Operator kinds @@ -237,9 +237,9 @@ tag_invoke( /** Convert ExplicitInfo to a string. + @param info The explicit-specifier information. @param resolved If true, the operand is not shown when the explicit-specifier is non-dependent. - @param implicit If true, implicit explicit-specifiers are shown. */ MRDOCS_DECL @@ -268,7 +268,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - AccessKind kind) + AccessKind const kind) { v = toString(kind); } @@ -280,7 +280,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - ConstexprKind kind) + ConstexprKind const kind) { v = toString(kind); } @@ -292,7 +292,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - StorageClassKind kind) + StorageClassKind const kind) { v = toString(kind); } @@ -309,7 +309,6 @@ tag_invoke( v = toString(kind); } -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Symbols.hpp b/include/mrdocs/Metadata/Symbols.hpp index d711d9dc18..2f1088cef5 100644 --- a/include/mrdocs/Metadata/Symbols.hpp +++ b/include/mrdocs/Metadata/Symbols.hpp @@ -22,16 +22,12 @@ #include namespace clang::mrdocs { - class DomCorpus; - namespace dom { - struct ValueFromTag; - class Value; - } +class DomCorpus; +namespace dom { + struct ValueFromTag; + class Value; } -namespace clang { -namespace mrdocs { - /** A unique identifier for a symbol. This is calculated as the SHA1 digest of the @@ -189,14 +185,13 @@ tag_invoke( std::unique_ptr const& t, DomCorpus const* domCorpus); -} // mrdocs -} // clang +} // clang::mrdocs template<> struct std::hash { - std::size_t operator()( - const clang::mrdocs::SymbolID& id) const + std::size_t + operator()(const clang::mrdocs::SymbolID& id) const noexcept { return std::hash()( std::string_view(id)); diff --git a/include/mrdocs/Metadata/Template.hpp b/include/mrdocs/Metadata/Template.hpp index 4126ba558a..ce4e372180 100644 --- a/include/mrdocs/Metadata/Template.hpp +++ b/include/mrdocs/Metadata/Template.hpp @@ -21,8 +21,10 @@ #include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { + +std::strong_ordering +operator<=>(PolymorphicValue const& lhs, PolymorphicValue const& rhs); enum class TArgKind : int { @@ -60,6 +62,8 @@ struct TArg constexpr bool isNonType() const noexcept { return Kind == TArgKind::NonType; } constexpr bool isTemplate() const noexcept { return Kind == TArgKind::Template; } + auto operator<=>(TArg const&) const = default; + protected: constexpr TArg( @@ -86,21 +90,26 @@ struct IsTArg : TArg } }; -struct TypeTArg +struct TypeTArg final : IsTArg { /** Template argument type. */ - std::unique_ptr Type; + PolymorphicValue Type; + + auto operator<=>(TypeTArg const&) const = default; }; -struct NonTypeTArg + +struct NonTypeTArg final : IsTArg { /** Template argument expression. */ ExprInfo Value; + + auto operator<=>(NonTypeTArg const&) const = default; }; -struct TemplateTArg +struct TemplateTArg final : IsTArg { /** SymbolID of the referenced template. */ @@ -108,13 +117,14 @@ struct TemplateTArg /** Name of the referenced template. */ std::string Name; + + auto operator<=>(TemplateTArg const&) const = default; }; template< - typename TArgTy, - typename F, - typename... Args> - requires std::derived_from + std::derived_from TArgTy, + class F, + class... Args> constexpr decltype(auto) visit( @@ -141,7 +151,22 @@ visit( } } -MRDOCS_DECL std::string toString(const TArg& arg) noexcept; +inline +std::strong_ordering +operator<=>(PolymorphicValue const& lhs, PolymorphicValue const& rhs) +{ + return CompareDerived(lhs, rhs); +} + +inline +bool +operator==(PolymorphicValue const& lhs, PolymorphicValue const& rhs) { + return lhs <=> rhs == std::strong_ordering::equal; +} + +MRDOCS_DECL +std::string +toString(const TArg& arg) noexcept; MRDOCS_DECL void @@ -156,7 +181,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - std::unique_ptr const& I, + PolymorphicValue const& I, DomCorpus const* domCorpus) { if (!I) @@ -193,14 +218,16 @@ struct TParam bool IsParameterPack = false; /** The default template argument, if any */ - std::unique_ptr Default; + PolymorphicValue Default; - virtual ~TParam() = default; + constexpr virtual ~TParam() = default; constexpr bool isType() const noexcept { return Kind == TParamKind::Type; } constexpr bool isNonType() const noexcept { return Kind == TParamKind::NonType; } constexpr bool isTemplate() const noexcept { return Kind == TParamKind::Template; } + auto operator<=>(TParam const&) const = default; + protected: constexpr TParam( @@ -222,7 +249,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - std::unique_ptr const& I, + PolymorphicValue const& I, DomCorpus const* domCorpus) { if (!I) @@ -243,6 +270,8 @@ struct TParamCommonBase : TParam static constexpr bool isNonType() noexcept { return K == TParamKind::NonType; } static constexpr bool isTemplate() noexcept { return K == TParamKind::Template; } + auto operator<=>(TParamCommonBase const&) const = default; + protected: constexpr TParamCommonBase() noexcept @@ -270,28 +299,50 @@ tag_invoke( v = toString(kind); } -struct TypeTParam +struct TypeTParam final : TParamCommonBase { /** Keyword (class/typename) the parameter uses */ TParamKeyKind KeyKind = TParamKeyKind::Class; /** The type-constraint for the parameter, if any. */ - std::unique_ptr Constraint; + PolymorphicValue Constraint; + + auto operator<=>(TypeTParam const&) const = default; }; -struct NonTypeTParam +struct NonTypeTParam final : TParamCommonBase { /** Type of the non-type template parameter */ - std::unique_ptr Type; + PolymorphicValue Type; + + auto operator<=>(NonTypeTParam const&) const = default; }; -struct TemplateTParam +struct TemplateTParam final : TParamCommonBase { - /** Template parameters for the template template parameter */ - std::vector> Params; + /** Template parameters for the template-template parameter */ + std::vector> Params; + + auto operator<=>(TemplateTParam const& other) const + { + if (auto const r = Params.size() <=> other.Params.size(); + !std::is_eq(r)) + { + return r; + } + for (std::size_t i = 0; i < Params.size(); ++i) + { + if (auto const r = Params[i] <=> other.Params[i]; + !std::is_eq(r)) + { + return r; + } + } + return std::strong_ordering::equal; + } }; template< @@ -325,6 +376,20 @@ visit( } } +inline +std::strong_ordering +operator<=>(PolymorphicValue const& lhs, PolymorphicValue const& rhs) +{ + return CompareDerived(lhs, rhs); +} + +inline +bool +operator==(PolymorphicValue const& lhs, PolymorphicValue const& rhs) { + return lhs <=> rhs == std::strong_ordering::equal; +} + + // ---------------------------------------------------------------- enum class TemplateSpecKind @@ -342,8 +407,8 @@ toString(TemplateSpecKind kind); */ struct TemplateInfo { - std::vector> Params; - std::vector> Args; + std::vector> Params; + std::vector> Args; /** The requires-clause for the template parameter list, if any. */ @@ -395,7 +460,6 @@ tag_invoke( tag_invoke(dom::ValueFromTag{}, v, *I, domCorpus); } -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Type.hpp b/include/mrdocs/Metadata/Type.hpp index 7321b8f074..5973443bd3 100644 --- a/include/mrdocs/Metadata/Type.hpp +++ b/include/mrdocs/Metadata/Type.hpp @@ -11,20 +11,25 @@ #ifndef MRDOCS_API_METADATA_TYPE_HPP #define MRDOCS_API_METADATA_TYPE_HPP -#include +#include +#include +#include #include #include #include #include #include +#include #include -#include -#include -#include -#include namespace clang::mrdocs { +std::strong_ordering +operator<=>(PolymorphicValue const& lhs, PolymorphicValue const& rhs); + +std::strong_ordering +operator<=>(PolymorphicValue const& lhs, PolymorphicValue const& rhs); + enum QualifierKind { None, @@ -137,16 +142,25 @@ struct TypeInfo */ virtual TypeInfo* - innerType() const noexcept + innerType() noexcept { return nullptr; } + virtual + TypeInfo const* + cInnerType() const noexcept + { + return const_cast(this)->innerType(); + } + /** Return the symbol named by this type. */ SymbolID namedSymbol() const noexcept; + auto operator<=>(TypeInfo const&) const = default; + protected: constexpr TypeInfo( @@ -169,7 +183,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - std::unique_ptr const& I, + PolymorphicValue const& I, DomCorpus const* domCorpus) { if (!I) @@ -195,6 +209,8 @@ struct TypeInfoCommonBase : TypeInfo static constexpr bool isArray() noexcept { return K == TypeKind::Array; } static constexpr bool isFunction() noexcept { return K == TypeKind::Function; } + auto operator<=>(TypeInfoCommonBase const&) const = default; + protected: constexpr TypeInfoCommonBase() noexcept @@ -203,108 +219,160 @@ struct TypeInfoCommonBase : TypeInfo } }; -struct NamedTypeInfo +struct NamedTypeInfo final : TypeInfoCommonBase { QualifierKind CVQualifiers = QualifierKind::None; - std::unique_ptr Name; + PolymorphicValue Name; + + std::strong_ordering + operator<=>(NamedTypeInfo const& other) const; }; -struct DecltypeTypeInfo +struct DecltypeTypeInfo final : TypeInfoCommonBase { QualifierKind CVQualifiers = QualifierKind::None; ExprInfo Operand; + + auto operator<=>(DecltypeTypeInfo const&) const = default; }; -struct AutoTypeInfo +struct AutoTypeInfo final : TypeInfoCommonBase { QualifierKind CVQualifiers = QualifierKind::None; AutoKind Keyword = AutoKind::Auto; - std::unique_ptr Constraint; + PolymorphicValue Constraint; + + auto operator<=>(AutoTypeInfo const&) const = default; }; -struct LValueReferenceTypeInfo +struct LValueReferenceTypeInfo final : TypeInfoCommonBase { - std::unique_ptr PointeeType; + PolymorphicValue PointeeType; - TypeInfo* innerType() const noexcept override + TypeInfo* + innerType() noexcept override { - return PointeeType.get(); + return PointeeType.operator->(); } + + auto operator<=>(LValueReferenceTypeInfo const&) const = default; }; -struct RValueReferenceTypeInfo +struct RValueReferenceTypeInfo final : TypeInfoCommonBase { - std::unique_ptr PointeeType; + PolymorphicValue PointeeType; - TypeInfo* innerType() const noexcept override + TypeInfo* + innerType() noexcept override { - return PointeeType.get(); + return PointeeType.operator->(); } + + auto operator<=>(RValueReferenceTypeInfo const&) const = default; }; -struct PointerTypeInfo +struct PointerTypeInfo final : TypeInfoCommonBase { QualifierKind CVQualifiers = QualifierKind::None; - std::unique_ptr PointeeType; + PolymorphicValue PointeeType; - TypeInfo* innerType() const noexcept override + TypeInfo* + innerType() noexcept override { - return PointeeType.get(); + return PointeeType.operator->(); } + + auto operator<=>(PointerTypeInfo const&) const = default; }; -struct MemberPointerTypeInfo +struct MemberPointerTypeInfo final : TypeInfoCommonBase { QualifierKind CVQualifiers = QualifierKind::None; - std::unique_ptr ParentType; - std::unique_ptr PointeeType; + PolymorphicValue ParentType; + PolymorphicValue PointeeType; - TypeInfo* innerType() const noexcept override + TypeInfo* + innerType() noexcept override { - return PointeeType.get(); + return PointeeType.operator->(); } + + auto operator<=>(MemberPointerTypeInfo const&) const = default; }; -struct ArrayTypeInfo +struct ArrayTypeInfo final : TypeInfoCommonBase { - std::unique_ptr ElementType; + PolymorphicValue ElementType; ConstantExprInfo Bounds; - TypeInfo* innerType() const noexcept override + TypeInfo* + innerType() noexcept override { - return ElementType.get(); + return ElementType.operator->(); } + + auto operator<=>(ArrayTypeInfo const&) const = default; }; -struct FunctionTypeInfo +struct FunctionTypeInfo final : TypeInfoCommonBase { - std::unique_ptr ReturnType; - std::vector> ParamTypes; + PolymorphicValue ReturnType; + std::vector> ParamTypes; QualifierKind CVQualifiers = QualifierKind::None; ReferenceKind RefQualifier = ReferenceKind::None; NoexceptInfo ExceptionSpec; bool IsVariadic = false; - TypeInfo* innerType() const noexcept override + TypeInfo* + innerType() noexcept override { - return ReturnType.get(); + return ReturnType.operator->(); + } + + auto + operator<=>(FunctionTypeInfo const& other) const { + if (auto const r = dynamic_cast(*this) <=> + dynamic_cast(other); + !std::is_eq(r)) + { + return r; + } + if (auto const r = ReturnType <=> other.ReturnType; + !std::is_eq(r)) + { + return r; + } + if (auto const r = ParamTypes.size() <=> other.ParamTypes.size(); + !std::is_eq(r)) + { + return r; + } + for (std::size_t i = 0; i < ParamTypes.size(); ++i) + { + if (auto const r = ParamTypes[i] <=> other.ParamTypes[i]; + !std::is_eq(r)) + { + return r; + } + } + return std::tie(CVQualifiers, RefQualifier, ExceptionSpec, IsVariadic) <=> + std::tie(other.CVQualifiers, other.RefQualifier, other.ExceptionSpec, other.IsVariadic); } }; template< - class TypeTy, + std::derived_from TypeTy, class F, class... Args> - requires std::derived_from decltype(auto) visit( TypeTy& I, @@ -355,6 +423,20 @@ visit( } } +inline +std::strong_ordering +operator<=>(PolymorphicValue const& lhs, PolymorphicValue const& rhs) +{ + return CompareDerived(lhs, rhs); +} + +inline +bool +operator==(PolymorphicValue const& lhs, PolymorphicValue const& rhs) { + return lhs <=> rhs == std::strong_ordering::equal; +} + + // VFALCO maybe we should rename this to `renderType` or something? MRDOCS_DECL std::string @@ -362,7 +444,6 @@ toString( const TypeInfo& T, std::string_view Name = ""); - } // clang::mrdocs #endif diff --git a/include/mrdocs/Metadata/Using.hpp b/include/mrdocs/Metadata/Using.hpp index 7d29e96124..bb3aeaa45b 100644 --- a/include/mrdocs/Metadata/Using.hpp +++ b/include/mrdocs/Metadata/Using.hpp @@ -18,8 +18,7 @@ #include #include -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { enum class UsingClass { @@ -56,7 +55,7 @@ tag_invoke( /** Info for using declarations. */ -struct UsingInfo +struct UsingInfo final : InfoCommonBase, SourceInfo { @@ -70,7 +69,7 @@ struct UsingInfo /** The qualifier for a using declaration. */ - std::unique_ptr Qualifier; + PolymorphicValue Qualifier; //-------------------------------------------- @@ -80,7 +79,6 @@ struct UsingInfo } }; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/MetadataFwd.hpp b/include/mrdocs/MetadataFwd.hpp index e5799250af..5c55014c14 100644 --- a/include/mrdocs/MetadataFwd.hpp +++ b/include/mrdocs/MetadataFwd.hpp @@ -12,14 +12,10 @@ #ifndef MRDOCS_API_METADATAFWD_HPP #define MRDOCS_API_METADATAFWD_HPP -#include -#include - // Forward declarations for all types // related to metadata extracted from AST -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { class Corpus; @@ -73,7 +69,6 @@ struct StaticDataMember; struct OverloadSet; -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/include/mrdocs/mrdocs.natvis b/include/mrdocs/mrdocs.natvis index 08f3e4917e..d63d76b598 100644 --- a/include/mrdocs/mrdocs.natvis +++ b/include/mrdocs/mrdocs.natvis @@ -252,4 +252,15 @@ + + + + *{ptr_} + (empty) + + ptr_ + *ptr_ + + + diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 2ba05ca624..d79731a5e2 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -112,6 +112,7 @@ traverse(DeclTy* D) using R = std::conditional_t< std::same_as, InfoTypeFor_t, + InfoTy>; auto exp = upsert(D); @@ -1216,7 +1217,7 @@ populate( ++it; continue; } - if (auto* T = dynamic_cast(arg.get()); + if (auto* T = dynamic_cast(arg.operator->()); T && T->Type && !T->Type->Constraints.empty()) @@ -1356,10 +1357,11 @@ populate( const Expr* E, const llvm::APInt& V); + void ASTVisitor:: populate( - std::unique_ptr& I, + PolymorphicValue& I, const NamedDecl* N) { visit(N, [&](const DeclTy* P) @@ -1371,9 +1373,9 @@ populate( { if (!I) { - I = std::make_unique(); + I = MakePolymorphicValue(); } - auto* R = dynamic_cast(I.get()); + auto* R = dynamic_cast(I.operator->()); if (P->wasDeclaredWithTypename()) { R->KeyKind = TParamKeyKind::Typename; @@ -1400,9 +1402,9 @@ populate( { if (!I) { - I = std::make_unique(); + I = MakePolymorphicValue(); } - auto* R = dynamic_cast(I.get()); + auto* R = dynamic_cast(I.operator->()); R->Type = toTypeInfo(P->getType()); if (P->hasDefaultArgument() && !R->Default) { @@ -1415,13 +1417,13 @@ populate( { if (!I) { - I = std::make_unique(); + I = MakePolymorphicValue(); } - TemplateTemplateParmDecl const* TTPD = cast(P); + auto const* TTPD = cast(P); MRDOCS_CHECK_OR(TTPD); TemplateParameterList const* TPL = TTPD->getTemplateParameters(); MRDOCS_CHECK_OR(TPL); - auto* Result = dynamic_cast(I.get()); + auto* Result = dynamic_cast(I.operator->()); if (Result->Params.size() < TPL->size()) { Result->Params.resize(TPL->size()); @@ -1481,9 +1483,9 @@ populate( // parameter types we extracted have constraints for (auto it = TI.Params.begin(); it != TI.Params.end(); ) { - std::unique_ptr& param = *it; + PolymorphicValue& param = *it; - if (auto const* T = dynamic_cast(param.get()); + if (auto const* T = dynamic_cast(param.operator->()); T && T->Type && !T->Type->Constraints.empty()) @@ -1503,7 +1505,7 @@ populate( if (param->Default && param->Default->isType()) { - if (auto const* T = dynamic_cast(param->Default.get()); + if (auto const* T = dynamic_cast(param->Default.operator->()); T && T->Type && !T->Type->Constraints.empty()) @@ -1529,7 +1531,7 @@ populate( void ASTVisitor:: populate( - std::vector>& result, + std::vector>& result, const ASTTemplateArgumentListInfo* args) { if (!args) @@ -1660,7 +1662,7 @@ qualifiedName(NamedDecl const* ND) const bool ASTVisitor:: generateJavadoc( - std::unique_ptr& javadoc, + std::optional& javadoc, Decl const* D) { RawComment const* RC = @@ -1673,7 +1675,7 @@ generateJavadoc( return true; } -std::unique_ptr +PolymorphicValue ASTVisitor:: toTypeInfo(QualType const qt, TraversalMode const mode) { @@ -1691,7 +1693,7 @@ toTypeInfo(QualType const qt, TraversalMode const mode) return Builder.result(); } -std::unique_ptr +PolymorphicValue ASTVisitor:: toNameInfo( NestedNameSpecifier const* NNS) @@ -1703,7 +1705,7 @@ toNameInfo( MRDOCS_SYMBOL_TRACE(NNS, context_); ScopeExitRestore scope(mode_, Dependency); - std::unique_ptr I = nullptr; + PolymorphicValue I = nullptr; if (const Type* T = NNS->getAsType()) { NameInfoBuilder Builder(*this, NNS->getPrefix()); @@ -1712,13 +1714,13 @@ toNameInfo( } else if(const IdentifierInfo* II = NNS->getAsIdentifier()) { - I = std::make_unique(); + I = MakePolymorphicValue(); I->Name = II->getName(); I->Prefix = toNameInfo(NNS->getPrefix()); } else if(const NamespaceDecl* ND = NNS->getAsNamespace()) { - I = std::make_unique(); + I = MakePolymorphicValue(); I->Name = ND->getIdentifier()->getName(); I->Prefix = toNameInfo(NNS->getPrefix()); Decl const* ID = getInstantiatedFrom(ND); @@ -1729,7 +1731,7 @@ toNameInfo( } else if(const NamespaceAliasDecl* NAD = NNS->getAsNamespaceAlias()) { - I = std::make_unique(); + I = MakePolymorphicValue(); I->Name = NAD->getIdentifier()->getName(); I->Prefix = toNameInfo(NNS->getPrefix()); Decl const* ID = getInstantiatedFrom(NAD); @@ -1742,7 +1744,7 @@ toNameInfo( } template -std::unique_ptr +PolymorphicValue ASTVisitor:: toNameInfo( DeclarationName const Name, @@ -1753,16 +1755,16 @@ toNameInfo( { return nullptr; } - std::unique_ptr I = nullptr; + PolymorphicValue I = nullptr; if(TArgs) { - auto Specialization = std::make_unique(); + auto Specialization = MakePolymorphicValue(); populate(Specialization->TemplateArgs, *TArgs); - I = std::move(Specialization); + I = PolymorphicValue(std::move(Specialization)); } else { - I = std::make_unique(); + I = MakePolymorphicValue(); } I->Name = extractName(Name); if (NNS) @@ -1773,7 +1775,7 @@ toNameInfo( } template -std::unique_ptr +PolymorphicValue ASTVisitor:: toNameInfo( Decl const* D, @@ -1801,14 +1803,14 @@ toNameInfo( } template -std::unique_ptr +PolymorphicValue ASTVisitor:: toNameInfo>( Decl const* D, std::optional> TArgs, NestedNameSpecifier const* NNS); -std::unique_ptr +PolymorphicValue ASTVisitor:: toTArg(const TemplateArgument& A) { @@ -1837,7 +1839,7 @@ toTArg(const TemplateArgument& A) // type case TemplateArgument::Type: { - auto R = std::make_unique(); + auto R = MakePolymorphicValue(); QualType QT = A.getAsType(); MRDOCS_ASSERT(! QT.isNull()); // if the template argument is a pack expansion, @@ -1850,14 +1852,14 @@ toTArg(const TemplateArgument& A) QT = PT->getPattern(); } R->Type = toTypeInfo(QT); - return R; + return PolymorphicValue(R); } // pack expansion of a template name case TemplateArgument::TemplateExpansion: // template name case TemplateArgument::Template: { - auto R = std::make_unique(); + auto R = MakePolymorphicValue(); R->IsPackExpansion = A.isPackExpansion(); // KRYSTIAN FIXME: template template arguments are @@ -1868,16 +1870,9 @@ toTArg(const TemplateArgument& A) TemplateName const TN = A.getAsTemplateOrTemplatePattern(); if(auto* TD = TN.getAsTemplateDecl()) { - if(auto* II = TD->getIdentifier()) - R->Name = II->getName(); - // do not extract a SymbolID or build Info if - // the template template parameter names a - // template template parameter or builtin template - if(! isa(TD) && - ! isa(TD)) + if (auto* II = TD->getIdentifier()) { - // upsertDependency(getInstantiatedFrom< - // NamedDecl>(TD), R->Template); + R->Name = II->getName(); } } else @@ -1886,7 +1881,7 @@ toTArg(const TemplateArgument& A) TN.print(stream, context_.getPrintingPolicy(), TemplateName::Qualified::AsWritten); } - return R; + return PolymorphicValue(R); } // nullptr value case TemplateArgument::NullPtr: @@ -1897,7 +1892,7 @@ toTArg(const TemplateArgument& A) // expression case TemplateArgument::Expression: { - auto R = std::make_unique(); + auto R = MakePolymorphicValue(); R->IsPackExpansion = A.isPackExpansion(); // if this is a pack expansion, use the template argument // expansion pattern in place of the template argument pack @@ -1908,7 +1903,7 @@ toTArg(const TemplateArgument& A) llvm::raw_string_ostream stream(R->Value.Written); adjusted.print(context_.getPrintingPolicy(), stream, false); - return R; + return PolymorphicValue(R); } default: MRDOCS_UNREACHABLE(); @@ -3014,8 +3009,7 @@ upsert(SymbolID const& id) bool const isNew = !info; if (!info) { - info = info_.emplace(std::make_unique< - InfoTy>(id)).first->get(); + info = info_.emplace(std::make_unique(id)).first->get(); auto const minExtract = mode_ == TraversalMode::Regular ? ExtractionMode::Regular : ExtractionMode::Dependency; info->Extraction = mostSpecific(info->Extraction, minExtract); diff --git a/src/lib/AST/ASTVisitor.hpp b/src/lib/AST/ASTVisitor.hpp index 543af3e37f..8bd645cdfc 100644 --- a/src/lib/AST/ASTVisitor.hpp +++ b/src/lib/AST/ASTVisitor.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -586,7 +585,7 @@ class ASTVisitor populate(ConstantExprInfo& I, const Expr* E, const llvm::APInt& V); void - populate(std::unique_ptr& I, const NamedDecl* N); + populate(PolymorphicValue& I, const NamedDecl* N); void populate(std::optional& TI, const TemplateParameterList* TPL) { @@ -603,7 +602,7 @@ class ASTVisitor template Range> void populate( - std::vector>& result, + std::vector>& result, Range&& args) { for (TemplateArgument const& arg : args) @@ -628,7 +627,7 @@ class ASTVisitor void populate( - std::vector>& result, + std::vector>& result, const ASTTemplateArgumentListInfo* args); template InfoTy> @@ -664,37 +663,37 @@ class ASTVisitor */ bool generateJavadoc( - std::unique_ptr& javadoc, + std::optional& javadoc, Decl const* D); - std::unique_ptr + PolymorphicValue toTypeInfo(QualType qt, TraversalMode mode); - std::unique_ptr + PolymorphicValue toTypeInfo(QualType qt) { return toTypeInfo(qt, TraversalMode::Dependency); } - std::unique_ptr + PolymorphicValue toNameInfo( NestedNameSpecifier const* NNS); template > - std::unique_ptr + PolymorphicValue toNameInfo( DeclarationName Name, std::optional TArgs = std::nullopt, const NestedNameSpecifier* NNS = nullptr); template > - std::unique_ptr + PolymorphicValue toNameInfo( const Decl* D, std::optional TArgs = std::nullopt, const NestedNameSpecifier* NNS = nullptr); - std::unique_ptr + PolymorphicValue toTArg(const TemplateArgument& A); // Pretty-print an expression diff --git a/src/lib/AST/NameInfoBuilder.cpp b/src/lib/AST/NameInfoBuilder.cpp index ea83f94511..e86812c0a6 100644 --- a/src/lib/AST/NameInfoBuilder.cpp +++ b/src/lib/AST/NameInfoBuilder.cpp @@ -34,8 +34,8 @@ buildTerminal( unsigned, bool) { - auto I = std::make_unique(); - I->Name = getASTVisitor().toString(T); + NameInfo I; + I.Name = getASTVisitor().toString(T); Result = std::move(I); if (NNS) { @@ -52,19 +52,19 @@ buildTerminal( unsigned, bool) { - if(TArgs) + if (TArgs) { - auto I = std::make_unique(); + auto I = MakePolymorphicValue(); if (II) { I->Name = II->getName(); } getASTVisitor().populate(I->TemplateArgs, *TArgs); - Result = std::move(I); + Result = PolymorphicValue(std::move(I)); } else { - auto I = std::make_unique(); + auto I = MakePolymorphicValue(); if (II) { I->Name = II->getName(); @@ -90,33 +90,35 @@ buildTerminal( // we look for the Info of the specialized record. Decl const* ID = decayToPrimaryTemplate(D); - auto TI = std::make_unique(); - auto populateNameInfo = [&](NameInfo* Name, NamedDecl const* D) + auto populateNameInfo = [&](NameInfo& Name, NamedDecl const* DU) { - if(const IdentifierInfo* II = D->getIdentifier()) + if(const IdentifierInfo* II = DU->getIdentifier()) { - Name->Name = II->getName(); + Name.Name = II->getName(); } if (Info const* I = getASTVisitor().findOrTraverse(const_cast(ID))) { - Name->id = I->id; + Name.id = I->id; } - if(NNS) + if (NNS) { - Name->Prefix = getASTVisitor().toNameInfo(NNS); + Name.Prefix = getASTVisitor().toNameInfo(NNS); } }; + PolymorphicValue TI; if (!TArgs) { - populateNameInfo(TI.get(), D); + NameInfo Name; + populateNameInfo(Name, D); + TI = std::move(Name); } else { - auto Name = std::make_unique(); - populateNameInfo(Name.get(), D); - getASTVisitor().populate(Name->TemplateArgs, *TArgs); + SpecializationNameInfo Name; + populateNameInfo(Name, D); + getASTVisitor().populate(Name.TemplateArgs, *TArgs); TI = std::move(Name); } Result = std::move(TI); diff --git a/src/lib/AST/NameInfoBuilder.hpp b/src/lib/AST/NameInfoBuilder.hpp index 368ffb7185..9e31973ed0 100644 --- a/src/lib/AST/NameInfoBuilder.hpp +++ b/src/lib/AST/NameInfoBuilder.hpp @@ -14,6 +14,7 @@ #ifndef MRDOCS_LIB_AST_NAMEINFOBUILDER_HPP #define MRDOCS_LIB_AST_NAMEINFOBUILDER_HPP +#include #include #include @@ -22,12 +23,12 @@ namespace clang::mrdocs { class NameInfoBuilder : public TerminalTypeVisitor { - std::unique_ptr Result; + PolymorphicValue Result; public: using TerminalTypeVisitor::TerminalTypeVisitor; - std::unique_ptr + PolymorphicValue result() { return std::move(Result); diff --git a/src/lib/AST/ParseJavadoc.cpp b/src/lib/AST/ParseJavadoc.cpp index 7fabf90d74..e641971214 100644 --- a/src/lib/AST/ParseJavadoc.cpp +++ b/src/lib/AST/ParseJavadoc.cpp @@ -164,7 +164,7 @@ class JavadocVisitor FullComment const* FC_; Javadoc jd_; Diagnostics& diags_; - doc::List params_; + std::vector> params_; doc::Block* block_ = nullptr; doc::Text* last_child_ = nullptr; std::size_t htmlTagNesting_ = 0; @@ -400,7 +400,7 @@ class JavadocVisitor */ template TextTy, typename... Args> void - emplaceText(bool end_with_nl, Args&&... args) + emplaceText(bool const end_with_nl, Args&&... args) { TextTy elem(std::forward(args)...); bool can_merge = false; @@ -411,16 +411,15 @@ class JavadocVisitor can_merge = true; if constexpr(TextTy::static_kind == doc::Kind::styled) - can_merge = static_cast( + can_merge = dynamic_cast( last_child_)->style == elem.style; } if(! can_merge) { - auto new_text = std::make_unique(std::move(elem)); - last_child_ = new_text.get(); + auto new_text = MakePolymorphicValue(std::move(elem)); + last_child_ = new_text.operator->(); block_->children.emplace_back(std::move(new_text)); - } else { @@ -465,12 +464,12 @@ ensureUTF8( escaped by prefixing them with a backslash. */ -doc::List +std::vector> parseStyled(StringRef s) { - doc::List result; + std::vector> result; std::string currentText; - doc::Style currentStyle = doc::Style::none; + auto currentStyle = doc::Style::none; bool escapeNext = false; auto isStyleMarker = [](char c) { @@ -490,21 +489,21 @@ parseStyled(StringRef s) } else { - result.emplace_back(std::make_unique(std::move(currentText))); + result.emplace_back(MakePolymorphicValue(std::move(currentText))); } } else { bool const lastIsSame = !result.empty() && result.back()->kind == doc::Kind::styled && - static_cast(*result.back()).style == currentStyle; + dynamic_cast(*result.back()).style == currentStyle; if (lastIsSame) { - auto& lastStyled = static_cast(*result.back()); + auto& lastStyled = dynamic_cast(*result.back()); lastStyled.string.append(currentText); } else { - result.emplace_back(std::make_unique(std::move(currentText), currentStyle)); + result.emplace_back(MakePolymorphicValue(std::move(currentText), currentStyle)); } } currentText.clear(); @@ -582,17 +581,17 @@ visitChildren( auto it = block_->children.begin(); while(it != block_->children.end()) { - auto& child = *it; - if (child.get()->kind == doc::Kind::text) + if (auto& child = *it; + child->kind == doc::Kind::text) { - auto* text = dynamic_cast(child.get()); + auto* text = dynamic_cast(child.operator->()); MRDOCS_ASSERT(text); auto next = std::next(it); if(next != block_->children.end()) { - if(next->get()->kind == doc::Kind::text) + if((*next)->kind == doc::Kind::text) { - auto* next_text = dynamic_cast(next->get()); + auto* next_text = dynamic_cast(next->operator->()); MRDOCS_ASSERT(next_text); text->string.append(next_text->string); it = block_->children.erase(next); @@ -604,25 +603,25 @@ visitChildren( } // Parse any Text nodes for styled text - for (auto it = block_->children.begin(); it != block_->children.end();) + for (auto cIt = block_->children.begin(); cIt != block_->children.end();) { - MRDOCS_ASSERT(it->get()); - if (it->get()->kind == doc::Kind::text) + MRDOCS_ASSERT(cIt->operator->()); + if ((*cIt)->kind == doc::Kind::text) { - auto* text = dynamic_cast(it->get()); + auto* text = dynamic_cast(cIt->operator->()); auto styledText = parseStyled(text->string); - std::size_t const offset = std::distance(block_->children.begin(), it); + std::size_t const offset = std::distance(block_->children.begin(), cIt); std::size_t const n = styledText.size(); - block_->children.erase(it); + block_->children.erase(cIt); block_->children.insert( block_->children.begin() + offset, std::make_move_iterator(styledText.begin()), std::make_move_iterator(styledText.end())); - it = block_->children.begin() + offset + n; + cIt = block_->children.begin() + offset + n; } else { - ++it; + ++cIt; } } } @@ -664,16 +663,17 @@ build() // Move list items to ul.items ul.items.reserve(std::distance(it, last)); for (auto li_it = begin; li_it != last; ++li_it) { - std::unique_ptr block = std::move(*li_it); - MRDOCS_ASSERT(dynamic_cast(block.get())); - doc::Block* raw_block_ptr = block.release(); - auto const raw_li_ptr = static_cast(raw_block_ptr); - auto li = std::make_unique(std::move(*raw_li_ptr)); - ul.items.emplace_back(std::move(li)); + PolymorphicValue block = std::move(*li_it); + MRDOCS_ASSERT(IsA(block)); + PolymorphicValue li = DynamicCast(std::move(block)); + ul.items.emplace_back(std::move(*li)); } // Remove the list items and insert the ul it = blocks.erase(begin, last); - it = blocks.insert(it, std::make_unique(std::move(ul))); + it = blocks.insert( + it, + PolymorphicValue( + MakePolymorphicValue(std::move(ul)))); } ++it; } @@ -1128,25 +1128,26 @@ visitInlineCommandComment( // It looks like the clang parser does not // emit nested styles, so only one inline // style command can be applied per args. - - doc::String s; + std::string s; std::size_t n = 0; - for(unsigned i = 0; i < C->getNumArgs(); ++i) + for (unsigned i = 0; i < C->getNumArgs(); ++i) + { n += C->getArgText(i).size(); + } s.reserve(n); - for(unsigned i = 0; i < C->getNumArgs(); ++i) + for (unsigned i = 0; i < C->getNumArgs(); ++i) + { s.append(C->getArgText(i)); + } - doc::Style style = convertStyle(C->getRenderKind()); - if(style != doc::Style::none) - emplaceText( - C->hasTrailingNewline(), - std::move(s), - style); - else - emplaceText( - C->hasTrailingNewline(), - std::move(s)); + if (doc::Style style = convertStyle(C->getRenderKind()); + style != doc::Style::none) + { + emplaceText(C->hasTrailingNewline(), std::move(s), style); + } else + { + emplaceText(C->hasTrailingNewline(), std::move(s)); + } } //------------------------------------------------ @@ -1208,7 +1209,7 @@ visitBlockCommandComment( { auto itr = std::ranges::find_if( jd_.getBlocks(), - [&](const std::unique_ptr & b) + [&](const PolymorphicValue & b) { return b->kind == doc::Kind::returns; }); @@ -1271,7 +1272,7 @@ visitBlockCommandComment( // the first TextComment is the heading text if (C->getNumArgs() == 0) { - doc::String text(std::move( + std::string text(std::move( paragraph.children.front()->string)); // VFALCO Unfortunately clang puts at least @@ -1561,13 +1562,15 @@ visitParamCommandComment( auto scope = enterScope(param); visitChildren(C->getParagraph()); - auto itr = std::ranges::find_if( + auto const itr = std::ranges::find_if( jd_.getBlocks(), - [&](const std::unique_ptr & b) + [&](PolymorphicValue const& b) { if (b->kind != doc::Kind::param) + { return false; - auto p = dynamic_cast(b.get()); + } + auto p = dynamic_cast(b.operator->()); MRDOCS_ASSERT(p != nullptr); return p->name == param.name; }); @@ -1602,13 +1605,15 @@ visitTParamCommandComment( auto scope = enterScope(tparam); visitChildren(C->getParagraph()); - auto itr = std::ranges::find_if( + auto const itr = std::ranges::find_if( jd_.getBlocks(), - [&](const std::unique_ptr & b) + [&](PolymorphicValue const& b) { if (b->kind != doc::Kind::tparam) + { return false; - auto tp = dynamic_cast(b.get()); + } + auto const tp = dynamic_cast(b.operator->()); MRDOCS_ASSERT(tp != nullptr); return tp->name == tparam.name; }); @@ -1703,7 +1708,7 @@ initCustomCommentCommands(ASTContext& context) void parseJavadoc( - std::unique_ptr& jd, + std::optional& jd, FullComment const* FC, Decl const* D, Config const& config, @@ -1712,11 +1717,13 @@ parseJavadoc( MRDOCS_COMMENT_TRACE(FC, D->getASTContext()); JavadocVisitor visitor(FC, D, config, diags); auto result = visitor.build(); - if(jd == nullptr) + if (!jd) { // Do not create javadocs which have no nodes - if(! result.getBlocks().empty()) - jd = std::make_unique(std::move(result)); + if (!result.getBlocks().empty()) + { + jd = std::move(result); + } } else if(*jd != result) { diff --git a/src/lib/AST/ParseJavadoc.hpp b/src/lib/AST/ParseJavadoc.hpp index 2dfd3d0728..0c29f3986d 100644 --- a/src/lib/AST/ParseJavadoc.hpp +++ b/src/lib/AST/ParseJavadoc.hpp @@ -51,7 +51,7 @@ initCustomCommentCommands( */ void parseJavadoc( - std::unique_ptr& jd, + std::optional& jd, comments::FullComment const* FC, Decl const* D, Config const& config, diff --git a/src/lib/AST/TerminalTypeVisitor.hpp b/src/lib/AST/TerminalTypeVisitor.hpp index eaba00ff25..c320b08e11 100644 --- a/src/lib/AST/TerminalTypeVisitor.hpp +++ b/src/lib/AST/TerminalTypeVisitor.hpp @@ -153,6 +153,7 @@ class TerminalTypeVisitor This function is an empty placeholder for `buildPointer` when not defined by the `Derived` visitor. */ + static void buildPointer (const PointerType*, diff --git a/src/lib/AST/TypeInfoBuilder.cpp b/src/lib/AST/TypeInfoBuilder.cpp index 6fac4c334a..89e5cac427 100644 --- a/src/lib/AST/TypeInfoBuilder.cpp +++ b/src/lib/AST/TypeInfoBuilder.cpp @@ -19,56 +19,61 @@ void TypeInfoBuilder:: buildPointer(const PointerType* T, unsigned quals) { - auto I = std::make_unique(); - I->CVQualifiers = toQualifierKind(quals); - *std::exchange(Inner, &I->PointeeType) = std::move(I); + PointerTypeInfo I; + I.CVQualifiers = toQualifierKind(quals); + *Inner = std::move(I); + Inner = &get(*Inner).PointeeType; } void TypeInfoBuilder:: buildLValueReference(const LValueReferenceType* T) { - auto I = std::make_unique(); - *std::exchange(Inner, &I->PointeeType) = std::move(I); + LValueReferenceTypeInfo I; + *Inner = std::move(I); + Inner = &get(*Inner).PointeeType; } void TypeInfoBuilder:: buildRValueReference(const RValueReferenceType* T) { - auto I = std::make_unique(); - *std::exchange(Inner, &I->PointeeType) = std::move(I); + RValueReferenceTypeInfo I; + *Inner = std::move(I); + Inner = &get(*Inner).PointeeType; } void TypeInfoBuilder:: -buildMemberPointer(const MemberPointerType* T, unsigned quals) +buildMemberPointer( + const MemberPointerType* T, + unsigned const quals) { - auto I = std::make_unique(); - I->CVQualifiers = toQualifierKind(quals); + MemberPointerTypeInfo I; + I.CVQualifiers = toQualifierKind(quals); // do not set NNS because the parent type is *not* // a nested-name-specifier which qualifies the pointee type - I->ParentType = getASTVisitor().toTypeInfo( + I.ParentType = getASTVisitor().toTypeInfo( QualType(T->getClass(), 0)); - *std::exchange(Inner, &I->PointeeType) = std::move(I); + *Inner = std::move(I); + Inner = &get(*Inner).PointeeType; } void TypeInfoBuilder:: buildArray(const ArrayType* T) { - auto I = std::make_unique(); - if(auto* CAT = dyn_cast(T)) + ArrayTypeInfo I; + if (auto* CAT = dyn_cast(T)) { - getASTVisitor().populate( - I->Bounds, CAT->getSizeExpr(), CAT->getSize()); + getASTVisitor().populate(I.Bounds, CAT->getSizeExpr(), CAT->getSize()); } - else if(auto* DAT = dyn_cast(T)) + else if (auto* DAT = dyn_cast(T)) { - getASTVisitor().populate( - I->Bounds, DAT->getSizeExpr()); + getASTVisitor().populate(I.Bounds, DAT->getSizeExpr()); } - *std::exchange(Inner, &I->ElementType) = std::move(I); + *Inner = std::move(I); + Inner = &get(*Inner).ElementType; } void @@ -76,19 +81,19 @@ TypeInfoBuilder:: populate(const FunctionType* T) { auto* FPT = cast(T); - auto I = std::make_unique(); - for(QualType PT : FPT->getParamTypes()) + FunctionTypeInfo I; + for (QualType const PT : FPT->getParamTypes()) { - I->ParamTypes.emplace_back( - getASTVisitor().toTypeInfo(PT)); + I.ParamTypes.emplace_back(getASTVisitor().toTypeInfo(PT)); } - I->RefQualifier = toReferenceKind( + I.RefQualifier = toReferenceKind( FPT->getRefQualifier()); - I->CVQualifiers = toQualifierKind( + I.CVQualifiers = toQualifierKind( FPT->getMethodQuals().getFastQualifiers()); - I->IsVariadic = FPT->isVariadic(); - getASTVisitor().populate(I->ExceptionSpec, FPT); - *std::exchange(Inner, &I->ReturnType) = std::move(I); + I.IsVariadic = FPT->isVariadic(); + getASTVisitor().populate(I.ExceptionSpec, FPT); + *Inner = std::move(I); + Inner = &get(*Inner).ReturnType; } void @@ -98,11 +103,11 @@ buildDecltype( unsigned quals, bool pack) { - auto I = std::make_unique(); + DecltypeTypeInfo I;; getASTVisitor().populate( - I->Operand, T->getUnderlyingExpr()); - I->CVQualifiers = toQualifierKind(quals); - I->Constraints = this->Constraints; + I.Operand, T->getUnderlyingExpr()); + I.CVQualifiers = toQualifierKind(quals); + I.Constraints = this->Constraints; *Inner = std::move(I); Result->IsPackExpansion = pack; } @@ -114,9 +119,9 @@ buildAuto( unsigned const quals, bool const pack) { - auto I = std::make_unique(); - I->CVQualifiers = toQualifierKind(quals); - I->Keyword = convertToAutoKind(T->getKeyword()); + AutoTypeInfo I; + I.CVQualifiers = toQualifierKind(quals); + I.Keyword = convertToAutoKind(T->getKeyword()); if(T->isConstrained()) { std::optional> TArgs; @@ -125,18 +130,16 @@ buildAuto( { TArgs.emplace(Args); } - I->Constraint = getASTVisitor().toNameInfo( + I.Constraint = getASTVisitor().toNameInfo( T->getTypeConstraintConcept(), TArgs); // Constraint->Prefix = getASTVisitor().buildNameInfo( // cast(CD->getDeclContext())); } - I->Constraints = this->Constraints; + I.Constraints = this->Constraints; *Inner = std::move(I); Result->IsPackExpansion = pack; } - - void TypeInfoBuilder:: buildTerminal( @@ -145,12 +148,12 @@ buildTerminal( unsigned quals, bool pack) { - auto TI = std::make_unique(); - TI->CVQualifiers = toQualifierKind(quals); - TI->Name = std::make_unique(); - TI->Name->Name = getASTVisitor().toString(T); - TI->Name->Prefix = getASTVisitor().toNameInfo(NNS); - TI->Constraints = this->Constraints; + NamedTypeInfo TI; + TI.CVQualifiers = toQualifierKind(quals); + TI.Name = MakePolymorphicValue(); + TI.Name->Name = getASTVisitor().toString(T); + TI.Name->Prefix = getASTVisitor().toNameInfo(NNS); + TI.Constraints = this->Constraints; *Inner = std::move(TI); Result->Constraints = this->Constraints; Result->IsPackExpansion = pack; @@ -165,31 +168,31 @@ buildTerminal( unsigned quals, bool pack) { - auto I = std::make_unique(); - I->CVQualifiers = toQualifierKind(quals); + NamedTypeInfo I; + I.CVQualifiers = toQualifierKind(quals); - if(TArgs) + if (TArgs) { - auto Name = std::make_unique(); + SpecializationNameInfo Name; if(II) { - Name->Name = II->getName(); + Name.Name = II->getName(); } - Name->Prefix = getASTVisitor().toNameInfo(NNS); - getASTVisitor().populate(Name->TemplateArgs, *TArgs); - I->Name = std::move(Name); + Name.Prefix = getASTVisitor().toNameInfo(NNS); + getASTVisitor().populate(Name.TemplateArgs, *TArgs); + I.Name = std::move(Name); } else { - auto Name = std::make_unique(); + NameInfo Name; if(II) { - Name->Name = II->getName(); + Name.Name = II->getName(); } - Name->Prefix = getASTVisitor().toNameInfo(NNS); - I->Name = std::move(Name); + Name.Prefix = getASTVisitor().toNameInfo(NNS); + I.Name = std::move(Name); } - I->Constraints = this->Constraints; + I.Constraints = this->Constraints; *Inner = std::move(I); Result->Constraints = this->Constraints; Result->IsPackExpansion = pack; @@ -213,38 +216,39 @@ buildTerminal( Decl const* ID = decayToPrimaryTemplate(D); MRDOCS_SYMBOL_TRACE(ID, getASTVisitor().context_); - auto TI = std::make_unique(); - TI->CVQualifiers = toQualifierKind(quals); + NamedTypeInfo TI; + TI.CVQualifiers = toQualifierKind(quals); - auto populateNameInfo = [&](NameInfo* Name, NamedDecl* D) + auto populateNameInfo = [&](NameInfo& Name, NamedDecl* D) { if(const IdentifierInfo* II = D->getIdentifier()) { - Name->Name = II->getName(); + Name.Name = II->getName(); } if (Info const* I = getASTVisitor().findOrTraverse(const_cast(ID))) { - Name->id = I->id; + Name.id = I->id; } if(NNS) { - Name->Prefix = getASTVisitor().toNameInfo(NNS); + Name.Prefix = getASTVisitor().toNameInfo(NNS); } }; if (!TArgs) { - TI->Name = std::make_unique(); - populateNameInfo(TI->Name.get(), D); + NameInfo Name; + populateNameInfo(Name, D); + TI.Name = std::move(Name); } else { - auto Name = std::make_unique(); - populateNameInfo(Name.get(), D); - getASTVisitor().populate(Name->TemplateArgs, *TArgs); - TI->Name = std::move(Name); + SpecializationNameInfo Name; + populateNameInfo(Name, D); + getASTVisitor().populate(Name.TemplateArgs, *TArgs); + TI.Name = std::move(Name); } - TI->Constraints = this->Constraints; + TI.Constraints = this->Constraints; *Inner = std::move(TI); Result->Constraints = this->Constraints; Result->IsPackExpansion = pack; diff --git a/src/lib/AST/TypeInfoBuilder.hpp b/src/lib/AST/TypeInfoBuilder.hpp index 4112d07673..02da7a030c 100644 --- a/src/lib/AST/TypeInfoBuilder.hpp +++ b/src/lib/AST/TypeInfoBuilder.hpp @@ -34,18 +34,34 @@ namespace clang::mrdocs { class TypeInfoBuilder : public TerminalTypeVisitor { - std::unique_ptr Result; + /* The resulting of converting a QualType to a TypeInfo - /* A pointer to the inner type being constructed. + This variable holds the result of the type information + as a polymorphic `TypeInfo` object. - This variable is used to chain the construction of - nested type information. - - It temporarily holds the current inner type - until it is assigned to the appropriate member - of the outer type. */ - std::unique_ptr* Inner = &Result; + PolymorphicValue Result; + + /* A pointer to the inner type of result currently being populated. + + The Result variable is a polymorphic `TypeInfo` object that + might contain nested type information, also represented + as a `TypeInfo` object. + + For instance `int&` is represented as a `ReferenceTypeInfo` + object that contains a `NamedTypeInfo` object representing + the `int` type. + + The builder will always populate the inner type of the + result being constructed. For instance, when building + a `ReferenceTypeInfo` object for `int&`, the inner type + (initially the same as the result) will be set to a + `LValueReferenceTypeInfo`, that contains the `NamedTypeInfo` + as a member. So `Inner` becomes a pointer to this + `NamedTypeInfo` object, and the visiting process continues + populating the `Inner` object. + */ + PolymorphicValue* Inner = &Result; public: using TerminalTypeVisitor::TerminalTypeVisitor; @@ -57,7 +73,7 @@ class TypeInfoBuilder @return A unique pointer to the `TypeInfo` object. */ - std::unique_ptr + PolymorphicValue result() { return std::move(Result); diff --git a/src/lib/Gen/adoc/DocVisitor.cpp b/src/lib/Gen/adoc/DocVisitor.cpp index fb11232b4e..084a6bc25f 100644 --- a/src/lib/Gen/adoc/DocVisitor.cpp +++ b/src/lib/Gen/adoc/DocVisitor.cpp @@ -98,25 +98,33 @@ DocVisitor:: operator()( doc::Paragraph const& I) const { - std::span const children = I.children; - if (children.empty()) + if (I.children.empty()) { return; } std::size_t i = 0; - for (auto it = children.begin(); it != children.end(); ++it) + for (auto it = I.children.begin(); it != I.children.end(); ++it) { auto& child = *it; - if (i == 0) + if (i != 0 && + i != I.children.size() - 1) { - child->string = ltrim(child->string); + write(*child, *this); } - if (i == children.size() - 1) + else { - child->string = rtrim(child->string); + auto childCopy = *it; + if (i == 0) + { + childCopy->string = ltrim(childCopy->string); + } + if (i == I.children.size() - 1) + { + childCopy->string = rtrim(childCopy->string); + } + write(*childCopy, *this); } - write(*child, *this); i = i + 1; } @@ -139,15 +147,24 @@ operator()( for (auto it = children.begin(); it != children.end(); ++it) { auto& child = *it; - if (i == 0) + if (i != 0 && + i != children.size() - 1) { - child->string = ltrim(child->string); + write(*child, *this); } - if (i == children.size() - 1) + else { - child->string = rtrim(child->string); + auto childCopy = *it; + if (i == 0) + { + childCopy->string = ltrim(childCopy->string); + } + if (i == children.size() - 1) + { + childCopy->string = rtrim(childCopy->string); + } + write(*childCopy, *this); } - write(*child, *this); i = i + 1; } } @@ -198,7 +215,7 @@ operator()( } for(auto const& child : I.items) { - operator()(*child); + operator()(child); } dest_.push_back('\n'); } @@ -297,8 +314,7 @@ operator()(doc::Throws const& I) const std::size_t DocVisitor:: -measureLeftMargin( - doc::List const& list) +measureLeftMargin(std::vector> const& list) { if(list.empty()) { diff --git a/src/lib/Gen/adoc/DocVisitor.hpp b/src/lib/Gen/adoc/DocVisitor.hpp index 1e15e8b292..53d940c122 100644 --- a/src/lib/Gen/adoc/DocVisitor.hpp +++ b/src/lib/Gen/adoc/DocVisitor.hpp @@ -94,7 +94,7 @@ class DocVisitor static std::size_t - measureLeftMargin(doc::List const& list); + measureLeftMargin(std::vector> const& list); }; } // hbs diff --git a/src/lib/Gen/hbs/VisitorHelpers.cpp b/src/lib/Gen/hbs/VisitorHelpers.cpp index da3157d1cd..cbf5a6382e 100644 --- a/src/lib/Gen/hbs/VisitorHelpers.cpp +++ b/src/lib/Gen/hbs/VisitorHelpers.cpp @@ -9,11 +9,10 @@ // #include "VisitorHelpers.hpp" +#include #include -#include -#include #include -#include +#include namespace clang::mrdocs::hbs { @@ -50,10 +49,10 @@ resolveTypedef(Corpus const& c, Info const& I) { if (I.Kind == InfoKind::Typedef) { - TypedefInfo const& TI = dynamic_cast(I); - std::unique_ptr const& T = TI.Type; + auto const& TI = dynamic_cast(I); + PolymorphicValue const& T = TI.Type; MRDOCS_CHECK_OR(T && T->Kind == TypeKind::Named, &I); - NamedTypeInfo const& NT = dynamic_cast(*T); + auto const& NT = dynamic_cast(*T); MRDOCS_CHECK_OR(NT.Name, &I); Info const* resolved = c.find(NT.Name->id); MRDOCS_CHECK_OR(resolved, &I); @@ -156,7 +155,7 @@ findResolvedPrimarySiblingWithUrl(Corpus const& c, Info const& I) // The symbol is a typedef to a specialization if constexpr (std::same_as) { - std::unique_ptr const& T = U.Type; + PolymorphicValue const& T = U.Type; MRDOCS_CHECK_OR(T && T->Kind == TypeKind::Named, false); auto const& NT = dynamic_cast(*T); MRDOCS_CHECK_OR(NT.Name, false); diff --git a/src/lib/Gen/html/DocVisitor.cpp b/src/lib/Gen/html/DocVisitor.cpp index 72c078d356..dc5829d3bc 100644 --- a/src/lib/Gen/html/DocVisitor.cpp +++ b/src/lib/Gen/html/DocVisitor.cpp @@ -110,15 +110,16 @@ operator()( for (auto it = I.children.begin(); it != I.children.end(); ++it) { auto& child = *it; + auto childCopy = child; if (i == 0) { - child->string = ltrim(child->string); + childCopy->string = ltrim(childCopy->string); } else if (auto prevIt = std::prev(it); - !(*prevIt)->string.empty() && !child->string.empty()) + !(*prevIt)->string.empty() && !childCopy->string.empty()) { char const pc = (*(prevIt))->string.back(); - char const cc = child->string.front(); + char const cc = childCopy->string.front(); if (!std::isspace(pc) && !std::isspace(cc)) { dest_.push_back(' '); @@ -126,9 +127,9 @@ operator()( } if (i == I.children.size() - 1) { - child->string = rtrim(child->string); + childCopy->string = rtrim(childCopy->string); } - write(*child, *this); + write(*childCopy, *this); i = i + 1; } dest_.append("

\n"); @@ -149,15 +150,16 @@ operator()( for (auto it = I.children.begin(); it != I.children.end(); ++it) { auto& child = *it; + auto childCopy = child; if (i == 0) { - child->string = ltrim(child->string); + childCopy->string = ltrim(childCopy->string); } else if (auto prevIt = std::prev(it); - !(*prevIt)->string.empty() && !child->string.empty()) + !(*prevIt)->string.empty() && !childCopy->string.empty()) { char const pc = (*(prevIt))->string.back(); - char const cc = child->string.front(); + char const cc = childCopy->string.front(); if (!std::isspace(pc) && !std::isspace(cc)) { dest_.push_back(' '); @@ -165,9 +167,9 @@ operator()( } if (i == I.children.size() - 1) { - child->string = rtrim(child->string); + childCopy->string = rtrim(childCopy->string); } - write(*child, *this); + write(*childCopy, *this); i = i + 1; } dest_.append("\n"); @@ -223,7 +225,7 @@ operator()( dest_.append("
    \n"); for(auto const& child : I.items) { - operator()(*child); + operator()(child); } dest_.append("
\n"); } @@ -318,7 +320,7 @@ operator()(doc::Throws const& I) const std::size_t DocVisitor:: measureLeftMargin( - doc::List const& list) + std::vector> const& list) { if(list.empty()) { diff --git a/src/lib/Gen/html/DocVisitor.hpp b/src/lib/Gen/html/DocVisitor.hpp index a64ec9c375..520f36b18f 100644 --- a/src/lib/Gen/html/DocVisitor.hpp +++ b/src/lib/Gen/html/DocVisitor.hpp @@ -16,9 +16,7 @@ #include "lib/Gen/hbs/HandlebarsCorpus.hpp" #include -namespace clang { -namespace mrdocs { -namespace html { +namespace clang::mrdocs::html { class DocVisitor { @@ -94,11 +92,9 @@ class DocVisitor static std::size_t - measureLeftMargin(doc::List const& list); + measureLeftMargin(std::vector> const& list); }; -} // html -} // mrdocs -} // clang +} // clang::mrdocs::html #endif diff --git a/src/lib/Gen/xml/CXXTags.cpp b/src/lib/Gen/xml/CXXTags.cpp index 364cf427c2..64bf78c205 100644 --- a/src/lib/Gen/xml/CXXTags.cpp +++ b/src/lib/Gen/xml/CXXTags.cpp @@ -10,11 +10,10 @@ // #include "CXXTags.hpp" -#include +#include +#include -namespace clang { -namespace mrdocs { -namespace xml { +namespace clang::mrdocs::xml { llvm::StringRef getDefaultTagName(Info const& I) noexcept @@ -58,6 +57,4 @@ getTagName(Info const& I) noexcept MRDOCS_UNREACHABLE(); } -} // xml -} // mrdocs -} // clang +} // clang::mrdocs::xml diff --git a/src/lib/Gen/xml/CXXTags.hpp b/src/lib/Gen/xml/CXXTags.hpp index 501aebed6e..0ff28d42ad 100644 --- a/src/lib/Gen/xml/CXXTags.hpp +++ b/src/lib/Gen/xml/CXXTags.hpp @@ -14,12 +14,9 @@ #define MRDOCS_LIB_GEN_XML_CXXTAGS_HPP #include "XMLTags.hpp" -#include +#include #include -#include #include -#include -#include /* This file holds the business logic for transforming @@ -232,7 +229,7 @@ writeType( inline void writeType( - const std::unique_ptr& type, + PolymorphicValue const& type, XMLTags& tags) { if(! type) diff --git a/src/lib/Gen/xml/XMLTags.hpp b/src/lib/Gen/xml/XMLTags.hpp index a1cfe9a7f3..592a0c2220 100644 --- a/src/lib/Gen/xml/XMLTags.hpp +++ b/src/lib/Gen/xml/XMLTags.hpp @@ -12,26 +12,22 @@ #ifndef MRDOCS_LIB_GEN_XML_XMLTAGS_HPP #define MRDOCS_LIB_GEN_XML_XMLTAGS_HPP -#include -#include -#include -#include -#include -#include +#include +#include #include #include #include -#include -#include +#include +#include +#include +#include /* Object for assisting with generating XML tags and correctly escaped strings */ -namespace clang { -namespace mrdocs { -namespace xml { +namespace clang::mrdocs::xml { class jit_indenter; @@ -207,8 +203,6 @@ class XMLTags void nest(int levels); }; -} // xml -} // mrdocs -} // clang +} // clang::mrdocs::xml #endif diff --git a/src/lib/Gen/xml/XMLWriter.cpp b/src/lib/Gen/xml/XMLWriter.cpp index a950dba8de..b23298b94d 100644 --- a/src/lib/Gen/xml/XMLWriter.cpp +++ b/src/lib/Gen/xml/XMLWriter.cpp @@ -237,7 +237,7 @@ writeEnum( { I.Access }, { I.id } }); - if(I.UnderlyingType) + if (I.UnderlyingType) { tags_.open(baseTagName); writeType(I.UnderlyingType, tags_); @@ -707,31 +707,21 @@ writeSpecialization( void XMLWriter:: writeJavadoc( - std::unique_ptr const& javadoc) + std::optional const& javadoc) { - if(! javadoc) + if (!javadoc) + { return; + } tags_.open(javadocTagName); writeNodes(javadoc->getBlocks()); tags_.close(javadocTagName); } -template -void -XMLWriter:: -writeNodes( - doc::List const& list) -{ - if(list.empty()) - return; - for(auto const& node : list) - writeNode(*node); -} void XMLWriter:: -writeNode( - doc::Node const& node) +writeNode(doc::Node const& node) { switch(node.kind) { diff --git a/src/lib/Gen/xml/XMLWriter.hpp b/src/lib/Gen/xml/XMLWriter.hpp index f210f4002f..352fdcb86f 100644 --- a/src/lib/Gen/xml/XMLWriter.hpp +++ b/src/lib/Gen/xml/XMLWriter.hpp @@ -19,9 +19,7 @@ #include #include -namespace clang { -namespace mrdocs { -namespace xml { +namespace clang::mrdocs::xml { class jit_indenter; @@ -60,20 +58,21 @@ class XMLWriter template void operator()(T const&); + + // --------------- + // Info types + #define INFO(Type) void write##Type(Type##Info const&); #include void writeSourceInfo(SourceInfo const& I); void writeLocation(Location const& loc, bool def = false); - void writeJavadoc(std::unique_ptr const& javadoc); + void writeJavadoc(std::optional const& javadoc); void openTemplate(const std::optional& I); void closeTemplate(const std::optional& I); - // void writeType(std::unique_ptr const& type); - - template - void writeNodes(doc::List const& list); - void writeNode(doc::Node const& node); + // --------------- + // Javadoc types void writeAdmonition(doc::Admonition const& node); void writeBrief(doc::Paragraph const& node); @@ -95,10 +94,29 @@ class XMLWriter void writeSee(doc::See const& node, llvm::StringRef tag = ""); void writePrecondition(doc::Precondition const& node); void writePostcondition(doc::Postcondition const& node); + + void writeNode(doc::Node const& node); + + template + void + writeNodes(std::vector> const& list) + { + for (auto const& node: list) + { + writeNode(*node); + } + } + + template T> + void writeNodes(std::vector const& list) + { + for (auto const& node: list) + { + writeNode(node); + } + } }; -} // xml -} // mrdocs -} // clang +} // clang::mrdocs::xml #endif diff --git a/src/lib/Lib/ConfigOptions.json b/src/lib/Lib/ConfigOptions.json index 6e76d703b8..436499958b 100644 --- a/src/lib/Lib/ConfigOptions.json +++ b/src/lib/Lib/ConfigOptions.json @@ -145,8 +145,8 @@ }, { "name": "see-below", - "brief": "Symbols rendered as \"see-below\"", - "details": "Symbols that match one of these filters are tagged as \"see-below\" in the documentation, and so do symbols in scopes tagged as \"see-below\". This option is used to remove details about symbols that are considered part of the private API of the project. In the documentation page for this symbol, the synopsis of the implementation is rendered as \"see-below\" and members of scopes (such as a namespace or record) are not listed. The rest of the documentation is rendered as usual. See the documentation for \"include-symbol\" for the pattern syntax.", + "brief": "Exposition only symbols rendered as \"see-below\".", + "details": "Symbols that match one of these filters are tagged as \"see-below\" in the documentation, and so do symbols in scopes tagged as \"see-below\". This option is used to remove details about symbols that are considered part of the private API of the project but the user might need to interact with. In the documentation page for this symbol, the symbol is exposition only: the synopsis of the implementation is rendered as \"see-below\" and members of scopes (such as a namespace or record) are not listed. The rest of the documentation is rendered as usual to explain the symbol. See the documentation for \"include-symbol\" for the pattern syntax.", "type": "list", "default": [] }, diff --git a/src/lib/Metadata/Enum.cpp b/src/lib/Metadata/Enum.cpp deleted file mode 100644 index 4aa82c115c..0000000000 --- a/src/lib/Metadata/Enum.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// -// This is a derivative work. originally part of the LLVM Project. -// 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) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Official repository: https://github.com/cppalliance/mrdocs -// - -// -// This file defines the merging of different types of infos. The data in the -// calling Info is preserved during a merge unless that field is empty or -// default. In that case, the data from the parameter Info is used to replace -// the empty or default data. -// -// For most fields, the first decl seen provides the data. Exceptions to this -// include the location and description fields, which are collections of data on -// all decls related to a given definition. All other fields are ignored in new -// decls unless the first seen decl didn't, for whatever reason, incorporate -// data on that field (e.g. a forward declared class wouldn't have information -// on members on the forward declaration, but would have the class name). -// - -#include - -namespace clang { -namespace mrdocs { - -} // mrdocs -} // clang diff --git a/src/lib/Metadata/Finalize.cpp b/src/lib/Metadata/Finalize.cpp index 92b507fc8a..2ea5e42833 100644 --- a/src/lib/Metadata/Finalize.cpp +++ b/src/lib/Metadata/Finalize.cpp @@ -91,13 +91,15 @@ class Finalizer return found; } - void finalize(SymbolID& id) + void + finalize(SymbolID& id) { if(id && ! info_.contains(id)) id = SymbolID::invalid; } - void finalize(std::vector& ids) + void + finalize(std::vector& ids) { std::erase_if(ids, [this](const SymbolID& id) { @@ -105,15 +107,19 @@ class Finalizer }); } - void finalize(TArg& arg) + void + finalize(TArg& arg) { visit(arg, [this](Ty& A) { - if constexpr(Ty::isType()) + if constexpr (Ty::isType()) + { finalize(A.Type); - - if constexpr(Ty::isTemplate()) + } + if constexpr (Ty::isTemplate()) + { finalize(A.Template); + } }); } @@ -224,32 +230,50 @@ class Finalizer // name unless part of a class member access... requires { this->finalize(*ptr); } { - if(ptr) + if (ptr) + { finalize(*ptr); + } } template void finalize(std::unique_ptr& ptr) requires - requires { this->finalize(*ptr); } + requires { this->finalize(*ptr); } { - if(ptr) + if (ptr) + { finalize(*ptr); + } } template void finalize(std::optional& ptr) requires requires { this->finalize(*ptr); } { - if(ptr) + if (ptr) + { finalize(*ptr); + } + } + + template + void finalize(PolymorphicValue& v) requires + requires { this->finalize(*v); } + { + if (v) + { + finalize(*v); + } } template - requires std::ranges::input_range + requires std::ranges::input_range void finalize(Range&& range) { - for(auto&& elem : range) + for (auto&& elem: range) + { finalize(elem); + } } // ---------------------------------------------------------------- diff --git a/src/lib/Metadata/Finalize.hpp b/src/lib/Metadata/Finalize.hpp index a90b562310..97e4090c89 100644 --- a/src/lib/Metadata/Finalize.hpp +++ b/src/lib/Metadata/Finalize.hpp @@ -14,14 +14,12 @@ #include "lib/Lib/Info.hpp" #include "lib/Lib/Lookup.hpp" -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { MRDOCS_DECL void finalize(InfoSet& Info, SymbolLookup& Lookup); -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/src/lib/Metadata/Info.cpp b/src/lib/Metadata/Info.cpp index 6b9a37c31e..6fffa7ff5f 100644 --- a/src/lib/Metadata/Info.cpp +++ b/src/lib/Metadata/Info.cpp @@ -9,17 +9,16 @@ // Official repository: https://github.com/cppalliance/mrdocs // -#include "lib/Support/Radix.hpp" -#include "lib/Dom/LazyObject.hpp" #include "lib/Dom/LazyArray.hpp" -#include -#include -#include -#include +#include "lib/Dom/LazyObject.hpp" +#include "lib/Support/Radix.hpp" +#include #include #include #include #include +#include +#include namespace clang { namespace mrdocs { @@ -298,51 +297,33 @@ operator<( Info const& lhs, Info const& rhs) noexcept { + // Consider kind if (lhs.Kind != rhs.Kind) { return lhs.Kind < rhs.Kind; } + + // Consider name if (lhs.Name != rhs.Name) { return lhs.Name < rhs.Name; } - // If kind and name are the same, compare by template arguments - TemplateInfo const* lhsTemplate = visit(lhs, [](auto const& U) + // Consider template arguments + auto getTemplateInfoFn = [](auto const& U) -> TemplateInfo const* { if constexpr (requires { U.Template; }) { - if (U.Template) - { - return &*U.Template; - } + MRDOCS_CHECK_OR(U.Template, nullptr); + return &*U.Template; } return nullptr; - }); - TemplateInfo const* rhsTemplate = visit(rhs, [](auto const& U) - -> TemplateInfo const* - { - if constexpr (requires { U.Template; }) - { - if (U.Template) - { - return &*U.Template; - } - } - return nullptr; - }); - if (!lhsTemplate && !rhsTemplate) - { - return false; - } - if (!lhsTemplate) - { - return true; - } - if (!rhsTemplate) - { - return false; + }; + TemplateInfo const* lhsTemplate = visit(lhs, getTemplateInfoFn); + TemplateInfo const* rhsTemplate = visit(rhs, getTemplateInfoFn); + if (!lhsTemplate || !rhsTemplate) { + return lhsTemplate != nullptr; } if (lhsTemplate->Args.size() != rhsTemplate->Args.size()) { diff --git a/src/lib/Metadata/Function.cpp b/src/lib/Metadata/Info/Function.cpp similarity index 99% rename from src/lib/Metadata/Function.cpp rename to src/lib/Metadata/Info/Function.cpp index e2acbee167..775b4ed03e 100644 --- a/src/lib/Metadata/Function.cpp +++ b/src/lib/Metadata/Info/Function.cpp @@ -10,10 +10,10 @@ // Official repository: https://github.com/cppalliance/mrdocs // -#include -#include -#include #include +#include +#include +#include namespace clang { namespace mrdocs { diff --git a/src/lib/Metadata/Overloads.cpp b/src/lib/Metadata/Info/Overloads.cpp similarity index 94% rename from src/lib/Metadata/Overloads.cpp rename to src/lib/Metadata/Info/Overloads.cpp index c04e6bb19c..4ce7940c8a 100644 --- a/src/lib/Metadata/Overloads.cpp +++ b/src/lib/Metadata/Info/Overloads.cpp @@ -8,15 +8,15 @@ // Official repository: https://github.com/cppalliance/mrdocs // -#include -#include -#include -#include -#include +#include "lib/Support/Radix.hpp" +#include +#include +#include #include #include #include -#include "lib/Support/Radix.hpp" +#include +#include namespace clang::mrdocs { diff --git a/src/lib/Metadata/Record.cpp b/src/lib/Metadata/Info/Record.cpp similarity index 96% rename from src/lib/Metadata/Record.cpp rename to src/lib/Metadata/Info/Record.cpp index 1dd491ad92..e822502907 100644 --- a/src/lib/Metadata/Record.cpp +++ b/src/lib/Metadata/Info/Record.cpp @@ -8,7 +8,7 @@ // Official repository: https://github.com/cppalliance/mrdocs // -#include +#include #include namespace clang { diff --git a/src/lib/Metadata/Scope.cpp b/src/lib/Metadata/Info/Scope.cpp similarity index 97% rename from src/lib/Metadata/Scope.cpp rename to src/lib/Metadata/Info/Scope.cpp index 4a24050cb4..a68144026f 100644 --- a/src/lib/Metadata/Scope.cpp +++ b/src/lib/Metadata/Info/Scope.cpp @@ -9,7 +9,7 @@ // #include -#include +#include #include #include diff --git a/src/lib/Metadata/Interface.cpp b/src/lib/Metadata/Interface.cpp index e8af6d5a59..c442f5ad73 100644 --- a/src/lib/Metadata/Interface.cpp +++ b/src/lib/Metadata/Interface.cpp @@ -16,16 +16,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include #include -#include -#include -#include -#include #include namespace clang { @@ -105,7 +105,7 @@ class TrancheBuilder // When adding a function to the tranche, we have to // check if the function isn't already overriden by // a function with the same name and signature. - if (Tranche* tranche = trancheFor(access)) + if (trancheFor(access)) { if (buildingFromBase_) { diff --git a/src/lib/Metadata/Javadoc.cpp b/src/lib/Metadata/Javadoc.cpp index b8d386f822..b15168429f 100644 --- a/src/lib/Metadata/Javadoc.cpp +++ b/src/lib/Metadata/Javadoc.cpp @@ -26,7 +26,7 @@ namespace doc { Text& Block:: emplace_back( - std::unique_ptr text) + PolymorphicValue text) { MRDOCS_ASSERT(text->isText()); return *children.emplace_back(std::move(text)); @@ -34,47 +34,24 @@ emplace_back( void Block:: -append(List&& blocks) +append(std::vector>&& blocks) { children.reserve(children.size() + blocks.size()); - for(auto&& block : blocks) + for (auto&& block : blocks) { MRDOCS_ASSERT(block->isText()); - emplace_back(std::unique_ptr( - dynamic_cast(block.release()))); + emplace_back(DynamicCast(std::move(block))); } } void Block:: -append(List const& otherChildren) +append(std::vector> const& otherChildren) { - children.reserve(children.size() + otherChildren.size()); - for(auto const& otherChildPtr : otherChildren) - { - Text const& otherChild = *otherChildPtr; - visit(otherChild, [this](U const& otherChildU) { - if constexpr (std::derived_from) - { - U otherChildCopy; - otherChildCopy.string = otherChildU.string; - if constexpr (std::derived_from) - { - otherChildCopy.style = otherChildU.style; - } - if constexpr (std::derived_from) - { - otherChildCopy.href = otherChildU.href; - } - if constexpr (std::derived_from) - { - otherChildCopy.id = otherChildU.id; - } - auto otherChildCopyPtr = std::make_unique(std::move(otherChildCopy)); - children.push_back(std::move(otherChildCopyPtr)); - } - }); - } + children.insert( + children.end(), + otherChildren.begin(), + otherChildren.end()); } dom::String @@ -100,29 +77,12 @@ toString( //------------------------------------------------ -template -static -auto -move_to( - doc::List& dst, - doc::List& src, - typename doc::List::iterator it) -{ - auto elem = std::move(*it); - it = src.erase(it); - dst.emplace(dst.end(), - static_cast(elem.release())); - return it; -} - -//------------------------------------------------ - Javadoc:: Javadoc() noexcept = default; Javadoc:: Javadoc( - doc::List blocks) + std::vector> blocks) : blocks_(std::move(blocks)) { } @@ -132,20 +92,20 @@ Javadoc:: getBrief(Corpus const& corpus) const noexcept { // Brief from a @brief tag - const doc::Block* brief = nullptr; + doc::Block const* brief = nullptr; // The first paragraph promoted to brief - const doc::Block* promoted_brief = nullptr; + doc::Block const* promoted_brief = nullptr; // A brief copied from another symbol - const doc::Block* copied_brief = nullptr; + doc::Block const* copied_brief = nullptr; for(auto const& block : blocks_) { if (!brief && block->kind == doc::Kind::brief) { - brief = block.get(); + brief = block.operator->(); } if (!promoted_brief && block->kind == doc::Kind::paragraph) { - promoted_brief = block.get(); + promoted_brief = block.operator->(); } // if we already have an explicit/copied brief, @@ -162,13 +122,13 @@ getBrief(Corpus const& corpus) const noexcept { continue; } - auto const* copy = dynamic_cast(text.get()); - if(copy->id && - (copy->parts == doc::Parts::all || - copy->parts == doc::Parts::brief)) + if (auto const* copied = dynamic_cast(text.operator->()); + copied->id && + (copied->parts == doc::Parts::all || + copied->parts == doc::Parts::brief)) { // Look for the symbol to copy from - if (auto& jd = corpus.get(copy->id).javadoc) + if (auto& jd = corpus.get(copied->id).javadoc) { copied_brief = jd->getBrief(corpus); } @@ -190,23 +150,27 @@ getBrief(Corpus const& corpus) const noexcept return static_cast(brief); } -doc::List const& +std::vector> const& Javadoc:: getDescription(Corpus const& corpus) const noexcept { - for(auto const& block : blocks_) + for (auto const& block : blocks_) { for(auto const& text : block->children) { - if(text->kind != doc::Kind::copied) + if (!IsA(text)) + { continue; - auto* copy = static_cast(text.get()); - if(copy->id && - (copy->parts == doc::Parts::all || - copy->parts == doc::Parts::description)) + } + if (auto const* copied = dynamic_cast(text.operator->()); + copied->id && + (copied->parts == doc::Parts::all || + copied->parts == doc::Parts::description)) { - if(auto& jd = corpus.get(copy->id).javadoc) + if (auto& jd = corpus.get(copied->id).javadoc) + { return jd->getDescription(corpus); + } } } } @@ -215,11 +179,9 @@ getDescription(Corpus const& corpus) const noexcept bool Javadoc:: -operator==( - Javadoc const& other) const noexcept +operator==(Javadoc const& other) const noexcept { - return std::equal(blocks_.begin(), blocks_.end(), - other.blocks_.begin(), other.blocks_.end(), + return std::ranges::equal(blocks_, other.blocks_, [](const auto& a, const auto& b) { return a->equals(static_cast(*b)); @@ -264,39 +226,39 @@ makeOverview( case doc::Kind::brief: break; case doc::Kind::returns: - ov.returns = static_cast< - doc::Returns const*>(it->get()); + ov.returns = dynamic_cast< + doc::Returns const*>(it->operator->()); break; case doc::Kind::param: - ov.params.push_back(static_cast< - doc::Param const*>(it->get())); + ov.params.push_back(dynamic_cast< + doc::Param const*>(it->operator->())); break; case doc::Kind::tparam: - ov.tparams.push_back(static_cast< - doc::TParam const*>(it->get())); + ov.tparams.push_back(dynamic_cast< + doc::TParam const*>(it->operator->())); break; case doc::Kind::throws: - ov.exceptions.push_back(static_cast< - doc::Throws const*>(it->get())); + ov.exceptions.push_back(dynamic_cast< + doc::Throws const*>(it->operator->())); break; case doc::Kind::see: - ov.sees.push_back(static_cast< - doc::See const*>(it->get())); + ov.sees.push_back(dynamic_cast< + doc::See const*>(it->operator->())); break; case doc::Kind::precondition: - ov.preconditions.push_back(static_cast< - doc::Precondition const*>(it->get())); + ov.preconditions.push_back(dynamic_cast< + doc::Precondition const*>(it->operator->())); break; case doc::Kind::postcondition: - ov.postconditions.push_back(static_cast< - doc::Postcondition const*>(it->get())); + ov.postconditions.push_back(dynamic_cast< + doc::Postcondition const*>(it->operator->())); break; default: - if (briefP == it->get()) + if (briefP == it->operator->()) { break; } - ov.blocks.push_back(it->get()); + ov.blocks.push_back(it->operator->()); } } @@ -306,7 +268,7 @@ makeOverview( std::string Javadoc:: emplace_back( - std::unique_ptr block) + PolymorphicValue block) { MRDOCS_ASSERT(block->isBlock()); @@ -316,12 +278,12 @@ emplace_back( case doc::Kind::param: { // check for duplicate parameter name - auto t = static_cast(block.get()); + auto t = dynamic_cast(block.operator->()); for(auto const& q : blocks_) { if(q->kind == doc::Kind::param) { - auto u = static_cast(q.get()); + auto u = dynamic_cast(q.operator->()); if(u->name == t->name) { result = fmt::format( @@ -335,12 +297,12 @@ emplace_back( case doc::Kind::tparam: { // check for duplicate template parameter name - auto t = static_cast(block.get()); + auto t = dynamic_cast(block.operator->()); for(auto const& q : blocks_) { if(q->kind == doc::Kind::tparam) { - auto u = static_cast(q.get()); + auto u = dynamic_cast(q.operator->()); if(u->name == t->name) { result = fmt::format( @@ -372,19 +334,20 @@ append( void Javadoc:: -append(doc::List&& blocks) +append(std::vector>&& blocks) { blocks_.reserve(blocks_.size() + blocks.size()); - for(auto&& block : blocks) - emplace_back(std::unique_ptr( - static_cast(block.release()))); - #if 0 + for(auto&& blockAsNode : blocks) { - MRDOCS_ASSERT(block->isBlock()); - blocks_.emplace_back( - static_cast(block.release())); + if (IsA(blockAsNode)) + { + emplace_back(DynamicCast(std::move(blockAsNode))); + } + else + { + blockAsNode = {}; + } } - #endif } /** Return the Javadoc as a @ref dom::Value. diff --git a/src/lib/Metadata/Name.cpp b/src/lib/Metadata/Name.cpp index c883795139..aab1cb8dcb 100644 --- a/src/lib/Metadata/Name.cpp +++ b/src/lib/Metadata/Name.cpp @@ -40,13 +40,26 @@ writeTo( (result += ... += args); } +std::strong_ordering +NameInfo:: +operator<=>(NameInfo const& other) const +{ + auto const r = std::tie(Kind, id, Name) <=> + std::tie(other.Kind, other.id, other.Name); + if (!std::is_eq(r)) + { + return r; + } + return visit(other, detail::VisitCompareFn{other}); +} + static void toStringImpl( std::string& result, const NameInfo& N) { - if(N.Prefix) + if (N.Prefix) { toStringImpl(result, *N.Prefix); writeTo(result, "::"); @@ -54,10 +67,12 @@ toStringImpl( writeTo(result, N.Name); - if(! N.isSpecialization()) + if (!N.isSpecialization()) + { return; - std::span> targs = - static_cast(N).TemplateArgs; + } + auto const& NN = dynamic_cast(N); + std::span const targs = NN.TemplateArgs; writeTo(result, '<'); if(! targs.empty()) { diff --git a/src/lib/Metadata/Namespace.cpp b/src/lib/Metadata/Namespace.cpp deleted file mode 100644 index e856711892..0000000000 --- a/src/lib/Metadata/Namespace.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// -// This is a derivative work. originally part of the LLVM Project. -// 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) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Official repository: https://github.com/cppalliance/mrdocs -// - -#include "Reduce.hpp" -#include "lib/Support/Debug.hpp" -#include -#include -#include -#include - -namespace clang { -namespace mrdocs { - -} // mrdocs -} // clang diff --git a/src/lib/Metadata/Type.cpp b/src/lib/Metadata/Type.cpp index 1158d5f5f4..5aa8921246 100644 --- a/src/lib/Metadata/Type.cpp +++ b/src/lib/Metadata/Type.cpp @@ -87,7 +87,7 @@ namedSymbol() const noexcept { return SymbolID::invalid; } - auto const* NT = static_cast(this); + auto const* NT = dynamic_cast(this); if (!NT->Name) { return SymbolID::invalid; @@ -144,13 +144,16 @@ inline void TypeBeforeWriter:: operator()( - const T& t, + T const& t, auto& write, std::bool_constant) const { - if(TypeInfo* inner = t.innerType()) - visit(*inner, *this, write, std::bool_constant< - requires { t.PointeeType; }>{}); + if (TypeInfo const* inner = t.cInnerType()) + { + visit(*inner, *this, write, std::bool_constant{}); + } if(t.IsPackExpansion) write("..."); @@ -276,9 +279,12 @@ operator()( write(' ', spec); } - if(TypeInfo* inner = t.innerType()) - visit(*inner, *this, write, std::bool_constant< - requires { t.PointeeType; }>{}); + if (TypeInfo const* inner = t.cInnerType()) + { + visit(*inner, *this, write, std::bool_constant{}); + } } void @@ -291,6 +297,23 @@ writeTypeTo( } // (anon) +std::strong_ordering +NamedTypeInfo:: +operator<=>(NamedTypeInfo const& other) const +{ + if (auto const br = dynamic_cast(*this) <=> dynamic_cast(other); + !std::is_eq(br)) + { + return br; + } + if (auto const br = CVQualifiers <=> other.CVQualifiers; + !std::is_eq(br)) + { + return br; + } + return Name <=> other.Name; +} + std::string toString( const TypeInfo& T, diff --git a/src/lib/Metadata/Typedef.cpp b/src/lib/Metadata/Typedef.cpp deleted file mode 100644 index 4b2bbed51c..0000000000 --- a/src/lib/Metadata/Typedef.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// -// This is a derivative work. originally part of the LLVM Project. -// 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) 2023 Vinnie Falco (vinnie.falco@gmail.com) -// -// Official repository: https://github.com/cppalliance/mrdocs -// - -#include - -namespace clang { -namespace mrdocs { - -} // mrdocs -} // clang diff --git a/src/lib/Support/Debug.cpp b/src/lib/Support/Debug.cpp index a81543f952..cc100eb183 100644 --- a/src/lib/Support/Debug.cpp +++ b/src/lib/Support/Debug.cpp @@ -11,10 +11,10 @@ #include "lib/Support/Debug.hpp" #include "lib/Support/Radix.hpp" +#include +#include #include -#include #include -#include namespace clang { namespace mrdocs { diff --git a/src/lib/Support/Debug.hpp b/src/lib/Support/Debug.hpp index 8b81af33c5..4c2930e620 100644 --- a/src/lib/Support/Debug.hpp +++ b/src/lib/Support/Debug.hpp @@ -17,10 +17,10 @@ #include #endif #include - +#include +#include #include #include -#include template<> struct fmt::formatter @@ -61,8 +61,7 @@ struct fmt::formatter // Some nice odds and ends such as leak checking // and redirection to the Visual Studio output window. -namespace clang { -namespace mrdocs { +namespace clang::mrdocs { /** Enable debug heap checking. */ @@ -71,7 +70,6 @@ MRDOCS_DECL void debugEnableHeapChecking(); #define static_error(msg, value) \ static_assert(!std::is_same_v,msg) -} // mrdocs -} // clang +} // clang::mrdocs #endif diff --git a/src/lib/Support/LegibleNames.hpp b/src/lib/Support/LegibleNames.hpp index b02707e01d..daacd01e0d 100644 --- a/src/lib/Support/LegibleNames.hpp +++ b/src/lib/Support/LegibleNames.hpp @@ -11,8 +11,8 @@ #ifndef MRDOCS_LIB_SUPPORT_LEGIBLENAMES_HPP #define MRDOCS_LIB_SUPPORT_LEGIBLENAMES_HPP -#include #include +#include #include #include diff --git a/src/test/ADT/PolymorphicValue.cpp b/src/test/ADT/PolymorphicValue.cpp new file mode 100644 index 0000000000..6dc8d18442 --- /dev/null +++ b/src/test/ADT/PolymorphicValue.cpp @@ -0,0 +1,585 @@ +// +// 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) 2024 Alan de Freitas (alandefreitas@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include +#include + +namespace clang::mrdocs { + +struct X { + virtual ~X() = default; + + int a{42}; +}; + +struct Y : X { + int b{43}; +}; + +struct Z : X { + int c{44}; +}; + +struct PolymorphicValue_test +{ + static + void + testConstructors() + { + // default constructor + { + PolymorphicValue constexpr v; + BOOST_TEST_NOT(v); + } + + // nullptr constructor + { + PolymorphicValue constexpr v(nullptr); + BOOST_TEST_NOT(v); + } + + // from derived object + { + PolymorphicValue x(Y{}); + BOOST_TEST(x); + BOOST_TEST(x->a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + } + + // from pointer + { + PolymorphicValue x(new Y); + BOOST_TEST(x); + BOOST_TEST(x->a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + } + + // from nullptr pointer + { + X* p = nullptr; + PolymorphicValue const x(p); + BOOST_TEST_NOT(x); + } + + // from pointer different from Derived + { + Y* p = new Y{}; + X* p2 = p; + BOOST_TEST_THROWS(PolymorphicValue(p2), BadPolymorphicValueConstruction); + } + + // from pointer and copier + { + auto copier = [](Y const& y) -> Y* { auto el = new Y(y); el->b = 44; return el; }; + PolymorphicValue x(new Y, copier); + BOOST_TEST(x); + BOOST_TEST(x->a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + + PolymorphicValue x2(x); + BOOST_TEST(x2); + BOOST_TEST(x2->a == 42); + BOOST_TEST(dynamic_cast(&*x2)->b == 44); + } + + // from pointer, copier and deleter + { + auto copier = [](Y const& y) -> Y* { auto el = new Y(y); el->b = 44; return el; }; + auto deleter = [](Y const* y) { delete y; }; + PolymorphicValue x(new Y, copier, deleter); + BOOST_TEST(x); + BOOST_TEST(x->a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + + PolymorphicValue x2(x); + BOOST_TEST(x2); + BOOST_TEST(x2->a == 42); + BOOST_TEST(dynamic_cast(&*x2)->b == 44); + } + + // Copy constructor + { + // from empty + { + PolymorphicValue x; + PolymorphicValue y(x); + BOOST_TEST_NOT(y); + } + + // from valid + { + PolymorphicValue x(new Y); + x->a = 45; + PolymorphicValue y(x); + BOOST_TEST(y); + BOOST_TEST(y->a == 45); + BOOST_TEST(dynamic_cast(&*y)->b == 43); + } + } + + // Move constructor + { + PolymorphicValue x(new Y); + x->a = 45; + PolymorphicValue y(std::move(x)); + BOOST_TEST_NOT(x); + BOOST_TEST(y); + BOOST_TEST(y->a == 45); + BOOST_TEST(dynamic_cast(&*y)->b == 43); + } + + // Copy from derived value constructor + { + // from empty + { + PolymorphicValue x; + PolymorphicValue y(x); + BOOST_TEST_NOT(y); + } + + // from valid + { + PolymorphicValue x(new Y); + x->a = 45; + PolymorphicValue y(x); + BOOST_TEST(y); + BOOST_TEST(y->a == 45); + BOOST_TEST(dynamic_cast(&*y)->b == 43); + } + } + + // Move from derived constructor + { + // from empty + { + PolymorphicValue x; + PolymorphicValue y(std::move(x)); + BOOST_TEST_NOT(y); + } + + // from valid + { + PolymorphicValue x(new Y); + x->a = 45; + PolymorphicValue y(std::move(x)); + BOOST_TEST_NOT(x); + BOOST_TEST(y); + BOOST_TEST(y->a == 45); + BOOST_TEST(dynamic_cast(&*y)->b == 43); + } + } + + // In-place constructor + { + PolymorphicValue x(std::in_place_type); + BOOST_TEST(x); + BOOST_TEST(x->a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + } + } + + static + void + testAssignment() + { + // copy assignment + { +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#endif +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wself-move" +#endif + // from same + { + PolymorphicValue lhs(new Y); + lhs = lhs; + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 42); + } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + // from empty + { + PolymorphicValue lhs; + PolymorphicValue rhs; + lhs = rhs; + BOOST_TEST_NOT(lhs); + } + + // from valid + { + PolymorphicValue lhs(new Y); + lhs->a = 45; + PolymorphicValue rhs(new Y); + rhs->a = 46; + BOOST_TEST(lhs->a == 45); + BOOST_TEST(rhs->a == 46); + lhs = rhs; + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 46); + BOOST_TEST(rhs->a == 46); + BOOST_TEST(get(lhs).b == 43); + } + } + + // copy assignment + { +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#endif +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wself-move" +#endif + // from same + { + PolymorphicValue lhs(new Y); + lhs = std::move(lhs); + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 42); + } +#if defined(__clang__) +#pragma clang diagnostic pop +#endif +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + // from empty + { + PolymorphicValue lhs; + PolymorphicValue rhs; + lhs = std::move(rhs); + BOOST_TEST_NOT(lhs); + BOOST_TEST_NOT(rhs); + } + + // from valid + { + PolymorphicValue lhs(new Y); + lhs->a = 45; + PolymorphicValue rhs(new Y); + rhs->a = 46; + BOOST_TEST(lhs->a == 45); + BOOST_TEST(rhs->a == 46); + lhs = std::move(rhs); + BOOST_TEST(lhs->a == 46); + BOOST_TEST_NOT(rhs); + BOOST_TEST(get(lhs).b == 43); + } + } + + // copy from derived + { + PolymorphicValue lhs(new Y); + lhs->a = 45; + Y rhs; + rhs.a = 46; + BOOST_TEST(lhs->a == 45); + BOOST_TEST(rhs.a == 46); + lhs = rhs; + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 46); + BOOST_TEST(get(lhs).b == 43); + } + + // copy from derived + { + PolymorphicValue lhs(new Y); + lhs->a = 45; + Y rhs; + rhs.a = 46; + BOOST_TEST(lhs->a == 45); + BOOST_TEST(rhs.a == 46); + lhs = std::move(rhs); + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 46); + BOOST_TEST(get(lhs).b == 43); + } + } + + static + void + testDereference() + { + // from derived object + { + PolymorphicValue x(Y{}); + BOOST_TEST((*x).a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + } + + // from pointer + { + PolymorphicValue x(new Y); + BOOST_TEST((*x).a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + } + } + + static + void + testMake() + { + // MakePolymorphicValue(args...) + { + auto x = MakePolymorphicValue(); + BOOST_TEST(x); + BOOST_TEST(x->a == 42); + BOOST_TEST(dynamic_cast(&*x)->b == 43); + } + } + + static + void + testDynamicCast() + { + // from valid + { + PolymorphicValue x(new Y); + auto y = DynamicCast(std::move(x)); + BOOST_TEST(y); + BOOST_TEST(y->a == 42); + BOOST_TEST(y->b == 43); + } + + // from empty + { + PolymorphicValue x; + auto y = DynamicCast(std::move(x)); + BOOST_TEST_NOT(y); + } + + // from invalid derived type + { + PolymorphicValue x(new Z); + auto y = DynamicCast(std::move(x)); + BOOST_TEST_NOT(y); + } + } + + static + void + testSwap() + { + // default constructor + { + PolymorphicValue lhs; + PolymorphicValue rhs(new Y); + swap(lhs, rhs); + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 42); + BOOST_TEST(dynamic_cast(&*lhs)->b == 43); + BOOST_TEST_NOT(rhs); + } + + // rhs: default constructor + { + PolymorphicValue lhs(new Y); + PolymorphicValue rhs; + swap(lhs, rhs); + BOOST_TEST_NOT(lhs); + BOOST_TEST(rhs); + BOOST_TEST(rhs->a == 42); + BOOST_TEST(dynamic_cast(&*rhs)->b == 43); + } + + // lhs: from derived object + { + PolymorphicValue lhs(Y{}); + PolymorphicValue rhs(new Y); + swap(lhs, rhs); + BOOST_TEST(rhs); + BOOST_TEST(rhs->a == 42); + BOOST_TEST(dynamic_cast(&*rhs)->b == 43); + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 42); + BOOST_TEST(dynamic_cast(&*lhs)->b == 43); + } + + // rhs: from derived object + { + PolymorphicValue lhs(new Y); + PolymorphicValue rhs(Y{}); + swap(lhs, rhs); + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 42); + BOOST_TEST(dynamic_cast(&*lhs)->b == 43); + BOOST_TEST(rhs); + BOOST_TEST(rhs->a == 42); + BOOST_TEST(dynamic_cast(&*rhs)->b == 43); + } + + // lhs: from pointer + { + PolymorphicValue lhs(new Y); + PolymorphicValue rhs(new Y); + swap(lhs, rhs); + BOOST_TEST(rhs); + BOOST_TEST(rhs->a == 42); + BOOST_TEST(dynamic_cast(&*rhs)->b == 43); + BOOST_TEST(lhs); + BOOST_TEST(lhs->a == 42); + BOOST_TEST(dynamic_cast(&*lhs)->b == 43); + } + } + + static + void + testIsA() + { + // IsA(x) + { + PolymorphicValue const x(new Y); + BOOST_TEST(IsA(x)); + BOOST_TEST(IsA(x)); + } + + // Empty state + { + PolymorphicValue const x; + BOOST_TEST_NOT(IsA(x)); + BOOST_TEST_NOT(IsA(x)); + } + } + + static + void + testGet() + { + // from mutable + { + PolymorphicValue x(new Y); + + // to mutable derived + { + // get(x) + { + get(x).a = 30; + BOOST_TEST(get(x).a == 30); + get(x).b = 31; + BOOST_TEST(get(x).b == 31); + } + + // get(x) + { + get(x).a = 32; + BOOST_TEST(get(x).a == 32); + get(x).b = 33; + BOOST_TEST(get(x).b == 33); + } + + // get(x) + { + get(x)->a = 34; + BOOST_TEST(get(x)->a == 34); + get(x)->b = 35; + BOOST_TEST(get(x)->b == 35); + } + } + + // to const derived + { + // get(x) + { + BOOST_TEST(get(x).a == 34); + BOOST_TEST(get(x).b == 35); + } + + // get(x) + { + BOOST_TEST(get(x).a == 34); + BOOST_TEST(get(x).b == 35); + } + + // get(x) + { + BOOST_TEST(get(x)->a == 34); + BOOST_TEST(get(x)->b == 35); + } + } + } + + // from const + { + PolymorphicValue const x(new Y); + + // to mutable derived (returns const anyway) + { + // get(x) + { + BOOST_TEST(get(x).a == 42); + BOOST_TEST(get(x).b == 43); + } + + // get(x) + { + BOOST_TEST(get(x).a == 42); + BOOST_TEST(get(x).b == 43); + } + + // get(x) + { + BOOST_TEST(get(x)->a == 42); + BOOST_TEST(get(x)->b == 43); + } + } + + // to const derived + { + // get(x) + { + BOOST_TEST(get(x).a == 42); + BOOST_TEST(get(x).b == 43); + } + + // get(x) + { + BOOST_TEST(get(x).a == 42); + BOOST_TEST(get(x).b == 43); + } + + // get(x) + { + BOOST_TEST(get(x)->a == 42); + BOOST_TEST(get(x)->b == 43); + } + } + } + } + + void + run() + { + testConstructors(); + testAssignment(); + testDereference(); + testMake(); + testDynamicCast(); + testSwap(); + testIsA(); + testGet(); + } +}; + +TEST_SUITE( + PolymorphicValue_test, + "clang.mrdocs.ADT.PolymorphicValue"); + +} // clang::mrdocs + diff --git a/test-files/golden-tests/metadata/explicit-deduct-guide.adoc b/test-files/golden-tests/metadata/explicit-deduct-guide.adoc index 151005c0bb..70e63601e6 100644 --- a/test-files/golden-tests/metadata/explicit-deduct-guide.adoc +++ b/test-files/golden-tests/metadata/explicit-deduct-guide.adoc @@ -43,7 +43,7 @@ struct X; -[#X-0d] +[#X-06] == <><0> @@ -54,10 +54,11 @@ Declared in `<explicit‐deduct‐guide.cpp>` [source,cpp,subs="verbatim,replacements,macros,-callouts"] ---- -<><0>(bool) -> <><0>; +template<bool B = true> +<><0>(long) -> <><0>; ---- -[#X-00] +[#X-0d] == <><0> @@ -68,10 +69,10 @@ Declared in `<explicit‐deduct‐guide.cpp>` [source,cpp,subs="verbatim,replacements,macros,-callouts"] ---- -<><0>(char) -> <><0>; +<><0>(bool) -> <><0>; ---- -[#X-0b] +[#X-00] == <><0> @@ -82,10 +83,10 @@ Declared in `<explicit‐deduct‐guide.cpp>` [source,cpp,subs="verbatim,replacements,macros,-callouts"] ---- -<><0>(int) -> <><0>; +<><0>(char) -> <><0>; ---- -[#X-06] +[#X-0b] == <><0> @@ -96,8 +97,7 @@ Declared in `<explicit‐deduct‐guide.cpp>` [source,cpp,subs="verbatim,replacements,macros,-callouts"] ---- -template<bool B = true> -<><0>(long) -> <><0>; +<><0>(int) -> <><0>; ---- diff --git a/test-files/golden-tests/metadata/explicit-deduct-guide.html b/test-files/golden-tests/metadata/explicit-deduct-guide.html index 704463abd5..976359c66d 100644 --- a/test-files/golden-tests/metadata/explicit-deduct-guide.html +++ b/test-files/golden-tests/metadata/explicit-deduct-guide.html @@ -57,7 +57,7 @@

Synopsis

-

X<0>

+

X<0>

Synopsis

@@ -65,14 +65,15 @@

Synopsis

Declared in <explicit-deduct-guide.cpp>
 
-X<0>(bool) -> X<0>;
+template<bool B = true>
+X<0>(long) -> X<0>;
 
 
-

X<0>

+

X<0>

Synopsis

@@ -80,14 +81,14 @@

Synopsis

Declared in <explicit-deduct-guide.cpp>
 
-X<0>(char) -> X<0>;
+X<0>(bool) -> X<0>;
 
 
-

X<0>

+

X<0>

Synopsis

@@ -95,14 +96,14 @@

Synopsis

Declared in <explicit-deduct-guide.cpp>
 
-X<0>(int) -> X<0>;
+X<0>(char) -> X<0>;
 
 
-

X<0>

+

X<0>

Synopsis

@@ -110,8 +111,7 @@

Synopsis

Declared in <explicit-deduct-guide.cpp>
 
-template<bool B = true>
-X<0>(long) -> X<0>;
+X<0>(int) -> X<0>;
 
 
diff --git a/util/generate-yaml-schema.py b/util/generate-yaml-schema.py index a15d51fc43..86a9b5838f 100644 --- a/util/generate-yaml-schema.py +++ b/util/generate-yaml-schema.py @@ -49,7 +49,7 @@ def to_yaml_schema_type(option: Option) -> SchemaType: option_type = option["type"] if option_type == "bool": - return {"type": "boolean"} + return {"type": "boolean", "enum": [True, False]} if option_type == "int": return {"type": "integer"} if option_type == "unsigned":