diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d2bcd3df4..fd702190d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -433,6 +433,44 @@ jobs: run: | rm -r ../third-party/llvm-project + - name: Install Boost.Mp11 + uses: alandefreitas/cpp-actions/cmake-workflow@v1.8.12 + with: + source-dir: ../third-party/boost_mp11 + git-repository: https://github.com/boostorg/mp11 + git-tag: boost-1.90.0 + patches: | + ./third-party/patches/boost_mp11/CMakeLists.txt + ./third-party/patches/boost_mp11/boost_mp11-config.cmake.in + build-dir: ${sourceDir}/build + cc: ${{ steps.setup-cpp.outputs.cc }} + cxx: ${{ steps.setup-cpp.outputs.cxx }} + build-type: Release + shared: false + install: true + install-prefix: ${sourceDir}/install + run-tests: false + trace-commands: true + + - name: Install Boost.Describe + uses: alandefreitas/cpp-actions/cmake-workflow@v1.8.12 + with: + source-dir: ../third-party/boost_describe + git-repository: https://github.com/boostorg/describe + git-tag: boost-1.90.0 + patches: | + ./third-party/patches/boost_describe/CMakeLists.txt + ./third-party/patches/boost_describe/boost_describe-config.cmake.in + build-dir: ${sourceDir}/build + cc: ${{ steps.setup-cpp.outputs.cc }} + cxx: ${{ steps.setup-cpp.outputs.cxx }} + build-type: Release + shared: false + install: true + install-prefix: ${sourceDir}/install + run-tests: false + trace-commands: true + - name: Install JerryScript uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.2 with: @@ -567,6 +605,8 @@ jobs: -D LUA_ROOT="${{ steps.rmatrix.outputs.third-party-dir }}/lua/install" -D Lua_ROOT="${{ steps.rmatrix.outputs.third-party-dir }}/lua/install" -D lua_ROOT="${{ steps.rmatrix.outputs.third-party-dir }}/lua/install" + -D boost_mp11_ROOT="${{ steps.rmatrix.outputs.third-party-dir }}/boost_mp11/install" + -D boost_describe_ROOT="${{ steps.rmatrix.outputs.third-party-dir }}/boost_describe/install" ${{ runner.os == 'Windows' && '-D LibXml2_ROOT=../third-party/libxml2/install' || '' }} export-compile-commands: true run-tests: true @@ -575,7 +615,7 @@ jobs: package-dir: packages package-generators: ${{ matrix.mrdocs-package-generators }} package-artifact: false - ctest-timeout: 3600 + ctest-timeout: 9000 - name: Check YAML schema run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bac1935cd..3b3f30e68f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,10 @@ endif() set(CMAKE_FOLDER Dependencies) +# Boost.Describe + Boost.Mp11 (header-only, fetched via bootstrap.py recipes) +find_package(boost_mp11 REQUIRED) +find_package(boost_describe REQUIRED) + # LLVM + Clang if (LLVM_ROOT) # LLVM_ROOT is absolute @@ -320,6 +324,7 @@ target_compile_definitions( PRIVATE -DMRDOCS_TOOL ) +target_link_libraries(mrdocs-core PRIVATE Boost::describe Boost::mp11) # Dependencies target_include_directories(mrdocs-core diff --git a/docs/mrdocs.yml b/docs/mrdocs.yml index 7692b1090e..f40f0ffdd8 100644 --- a/docs/mrdocs.yml +++ b/docs/mrdocs.yml @@ -13,6 +13,14 @@ implementation-defined: - 'mrdocs::detail' - 'mrdocs::report::detail' - 'mrdocs::dom::detail' +exclude-symbols: + # Symbols defined when using the Boost.Describe macros. + - 'mrdocs::**::boost_base_descriptor_fn' + - 'mrdocs::**::boost_public_member_descriptor_fn' + - 'mrdocs::**::boost_protected_member_descriptor_fn' + - 'mrdocs::**::boost_private_member_descriptor_fn' + - 'mrdocs::**::boost_enum_descriptor_fn' + - 'mrdocs::**::should_use_BOOST_DESCRIBE_NESTED_ENUM' multipage: true generator: adoc cmake: '-D MRDOCS_DOCUMENTATION_BUILD=ON' diff --git a/include/mrdocs/Dom/LazyObject.hpp b/include/mrdocs/Dom/LazyObject.hpp index 6554e7b099..9d22174437 100644 --- a/include/mrdocs/Dom/LazyObject.hpp +++ b/include/mrdocs/Dom/LazyObject.hpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -15,8 +16,10 @@ #include #include #include +#include -namespace mrdocs::dom { +namespace mrdocs { +namespace dom { namespace detail { @@ -36,7 +39,92 @@ namespace detail /* A helper empty struct */ struct NoLazyObjectContext { }; -} + + /* The IO object for lazy objects. + + Mapping traits use this object to call the + map and defer methods, which are used to + access properties of the lazy object. + + Each function provides different behavior + to `map` and `defer` methods, allowing + to implement functionality such as + `get`, `set`, `visit`, and `size`. + + In some cases, only a function for + `map` is provided, and the `defer` function + is not used. In this case, the `defer` function + also uses the `map` function, which is + the default behavior. + + In other cases, the `defer` function is + used to defer the evaluation of a property + to a later time, which is useful for functionality + that requires accessing the value. + */ + template + class LazyObjectIO + { + MapFn mapFn; + DeferFn deferFn; + Context ctx; + + public: + explicit + LazyObjectIO(MapFn mapFn, DeferFn deferFn = {}, Context ctx = {}) + : mapFn(mapFn), deferFn(deferFn), ctx(ctx) {} + + template + void + map(std::string_view name, T const& value) + { + if constexpr (std::is_same_v) + { + mapFn(name, dom::ValueFrom(value)); + } + else + { + mapFn(name, dom::ValueFrom(value, ctx)); + } + } + + template + void + defer(std::string_view name, F&& deferred) + { + if constexpr (std::same_as) + { + mapFn(name, deferred); + } + else if (!deferFn) + { + mapFn(name, deferred); + } + else + { + deferFn(name, deferred); + } + } + }; + + // Deduction guides. + template + LazyObjectIO(MapFn, DeferFn, Context) -> LazyObjectIO; + + template + LazyObjectIO(MapFn, DeferFn) -> LazyObjectIO; + + template + LazyObjectIO(MapFn) -> LazyObjectIO; + + // Type-erased LazyObjectIO type alias template. + template + using TypeErasedLazyObjectIO = LazyObjectIO< + std::function, + std::function)>, + Context>; + +} // namespace detail /** Customization point tag. @@ -166,6 +254,12 @@ class LazyObjectImpl : public ObjectImpl Object overlay_; MRDOCS_NO_UNIQUE_ADDRESS Context context_{}; + // Type alias for the type-erased IO used by this class. + using IOType = detail::TypeErasedLazyObjectIO; + + using MapFnType = std::function; + using DeferFnType = std::function const&)>; + public: /** Wrap an object using the default lazy mapping. @param obj Object providing the data. @@ -218,67 +312,6 @@ class LazyObjectImpl : public ObjectImpl exists(std::string_view key) const override; }; -namespace detail -{ - /* The IO object for lazy objects. - - Mapping traits use this object to call the - map and defer methods, which are used to - access properties of the lazy object. - - Each function provides different behavior - to `map` and `defer` methods, allowing - to implement functionality such as - `get`, `set`, `visit`, and `size`. - - In some cases, only a function for - `map` is provided, and the `defer` function - is not used. In this case, the `defer` function - also uses the `map` function, which is - the default behavior. - - In other cases, the `defer` function is - used to defer the evaluation of a property - to a later time, which is useful for functionality - that requires accessing the value. - */ - template - class LazyObjectIO - { - MapFn mapFn; - DeferFn deferFn; - public: - explicit - LazyObjectIO(MapFn mapFn, DeferFn deferFn = {}) - : mapFn(mapFn), deferFn(deferFn) {} - - template - void - map(std::string_view name, T const& value) - { - mapFn(name, value); - } - - template - void - defer(std::string_view name, F&& deferred) - { - if constexpr (std::same_as) - { - mapFn(name, deferred); - } - else - { - deferFn(name, deferred); - } - } - }; - - // Deduction guide - template - LazyObjectIO(MapFn, DeferFn = {}) -> LazyObjectIO; -} - template requires HasLazyObjectMap std::size_t @@ -286,11 +319,12 @@ LazyObjectImpl:: size() const { std::size_t result = 0; - detail::LazyObjectIO io( + MapFnType mapFn = [&result, this](std::string_view name, auto const& /* value or deferred */) { result += !overlay_.exists(name); - }); + }; + IOType io(mapFn, nullptr, context_); if constexpr (HasLazyObjectMapWithContext) { tag_invoke(LazyObjectMapTag{}, io, *underlying_, context_); @@ -313,14 +347,15 @@ exists(std::string_view key) const return true; } bool result = false; - detail::LazyObjectIO io( + MapFnType mapFn = [&result, key](std::string_view name, auto const& /* value or deferred */) { if (!result && name == key) { result = true; } - }); + }; + IOType io(mapFn, nullptr, context_); if constexpr (HasLazyObjectMapWithContext) { tag_invoke(LazyObjectMapTag{}, io, *underlying_, context_); @@ -344,7 +379,7 @@ get(std::string_view key) const return overlay_.get(key); } Value result; - detail::LazyObjectIO io( + IOType io( [&result, key, this](std::string_view name, auto const& value) { if (result.isUndefined() && name == key) @@ -371,7 +406,8 @@ get(std::string_view key) const ValueFrom(deferred(), result); } } - }); + }, + context_); if constexpr (HasLazyObjectMapWithContext) { tag_invoke(LazyObjectMapTag{}, io, *underlying_, context_); @@ -399,34 +435,22 @@ LazyObjectImpl:: visit(std::function fn) const { bool visitMore = true; - detail::LazyObjectIO io( - [&visitMore, &fn, this](std::string_view name, auto const& value) + MapFnType mapFn = + [&visitMore, &fn, this](std::string_view name, dom::Value const& value) + { + if (visitMore && !overlay_.exists(name)) { - if (visitMore && !overlay_.exists(name)) - { - if constexpr (HasValueFromWithContext, Context>) - { - visitMore = fn(name, dom::ValueFrom(value, context_)); - } - else - { - visitMore = fn(name, dom::ValueFrom(value)); - } - } - }, [&visitMore, &fn, this](std::string_view name, auto const& deferred) + visitMore = fn(String(name), value); + } + }; + DeferFnType deferFn = [&visitMore, &fn, this](std::string_view name, + std::function const& deferred) { + if (visitMore && !overlay_.exists(name)) { - if (visitMore && !overlay_.exists(name)) - { - if constexpr (HasValueFromWithContext, Context>) - { - visitMore = fn(name, dom::ValueFrom(deferred(), context_)); - } - else - { - visitMore = fn(name, dom::ValueFrom(deferred())); - } - } - }); + visitMore = fn(String(name), deferred()); + } + }; + IOType io(mapFn, deferFn, context_); if constexpr (HasLazyObjectMapWithContext) { tag_invoke(LazyObjectMapTag{}, io, *underlying_, context_); @@ -465,6 +489,24 @@ LazyObject(T const& arr, Context const& context) return newObject>(arr, context); } -} // mrdocs::dom +} // dom + +class DomCorpus; + +/** Type-erased IO type for lazy object mapping. + + This alias provides a concrete, non-template IO type + that can be used with `tag_invoke()` overloads for + @ref dom::LazyObjectMapTag. Unlike the internal template-based + IO types used within @ref dom::LazyObjectImpl, this type uses + `std::function` for type erasure, allowing it to be used in + explicit template instantiations. + + @see dom::LazyObjectImpl + @see dom::LazyObjectMapTag +*/ +using LazyObjectIOType = dom::detail::TypeErasedLazyObjectIO; + +} // mrdocs #endif // MRDOCS_API_DOM_LAZYOBJECT_HPP diff --git a/include/mrdocs/Metadata/DocComment.hpp b/include/mrdocs/Metadata/DocComment.hpp index d076ef035d..d3a9099b09 100644 --- a/include/mrdocs/Metadata/DocComment.hpp +++ b/include/mrdocs/Metadata/DocComment.hpp @@ -194,43 +194,7 @@ tag_invoke( dom::LazyObjectMapTag, IO& io, DocComment const& I, - DomCorpus const* domCorpus) -{ - io.defer("description", [&I, domCorpus] { - return dom::LazyArray(I.Document, domCorpus); - }); - if (I.brief && !I.brief->children.empty()) - { - io.map("brief", I.brief); - } - io.defer("returns", [&I, domCorpus] { - return dom::LazyArray(I.returns, domCorpus); - }); - io.defer("params", [&I, domCorpus] { - return dom::LazyArray(I.params, domCorpus); - }); - io.defer("tparams", [&I, domCorpus] { - return dom::LazyArray(I.tparams, domCorpus); - }); - io.defer("exceptions", [&I, domCorpus] { - return dom::LazyArray(I.exceptions, domCorpus); - }); - io.defer("sees", [&I, domCorpus] { - return dom::LazyArray(I.sees, domCorpus); - }); - io.defer("relates", [&I, domCorpus] { - return dom::LazyArray(I.relates, domCorpus); - }); - io.defer("related", [&I, domCorpus] { - return dom::LazyArray(I.related, domCorpus); - }); - io.defer("preconditions", [&I, domCorpus] { - return dom::LazyArray(I.preconditions, domCorpus); - }); - io.defer("postconditions", [&I, domCorpus] { - return dom::LazyArray(I.postconditions, domCorpus); - }); -} + DomCorpus const* domCorpus); /** Return the @ref DocComment as a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/DocComment/Inline/ImageInline.hpp b/include/mrdocs/Metadata/DocComment/Inline/ImageInline.hpp index 3a9c441e3c..750c61ad61 100644 --- a/include/mrdocs/Metadata/DocComment/Inline/ImageInline.hpp +++ b/include/mrdocs/Metadata/DocComment/Inline/ImageInline.hpp @@ -65,13 +65,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, ImageInline const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, dynamic_cast(I), domCorpus); - tag_invoke(t, io, dynamic_cast(I), domCorpus); - io.map("src", I.src); - io.map("alt", I.alt); -} + DomCorpus const* domCorpus); /** Return the @ref ImageInline as a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Expression.hpp b/include/mrdocs/Metadata/Expression.hpp index 871cd7447b..3fa4df5e60 100644 --- a/include/mrdocs/Metadata/Expression.hpp +++ b/include/mrdocs/Metadata/Expression.hpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -13,12 +14,16 @@ #include #include +#include +#include #include #include #include namespace mrdocs { +class DomCorpus; + /** Represents an expression */ struct ExprInfo @@ -90,6 +95,39 @@ static void merge( } } +/** Map an ExprInfo to a @ref dom::Value object. + + @param v The output parameter to receive the dom::Value. + @param expr The expression info to convert. +*/ +inline +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + ExprInfo const& expr, + DomCorpus const*) +{ + v = expr.Written; +} + +/** Map an ExprInfo to a @ref dom::Value object. + + @param v The output parameter to receive the dom::Value. + @param expr The expression info to convert. +*/ +inline +void +tag_invoke( + dom::LazyObjectMapTag, + dom::Value& v, + ExprInfo const& expr, + DomCorpus const* +) +{ + v = expr.Written; +} + } // mrdocs #endif diff --git a/include/mrdocs/Metadata/Symbol/Concept.hpp b/include/mrdocs/Metadata/Symbol/Concept.hpp index 4cbbf2de73..fd2ed4b1d0 100644 --- a/include/mrdocs/Metadata/Symbol/Concept.hpp +++ b/include/mrdocs/Metadata/Symbol/Concept.hpp @@ -68,15 +68,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, ConceptSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("template", I.Template); - if (!I.Constraint.Written.empty()) - { - io.map("constraint", I.Constraint.Written); - } -} + DomCorpus const* domCorpus); /** Map the ConceptSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/Enum.hpp b/include/mrdocs/Metadata/Symbol/Enum.hpp index ddcad03dcd..9a36db2f9f 100644 --- a/include/mrdocs/Metadata/Symbol/Enum.hpp +++ b/include/mrdocs/Metadata/Symbol/Enum.hpp @@ -95,13 +95,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, EnumSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("type", I.UnderlyingType); - io.map("isScoped", I.Scoped); - io.map("constants", dom::LazyArray(I.Constants, domCorpus)); -} + DomCorpus const* domCorpus); /** Map the EnumSymbol to a @ref dom::Value object. diff --git a/include/mrdocs/Metadata/Symbol/EnumConstant.hpp b/include/mrdocs/Metadata/Symbol/EnumConstant.hpp index db5f8d699f..ef2b5b7c60 100644 --- a/include/mrdocs/Metadata/Symbol/EnumConstant.hpp +++ b/include/mrdocs/Metadata/Symbol/EnumConstant.hpp @@ -57,14 +57,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, EnumConstantSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - if (!I.Initializer.Written.empty()) - { - io.map("initializer", I.Initializer.Written); - } -} + DomCorpus const* domCorpus); /** Map the EnumConstantSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/ExtractionMode.hpp b/include/mrdocs/Metadata/Symbol/ExtractionMode.hpp index dde53bade7..7b40b3f542 100644 --- a/include/mrdocs/Metadata/Symbol/ExtractionMode.hpp +++ b/include/mrdocs/Metadata/Symbol/ExtractionMode.hpp @@ -5,6 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -54,37 +55,13 @@ enum class ExtractionMode Dependency, }; -/** Return the name of the SymbolKind as a string. -*/ -constexpr -std::string_view -toString(ExtractionMode kind) noexcept -{ - switch(kind) - { - case ExtractionMode::Regular: - return "regular"; - case ExtractionMode::SeeBelow: - return "see-below"; - case ExtractionMode::ImplementationDefined: - return "implementation-defined"; - case ExtractionMode::Dependency: - return "dependency"; - } - MRDOCS_UNREACHABLE(); -} - /** Return the SymbolKind from a @ref dom::Value string. */ -inline void tag_invoke( dom::ValueFromTag, dom::Value& v, - ExtractionMode kind) -{ - v = toString(kind); -} + ExtractionMode kind); /** Compare ExtractionModes and returns the least specific diff --git a/include/mrdocs/Metadata/Symbol/FileKind.hpp b/include/mrdocs/Metadata/Symbol/FileKind.hpp index f697b8d73e..312d7eb690 100644 --- a/include/mrdocs/Metadata/Symbol/FileKind.hpp +++ b/include/mrdocs/Metadata/Symbol/FileKind.hpp @@ -6,6 +6,7 @@ // // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -32,27 +33,15 @@ enum class FileKind Other }; -/** Convert a FileKind to its string form. - @param kind File category to stringify. - @return String view describing the kind. -*/ -MRDOCS_DECL -std::string_view -toString(FileKind kind); - /** Map a FileKind into a DOM value. @param v Destination value to populate. @param kind File category to serialize. */ -inline void tag_invoke( dom::ValueFromTag, dom::Value& v, - FileKind kind) -{ - v = toString(kind); -} + FileKind kind); } // mrdocs diff --git a/include/mrdocs/Metadata/Symbol/Friend.hpp b/include/mrdocs/Metadata/Symbol/Friend.hpp index 3d1056afb2..ada06d97f4 100644 --- a/include/mrdocs/Metadata/Symbol/Friend.hpp +++ b/include/mrdocs/Metadata/Symbol/Friend.hpp @@ -61,23 +61,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, FriendInfo const& I, - DomCorpus const* domCorpus) -{ - if (I.id) - { - io.defer("name", [&I, domCorpus]{ - return dom::ValueFrom(I.id, domCorpus).get("name"); - }); - io.map("symbol", I.id); - } - else if (I.Type) - { - io.defer("name", [&]{ - return dom::ValueFrom(I.Type, domCorpus).get("name"); - }); - io.map("type", I.Type); - } -} + DomCorpus const* domCorpus); /** Map the FriendInfo to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/Function.hpp b/include/mrdocs/Metadata/Symbol/Function.hpp index 080bc720d4..60074089b4 100644 --- a/include/mrdocs/Metadata/Symbol/Function.hpp +++ b/include/mrdocs/Metadata/Symbol/Function.hpp @@ -7,6 +7,7 @@ // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) // Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -47,7 +48,7 @@ struct FunctionSymbol final Optional Template; /// The class of function this is - FunctionClass Class = FunctionClass::Normal; + FunctionClass FuncClass = FunctionClass::Normal; /** Exception specification for the function. */ @@ -163,50 +164,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, FunctionSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("isVariadic", I.IsVariadic); - io.map("isVirtual", I.IsVirtual); - io.map("isVirtualAsWritten", I.IsVirtualAsWritten); - io.map("isPure", I.IsPure); - io.map("isDefaulted", I.IsDefaulted); - io.map("isExplicitlyDefaulted", I.IsExplicitlyDefaulted); - io.map("isDeleted", I.IsDeleted); - io.map("isDeletedAsWritten", I.IsDeletedAsWritten); - io.map("isNoReturn", I.IsNoReturn); - io.map("hasOverrideAttr", I.HasOverrideAttr); - io.map("hasTrailingReturn", I.HasTrailingReturn); - io.map("isConst", I.IsConst); - io.map("isVolatile", I.IsVolatile); - io.map("isFinal", I.IsFinal); - io.map("isNodiscard", I.IsNodiscard); - io.map("isExplicitObjectMemberFunction", I.IsExplicitObjectMemberFunction); - if (I.Constexpr != ConstexprKind::None) - { - io.map("constexprKind", I.Constexpr); - } - if (I.StorageClass != StorageClassKind::None) - { - io.map("storageClass", I.StorageClass); - } - if (I.RefQualifier != ReferenceKind::None) - { - io.map("refQualifier", I.RefQualifier); - } - io.map("functionClass", I.Class); - io.map("params", dom::LazyArray(I.Params, domCorpus)); - io.map("return", I.ReturnType); - io.map("template", I.Template); - io.map("overloadedOperator", I.OverloadedOperator); - io.map("exceptionSpec", I.Noexcept); - io.map("explicitSpec", I.Explicit); - if (!I.Requires.Written.empty()) - { - io.map("requires", I.Requires.Written); - } - io.map("attributes", dom::LazyArray(I.Attributes)); -} + DomCorpus const* domCorpus); /** Map the FunctionSymbol to a @ref dom::Value object. @@ -225,6 +183,23 @@ tag_invoke( v = dom::LazyObject(I, domCorpus); } +/** Map a vector of parameters to a @ref dom::Value object. + + @param v The output parameter to receive the dom::Value. + @param params The list of parameters to convert. + @param domCorpus The DomCorpus used to resolve references. + */ +inline +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + std::vector const& params, + DomCorpus const* domCorpus) +{ + v = dom::LazyArray(params, domCorpus); +} + /** Determine if one function would override the other @param base The base function diff --git a/include/mrdocs/Metadata/Symbol/FunctionClass.hpp b/include/mrdocs/Metadata/Symbol/FunctionClass.hpp index e4ba48a5b8..a305edb0ac 100644 --- a/include/mrdocs/Metadata/Symbol/FunctionClass.hpp +++ b/include/mrdocs/Metadata/Symbol/FunctionClass.hpp @@ -7,6 +7,7 @@ // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) // Copyright (c) 2024 Alan de Freitas (alandefreitas@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -33,23 +34,13 @@ enum class FunctionClass Destructor }; -/** Convert a function class to string form. -*/ -MRDOCS_DECL -dom::String -toString(FunctionClass kind) noexcept; - /** Return the FunctionClass from a @ref dom::Value string. */ -inline void tag_invoke( dom::ValueFromTag, dom::Value& v, - FunctionClass const kind) -{ - v = toString(kind); -} + FunctionClass const kind); } // mrdocs diff --git a/include/mrdocs/Metadata/Symbol/Guide.hpp b/include/mrdocs/Metadata/Symbol/Guide.hpp index cc4a0e0d9e..5951afe549 100644 --- a/include/mrdocs/Metadata/Symbol/Guide.hpp +++ b/include/mrdocs/Metadata/Symbol/Guide.hpp @@ -81,14 +81,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, GuideSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("params", dom::LazyArray(I.Params, domCorpus)); - io.map("deduced", I.Deduced); - io.map("template", I.Template); - io.map("explicitSpec", I.Explicit); -} + DomCorpus const* domCorpus); /** Map the GuideSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/Namespace.hpp b/include/mrdocs/Metadata/Symbol/Namespace.hpp index 5f80e3f5f8..aec6084063 100644 --- a/include/mrdocs/Metadata/Symbol/Namespace.hpp +++ b/include/mrdocs/Metadata/Symbol/Namespace.hpp @@ -105,19 +105,7 @@ tag_invoke( dom::LazyObjectMapTag, IO& io, NamespaceTranche const& I, - DomCorpus const* domCorpus) -{ - io.map("namespaces", dom::LazyArray(I.Namespaces, domCorpus)); - io.map("namespaceAliases", dom::LazyArray(I.NamespaceAliases, domCorpus)); - io.map("typedefs", dom::LazyArray(I.Typedefs, domCorpus)); - io.map("records", dom::LazyArray(I.Records, domCorpus)); - io.map("enums", dom::LazyArray(I.Enums, domCorpus)); - io.map("functions", dom::LazyArray(I.Functions, domCorpus)); - io.map("variables", dom::LazyArray(I.Variables, domCorpus)); - io.map("concepts", dom::LazyArray(I.Concepts, domCorpus)); - io.map("guides", dom::LazyArray(I.Guides, domCorpus)); - io.map("usings", dom::LazyArray(I.Usings, domCorpus)); -} + DomCorpus const* domCorpus); /** Map the NamespaceTranche to a @ref dom::Value object. */ @@ -195,14 +183,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, NamespaceSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("isInline", I.IsInline); - io.map("isAnonymous", I.IsAnonymous); - io.map("members", I.Members); - io.map("usingDirectives", dom::LazyArray(I.UsingDirectives, domCorpus)); -} + DomCorpus const* domCorpus); /** Map the NamespaceSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/NamespaceAlias.hpp b/include/mrdocs/Metadata/Symbol/NamespaceAlias.hpp index a590ab7414..6218f435f1 100644 --- a/include/mrdocs/Metadata/Symbol/NamespaceAlias.hpp +++ b/include/mrdocs/Metadata/Symbol/NamespaceAlias.hpp @@ -59,11 +59,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, NamespaceAliasSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("aliasedSymbol", I.AliasedSymbol); -} + DomCorpus const* domCorpus); /** Map the NamespaceAliasSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/Overloads.hpp b/include/mrdocs/Metadata/Symbol/Overloads.hpp index 98022eed39..e23475d612 100644 --- a/include/mrdocs/Metadata/Symbol/Overloads.hpp +++ b/include/mrdocs/Metadata/Symbol/Overloads.hpp @@ -23,7 +23,7 @@ struct OverloadsSymbol final : SymbolCommonBase { /// The class of the functions. - FunctionClass Class = FunctionClass::Normal; + FunctionClass FuncClass = FunctionClass::Normal; /// The overloaded operator, if any. OperatorKind OverloadedOperator = OperatorKind::None; @@ -92,13 +92,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, OverloadsSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("class", I.Class); - io.map("overloadedOperator", I.OverloadedOperator); - io.map("members", dom::LazyArray(I.Members, domCorpus)); -} + DomCorpus const* domCorpus); /** Map the OverloadsSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/Record.hpp b/include/mrdocs/Metadata/Symbol/Record.hpp index 0f1df06316..cafcb5f1b5 100644 --- a/include/mrdocs/Metadata/Symbol/Record.hpp +++ b/include/mrdocs/Metadata/Symbol/Record.hpp @@ -135,19 +135,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, RecordSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("tag", I.KeyKind); - io.map("defaultAccess", getDefaultAccessString(I.KeyKind)); - io.map("isFinal", I.IsFinal); - io.map("isTypedef", I.IsTypeDef); - io.map("bases", dom::LazyArray(I.Bases, domCorpus)); - io.map("derived", dom::LazyArray(I.Derived, domCorpus)); - io.map("interface", I.Interface); - io.map("template", I.Template); - io.map("friends", dom::LazyArray(I.Friends, domCorpus)); -} + DomCorpus const* domCorpus); /** Map the RecordSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/RecordInterface.hpp b/include/mrdocs/Metadata/Symbol/RecordInterface.hpp index 7c16c36735..5636f67652 100644 --- a/include/mrdocs/Metadata/Symbol/RecordInterface.hpp +++ b/include/mrdocs/Metadata/Symbol/RecordInterface.hpp @@ -78,12 +78,7 @@ tag_invoke( dom::LazyObjectMapTag, IO& io, RecordInterface const& I, - DomCorpus const*) -{ - io.map("public", I.Public); - io.map("protected", I.Protected); - io.map("private", I.Private); -} + DomCorpus const*); /** Map the RecordInterface to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/RecordKeyKind.hpp b/include/mrdocs/Metadata/Symbol/RecordKeyKind.hpp index 85238be811..19b810d12b 100644 --- a/include/mrdocs/Metadata/Symbol/RecordKeyKind.hpp +++ b/include/mrdocs/Metadata/Symbol/RecordKeyKind.hpp @@ -5,6 +5,7 @@ // // Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) // Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -30,23 +31,13 @@ enum class RecordKeyKind Union }; -/** Convert the key kind to its canonical string form. -*/ -MRDOCS_DECL -dom::String -toString(RecordKeyKind kind) noexcept; - /** Serialize the record key kind into a DOM value. */ -inline void tag_invoke( dom::ValueFromTag, dom::Value& v, - RecordKeyKind kind) -{ - v = toString(kind); -} + RecordKeyKind kind); } // mrdocs diff --git a/include/mrdocs/Metadata/Symbol/RecordTranche.hpp b/include/mrdocs/Metadata/Symbol/RecordTranche.hpp index 962ed707e9..2f5114b72d 100644 --- a/include/mrdocs/Metadata/Symbol/RecordTranche.hpp +++ b/include/mrdocs/Metadata/Symbol/RecordTranche.hpp @@ -114,20 +114,7 @@ tag_invoke( dom::LazyObjectMapTag, IO& io, RecordTranche const& I, - DomCorpus const* domCorpus) -{ - io.map("namespaceAliases", dom::LazyArray(I.NamespaceAliases, domCorpus)); - io.map("typedefs", dom::LazyArray(I.Typedefs, domCorpus)); - io.map("records", dom::LazyArray(I.Records, domCorpus)); - io.map("enums", dom::LazyArray(I.Enums, domCorpus)); - io.map("functions", dom::LazyArray(I.Functions, domCorpus)); - io.map("staticFunctions", dom::LazyArray(I.StaticFunctions, domCorpus)); - io.map("variables", dom::LazyArray(I.Variables, domCorpus)); - io.map("staticVariables", dom::LazyArray(I.StaticVariables, domCorpus)); - io.map("concepts", dom::LazyArray(I.Concepts, domCorpus)); - io.map("guides", dom::LazyArray(I.Guides, domCorpus)); - io.map("usings", dom::LazyArray(I.Usings, domCorpus)); -} + DomCorpus const* domCorpus); /** Map the RecordTranche to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/SymbolBase.hpp b/include/mrdocs/Metadata/Symbol/SymbolBase.hpp index ae2d13fd34..d3ea58e787 100644 --- a/include/mrdocs/Metadata/Symbol/SymbolBase.hpp +++ b/include/mrdocs/Metadata/Symbol/SymbolBase.hpp @@ -250,32 +250,7 @@ tag_invoke( dom::LazyObjectMapTag, IO& io, Symbol const& I, - DomCorpus const* domCorpus) -{ - MRDOCS_ASSERT(domCorpus); - io.map("class", std::string("symbol")); - io.map("kind", I.Kind); - io.map("id", I.id); - if (!I.Name.empty()) - { - io.map("name", I.Name); - } - io.map("access", I.Access); - io.map("extraction", I.Extraction); - io.map("isRegular", I.Extraction == ExtractionMode::Regular); - io.map("isSeeBelow", I.Extraction == ExtractionMode::SeeBelow); - io.map("isImplementationDefined", I.Extraction == ExtractionMode::ImplementationDefined); - io.map("isDependency", I.Extraction == ExtractionMode::Dependency); - if (I.Parent) - { - io.map("parent", I.Parent); - } - if (I.doc) - { - io.map("doc", *I.doc); - } - io.map("loc", I.Loc); -} + DomCorpus const* domCorpus); /** Return the Symbol as a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/Typedef.hpp b/include/mrdocs/Metadata/Symbol/Typedef.hpp index a34275331d..b12ea50acd 100644 --- a/include/mrdocs/Metadata/Symbol/Typedef.hpp +++ b/include/mrdocs/Metadata/Symbol/Typedef.hpp @@ -84,13 +84,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, TypedefSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("type", I.Type); - io.map("template", I.Template); - io.map("isUsing", I.IsUsing); -} + DomCorpus const* domCorpus); /** Map the TypedefSymbol to a @ref dom::Value object. diff --git a/include/mrdocs/Metadata/Symbol/Using.hpp b/include/mrdocs/Metadata/Symbol/Using.hpp index b9465f6854..c4bb3457a1 100644 --- a/include/mrdocs/Metadata/Symbol/Using.hpp +++ b/include/mrdocs/Metadata/Symbol/Using.hpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // Copyright (c) 2024 Fernando Pelliccioni (fpelliccioni@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // @@ -37,34 +38,16 @@ enum class UsingClass Enum // using enum }; -static constexpr -std::string_view -toString(UsingClass const& value) -{ - switch (value) - { - case UsingClass::Normal: return "normal"; - case UsingClass::Typename: return "typename"; - case UsingClass::Enum: return "enum"; - } - return "unknown"; -} - /** Return the UsingClass as a @ref dom::Value string. @param v The output value. @param kind The UsingClass to convert. */ -inline void tag_invoke( dom::ValueFromTag, dom::Value& v, - UsingClass kind) -{ - v = toString(kind); -} - + UsingClass kind); /** Info for using declarations. @@ -157,13 +140,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, UsingSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("usingClass", I.Class); - io.map("shadows", dom::LazyArray(I.ShadowDeclarations, domCorpus)); - io.map("qualifier", I.IntroducedName); -} + DomCorpus const* domCorpus); /** Map the UsingSymbol to a @ref dom::Value object. */ diff --git a/include/mrdocs/Metadata/Symbol/Variable.hpp b/include/mrdocs/Metadata/Symbol/Variable.hpp index 07162c2785..bb8de77c8e 100644 --- a/include/mrdocs/Metadata/Symbol/Variable.hpp +++ b/include/mrdocs/Metadata/Symbol/Variable.hpp @@ -135,37 +135,7 @@ tag_invoke( dom::LazyObjectMapTag t, IO& io, VariableSymbol const& I, - DomCorpus const* domCorpus) -{ - tag_invoke(t, io, I.asInfo(), domCorpus); - io.map("type", I.Type); - io.map("template", I.Template); - if (I.StorageClass != StorageClassKind::None) - { - io.map("storageClass", I.StorageClass); - } - io.map("isInline", I.IsInline); - io.map("isConstexpr", I.IsConstexpr); - io.map("isConstinit", I.IsConstinit); - io.map("isThreadLocal", I.IsThreadLocal); - if (!I.Initializer.Written.empty()) - { - io.map("initializer", I.Initializer.Written); - } - io.map("attributes", dom::LazyArray(I.Attributes)); - io.map("isRecordField", I.IsRecordField); - io.map("isMaybeUnused", I.IsMaybeUnused); - io.map("isDeprecated", I.IsDeprecated); - io.map("isVariant", I.IsVariant); - io.map("isMutable", I.IsMutable); - io.map("isBitfield", I.IsBitfield); - if (I.IsBitfield) - { - io.map("bitfieldWidth", I.BitfieldWidth.Written); - } - io.map("hasNoUniqueAddress", I.HasNoUniqueAddress); - io.map("attributes", dom::LazyArray(I.Attributes)); -} + DomCorpus const* domCorpus); /** Map the VariableSymbol to a @ref dom::Value object. */ diff --git a/share/mrdocs/addons/generator/adoc/partials/symbol.adoc.hbs b/share/mrdocs/addons/generator/adoc/partials/symbol.adoc.hbs index 0ff8370abc..bf1bb60288 100644 --- a/share/mrdocs/addons/generator/adoc/partials/symbol.adoc.hbs +++ b/share/mrdocs/addons/generator/adoc/partials/symbol.adoc.hbs @@ -137,14 +137,14 @@ {{/if}} {{! Using symbols }} -{{#if symbol.shadows}} +{{#if symbol.shadowDeclarations}} {{#> markup/dynamic-level-h }}Introduced Symbols{{/markup/dynamic-level-h~}} -{{#if (any_of_by symbol.shadows "doc")}} +{{#if (any_of_by symbol.shadowDeclarations "doc")}} [cols="1,4"] |=== |Name|Description -{{#each symbol.shadows}} +{{#each symbol.shadowDeclarations}} | {{> symbol/qualified-name . }} | {{> doc/block/inline-brief doc.brief }} {{/each}} @@ -153,7 +153,7 @@ [cols=1] |=== | Name -{{#each symbol.shadows}} +{{#each symbol.shadowDeclarations}} | {{> symbol/qualified-name . }} {{/each}} |=== diff --git a/share/mrdocs/addons/generator/common/partials/symbol/name-text.hbs b/share/mrdocs/addons/generator/common/partials/symbol/name-text.hbs index 3a80cf8ace..45146495dd 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/name-text.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/name-text.hbs @@ -11,7 +11,7 @@ See: https://mrdocs.com/docs/mrdocs/develop/generators.html#dom_reference --}} -{{~#if (and (eq kind "function") (eq functionClass "conversion"))~}} +{{~#if (and (eq kind "function") (eq funcClass "conversion"))~}} {{! Conversion operator: "operator" and the type declarator ~}} operator {{>type/declarator-text return ~}} {{~else if (eq kind "guide")~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/name.hbs b/share/mrdocs/addons/generator/common/partials/symbol/name.hbs index a458587acd..088a48ffcf 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/name.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/name.hbs @@ -11,7 +11,7 @@ See: https://mrdocs.com/docs/mrdocs/develop/generators.html#dom_reference --}} -{{~#if (and (eq kind "function") (eq functionClass "conversion"))~}} +{{~#if (and (eq kind "function") (eq funcClass "conversion"))~}} {{! Conversion operator: "operator" and the type declarator ~}} operator {{>type/declarator return ~}} {{~else if (eq kind "guide")~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/qualified-name-title.hbs b/share/mrdocs/addons/generator/common/partials/symbol/qualified-name-title.hbs index ed3433e3a3..8421cfa87e 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/qualified-name-title.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/qualified-name-title.hbs @@ -23,7 +23,7 @@ {{~#if (and parent parent.parent)~}} {{~> symbol/qualified-name-title parent is-qualified-name-parent=true ~}}{{#if parent.name }}::{{/if}} {{~/if~}} -{{~#if (and (eq kind "function") (eq functionClass "conversion"))~}} +{{~#if (and (eq kind "function") (eq funcClass "conversion"))~}} {{~> symbol/name . ~}} {{~else if is-qualified-name-parent ~}} {{!~ If this is a parent, we only print it if it really has a name ~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs index 1c3c8c31a1..149359fb83 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/function.hbs @@ -12,11 +12,11 @@ {{/if~}} {{#if explicitSpec}}{{explicitSpec}} {{/if~}} -{{#if (eq functionClass "normal")}}{{>type/declarator-prefix return}} +{{#if (eq funcClass "normal")}}{{>type/declarator-prefix return}} {{/if~}} {{~#if force-link~}} {{>symbol/name symbol }} -{{~else if (eq functionClass "conversion")~}} +{{~else if (eq funcClass "conversion")~}} {{>symbol/name symbol }} {{~else if (contains (arr "explicit" "partial") template.kind)~}} {{>symbol/name template.primary ~}}{{>template/args-text args=template.args ~}} @@ -32,7 +32,7 @@ {{#if isVolatile}} volatile{{/if~}} {{#if refQualifier}} {{refQualifier}}{{/if~}} {{#if exceptionSpec}} {{exceptionSpec}}{{/if~}} -{{#if (eq functionClass "normal")}}{{>type/declarator-suffix return}}{{/if~}} +{{#if (eq funcClass "normal")}}{{>type/declarator-suffix return}}{{/if~}} {{#if requires}} requires {{requires}}{{/if~}} diff --git a/share/mrdocs/addons/generator/common/partials/symbol/signature/using.hbs b/share/mrdocs/addons/generator/common/partials/symbol/signature/using.hbs index 58aa6e0e3b..12abccb86d 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/signature/using.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/signature/using.hbs @@ -1,5 +1,5 @@ -using {{#if (contains (arr "typename" "enum") usingClass)}} {{usingClass}} +using {{#if (contains (arr "typename" "enum") class)}} {{class}} {{~/if~}} -{{~#if qualifier~}} - {{>type/name-info qualifier }} +{{~#if introducedName~}} + {{>type/name-info introducedName }} {{~/if}}; \ No newline at end of file diff --git a/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs b/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs index 8e9b2262bc..1abc410714 100644 --- a/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs +++ b/share/mrdocs/addons/generator/common/partials/symbol/special-function-suffix.hbs @@ -15,9 +15,9 @@ {{#if (eq kind "overloads")~}} {{>symbol/special-function-suffix (front members)}} {{~else if (eq kind "function")~}} - {{#if (eq functionClass "constructor")}} + {{#if (eq funcClass "constructor")}} {{#>markup/span class="small"}}[constructor]{{/markup/span}} - {{~else if (eq functionClass "destructor")~}} + {{~else if (eq funcClass "destructor")~}} {{#>markup/span class="small"}}[destructor]{{/markup/span}} {{~/if~}} {{~#if isVirtual~}} diff --git a/share/mrdocs/addons/generator/html/partials/symbol.html.hbs b/share/mrdocs/addons/generator/html/partials/symbol.html.hbs index 476a28988e..516d0a8025 100644 --- a/share/mrdocs/addons/generator/html/partials/symbol.html.hbs +++ b/share/mrdocs/addons/generator/html/partials/symbol.html.hbs @@ -183,10 +183,10 @@ {{/if}} {{! Using symbols }} -{{#if symbol.shadows}} +{{#if symbol.shadowDeclarations}}
{{#> markup/dynamic-level-h level=2 }}Introduced Symbols{{/markup/dynamic-level-h~}} -{{#if (any_of_by symbol.shadows "doc")}} +{{#if (any_of_by symbol.shadowDeclarations "doc")}} @@ -195,7 +195,7 @@ -{{#each symbol.shadows}} +{{#each symbol.shadowDeclarations}} @@ -211,7 +211,7 @@ -{{#each symbol.shadows}} +{{#each symbol.shadowDeclarations}} diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 4322303632..985a82f9d6 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -913,7 +913,7 @@ populate( } } - I.Class = toFunctionClass(D->getDeclKind()); + I.FuncClass = toFunctionClass(D->getDeclKind()); // extract the return type in direct dependency mode // if it contains a placeholder type which is diff --git a/src/lib/CorpusImpl.cpp b/src/lib/CorpusImpl.cpp index 59808272a5..178fecefd2 100644 --- a/src/lib/CorpusImpl.cpp +++ b/src/lib/CorpusImpl.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -583,7 +584,7 @@ lookupImpl( } else if (component.isConversion()) { - MRDOCS_CHECK_OR(M.Class == FunctionClass::Conversion, matchRes); + MRDOCS_CHECK_OR(M.FuncClass == FunctionClass::Conversion, matchRes); MRDOCS_CHECK_OR(component.ConversionType == M.ReturnType, matchRes); } else diff --git a/src/lib/Gen/xml/XMLWriter.cpp b/src/lib/Gen/xml/XMLWriter.cpp index 3aebf8c731..9c5bb763cc 100644 --- a/src/lib/Gen/xml/XMLWriter.cpp +++ b/src/lib/Gen/xml/XMLWriter.cpp @@ -16,6 +16,7 @@ #include "CXXTags.hpp" #include #include +#include #include //------------------------------------------------ @@ -187,8 +188,8 @@ writeFunction( constexpr std::string_view functionTagName = "function"; tags_.open(functionTagName, { - { "class", toString(I.Class), - I.Class != FunctionClass::Normal }, + { "class", toString(I.FuncClass), + I.FuncClass != FunctionClass::Normal }, { "name", I.Name }, { I.Access }, { "exception-spec", except_spec, diff --git a/src/lib/Metadata/Finalizers/BaseMembersFinalizer.cpp b/src/lib/Metadata/Finalizers/BaseMembersFinalizer.cpp index 7fd45175db..a87fb7a107 100644 --- a/src/lib/Metadata/Finalizers/BaseMembersFinalizer.cpp +++ b/src/lib/Metadata/Finalizers/BaseMembersFinalizer.cpp @@ -119,8 +119,8 @@ inheritBaseMembers( // Check if we're not attempt to copy a special member function if (auto const *funcPtr = otherInfoPtr->asFunctionPtr()) { MRDOCS_CHECK_OR_CONTINUE( - !is_one_of(funcPtr->Class, {FunctionClass::Constructor, - FunctionClass::Destructor})); + !is_one_of(funcPtr->FuncClass, {FunctionClass::Constructor, + FunctionClass::Destructor})); } // Check if derived class has a member that shadows the base member diff --git a/src/lib/Metadata/Finalizers/DocComment/Function.hpp b/src/lib/Metadata/Finalizers/DocComment/Function.hpp index 17e60423aa..7e3724d28b 100644 --- a/src/lib/Metadata/Finalizers/DocComment/Function.hpp +++ b/src/lib/Metadata/Finalizers/DocComment/Function.hpp @@ -25,14 +25,14 @@ bool isSpecialFunction(FunctionSymbol const& I) { return - I.Class != FunctionClass::Normal || + I.FuncClass != FunctionClass::Normal || I.OverloadedOperator != OperatorKind::None; } bool isDefaultConstructor(FunctionSymbol const& I) { - return I.Class == FunctionClass::Constructor && I.Params.empty(); + return I.FuncClass == FunctionClass::Constructor && I.Params.empty(); } template @@ -41,7 +41,7 @@ isCopyOrMoveConstructorOrAssignment(FunctionSymbol const& I) { if constexpr (!assignment) { - MRDOCS_CHECK_OR(I.Class == FunctionClass::Constructor, false); + MRDOCS_CHECK_OR(I.FuncClass == FunctionClass::Constructor, false); } else { @@ -122,7 +122,7 @@ innermostTypenameString(Polymorphic const& T) bool populateFunctionBriefFromClass(FunctionSymbol& I, CorpusImpl const& corpus) { - switch (I.Class) + switch (I.FuncClass) { case FunctionClass::Normal: return false; @@ -315,7 +315,7 @@ populateFunctionReturnsForSpecial( Polymorphic const& innerR, CorpusImpl const& corpus) { - if (I.Class == FunctionClass::Conversion) + if (I.FuncClass == FunctionClass::Conversion) { if (auto* brief = getInfoBrief(innerR, corpus)) { @@ -529,7 +529,7 @@ setCntrOrAssignParamName( MRDOCS_CHECK_OR(I.Params.size() == 1, false); MRDOCS_CHECK_OR(I.IsRecordMethod, false); MRDOCS_CHECK_OR( - I.Class == FunctionClass::Constructor || + I.FuncClass == FunctionClass::Constructor || I.OverloadedOperator == OperatorKind::Equal, false); auto paramNames = @@ -645,7 +645,7 @@ setCntrOrAssignParamDoc( MRDOCS_CHECK_OR(index == 0, false); MRDOCS_CHECK_OR(I.IsRecordMethod, false); MRDOCS_CHECK_OR( - I.Class == FunctionClass::Constructor || + I.FuncClass == FunctionClass::Constructor || I.OverloadedOperator == OperatorKind::Equal, false); diff --git a/src/lib/Metadata/Finalizers/DocComment/Overloads.hpp b/src/lib/Metadata/Finalizers/DocComment/Overloads.hpp index c48ba576f6..b2ee136380 100644 --- a/src/lib/Metadata/Finalizers/DocComment/Overloads.hpp +++ b/src/lib/Metadata/Finalizers/DocComment/Overloads.hpp @@ -63,7 +63,7 @@ populateOverloadsBriefIfAllSameBrief(OverloadsSymbol& I, Range&& functionsWithBr bool populateOverloadsFromClass(OverloadsSymbol& I) { - switch (I.Class) + switch (I.FuncClass) { case FunctionClass::Normal: return false; diff --git a/src/lib/Metadata/Finalizers/DocCommentFinalizer.cpp b/src/lib/Metadata/Finalizers/DocCommentFinalizer.cpp index 53bd465773..91651c4173 100644 --- a/src/lib/Metadata/Finalizers/DocCommentFinalizer.cpp +++ b/src/lib/Metadata/Finalizers/DocCommentFinalizer.cpp @@ -832,7 +832,7 @@ generateAutoFunctionMetadata(FunctionSymbol& I) const return; } - if (!is_one_of(I.Class, { + if (!is_one_of(I.FuncClass, { FunctionClass::Constructor, FunctionClass::Destructor }) && I.doc->returns.empty()) diff --git a/src/lib/Metadata/Finalizers/SortMembersFinalizer.cpp b/src/lib/Metadata/Finalizers/SortMembersFinalizer.cpp index c6fd50ca72..f769b4c84b 100644 --- a/src/lib/Metadata/Finalizers/SortMembersFinalizer.cpp +++ b/src/lib/Metadata/Finalizers/SortMembersFinalizer.cpp @@ -37,7 +37,7 @@ struct SymbolIDCompareFn std::same_as || std::same_as) { - return I.Class; + return I.FuncClass; } return std::nullopt; } diff --git a/src/lib/Metadata/Source.cpp b/src/lib/Metadata/Source.cpp index 817a5dd662..01d15c0108 100644 --- a/src/lib/Metadata/Source.cpp +++ b/src/lib/Metadata/Source.cpp @@ -5,10 +5,13 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // +#include +#include #include #include #include @@ -19,22 +22,6 @@ namespace mrdocs { -std::string_view -toString(FileKind kind) -{ - switch(kind) - { - case FileKind::Source: - return "source"; - case FileKind::System: - return "system"; - case FileKind::Other: - return "other"; - default: - MRDOCS_UNREACHABLE(); - }; -} - namespace { template @@ -107,12 +94,7 @@ tag_invoke( IO& io, Location const& loc) { - io.map("fullPath", loc.FullPath); - io.map("shortPath", loc.ShortPath); - io.map("sourcePath", loc.SourcePath); - io.map("line", loc.LineNumber); - io.map("column", loc.ColumnNumber); - io.map("documented", loc.Documented); + mapReflectedType(io, loc); } void diff --git a/src/lib/Metadata/Symbol/ExtractionMode.cpp b/src/lib/Metadata/Symbol/ExtractionMode.cpp new file mode 100644 index 0000000000..e531e9a95e --- /dev/null +++ b/src/lib/Metadata/Symbol/ExtractionMode.cpp @@ -0,0 +1,27 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include +#include + +namespace mrdocs { + +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + ExtractionMode kind) +{ + v = toString(kind); +} + +} // mrdocs + diff --git a/src/lib/Metadata/Symbol/FileKind.cpp b/src/lib/Metadata/Symbol/FileKind.cpp new file mode 100644 index 0000000000..b51f30cbc8 --- /dev/null +++ b/src/lib/Metadata/Symbol/FileKind.cpp @@ -0,0 +1,27 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include +#include + +namespace mrdocs { + +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + FileKind kind) +{ + v = toString(kind); +} + +} // mrdocs + diff --git a/src/lib/Metadata/Symbol/Function.cpp b/src/lib/Metadata/Symbol/Function.cpp index 8a2c20ad2f..7d85dcec55 100644 --- a/src/lib/Metadata/Symbol/Function.cpp +++ b/src/lib/Metadata/Symbol/Function.cpp @@ -271,24 +271,6 @@ getOperatorReadableName( MRDOCS_UNREACHABLE(); } -dom::String -toString(FunctionClass const kind) noexcept -{ - switch(kind) - { - case FunctionClass::Normal: - return "normal"; - case FunctionClass::Constructor: - return "constructor"; - case FunctionClass::Conversion: - return "conversion"; - case FunctionClass::Destructor: - return "destructor"; - default: - MRDOCS_UNREACHABLE(); - } -} - void merge(Param& I, Param&& Other) { @@ -387,9 +369,9 @@ merge(FunctionSymbol& I, FunctionSymbol&& Other) { MRDOCS_ASSERT(canMerge(I, Other)); merge(I.asInfo(), std::move(Other.asInfo())); - if (I.Class == FunctionClass::Normal) + if (I.FuncClass == FunctionClass::Normal) { - I.Class = Other.Class; + I.FuncClass = Other.FuncClass; } I.ReturnType = std::move(Other.ReturnType); std::size_t const n = std::min(I.Params.size(), Other.Params.size()); diff --git a/src/lib/Metadata/Symbol/FunctionClass.cpp b/src/lib/Metadata/Symbol/FunctionClass.cpp new file mode 100644 index 0000000000..7553ae4ed9 --- /dev/null +++ b/src/lib/Metadata/Symbol/FunctionClass.cpp @@ -0,0 +1,27 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include +#include + +namespace mrdocs { + +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + FunctionClass const kind) +{ + v = toString(kind); +} + +} // mrdocs + diff --git a/src/lib/Metadata/Symbol/Overloads.cpp b/src/lib/Metadata/Symbol/Overloads.cpp index a6b1b49967..0d505b7318 100644 --- a/src/lib/Metadata/Symbol/Overloads.cpp +++ b/src/lib/Metadata/Symbol/Overloads.cpp @@ -48,7 +48,7 @@ addMember(OverloadsSymbol& I, FunctionSymbol const& Member) I.Name = Member.Name; I.Access = Member.Access; I.Extraction = Member.Extraction; - I.Class = Member.Class; + I.FuncClass = Member.FuncClass; I.OverloadedOperator = Member.OverloadedOperator; I.ReturnType = Member.ReturnType; } diff --git a/src/lib/Metadata/Symbol/Record.cpp b/src/lib/Metadata/Symbol/Record.cpp index 75b464128f..dee92b5298 100644 --- a/src/lib/Metadata/Symbol/Record.cpp +++ b/src/lib/Metadata/Symbol/Record.cpp @@ -4,10 +4,13 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) +// Copyright (c) 2025 Gennaro Prota (gennaro.prota@gmail.com) // // Official repository: https://github.com/cppalliance/mrdocs // +#include +#include #include #include #include @@ -15,23 +18,6 @@ namespace mrdocs { -dom::String -toString( - RecordKeyKind kind) noexcept -{ - switch(kind) - { - case RecordKeyKind::Struct: - return "struct"; - case RecordKeyKind::Class: - return "class"; - case RecordKeyKind::Union: - return "union"; - default: - MRDOCS_UNREACHABLE(); - } -} - namespace { void reduceSymbolIDs( @@ -165,12 +151,10 @@ tag_invoke( BaseInfo const& I, DomCorpus const* domCorpus) { - io.map("access", I.Access); + mapReflectedType(io, I, domCorpus); io.map("isPublic", I.Access == AccessKind::Public); io.map("isProtected", I.Access == AccessKind::Protected); io.map("isPrivate", I.Access == AccessKind::Private); - io.map("isVirtual", I.IsVirtual); - io.map("type", dom::ValueFrom(I.Type, domCorpus)); } void diff --git a/src/lib/Metadata/Symbol/RecordKeyKind.cpp b/src/lib/Metadata/Symbol/RecordKeyKind.cpp new file mode 100644 index 0000000000..4403141726 --- /dev/null +++ b/src/lib/Metadata/Symbol/RecordKeyKind.cpp @@ -0,0 +1,27 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include +#include + +namespace mrdocs { + +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + RecordKeyKind kind) +{ + v = toString(kind); +} + +} // mrdocs + diff --git a/src/lib/Metadata/Symbol/Using.cpp b/src/lib/Metadata/Symbol/Using.cpp index f4ad51aa41..a37da7ac87 100644 --- a/src/lib/Metadata/Symbol/Using.cpp +++ b/src/lib/Metadata/Symbol/Using.cpp @@ -9,6 +9,7 @@ // Official repository: https://github.com/cppalliance/mrdocs // +#include #include #include #include @@ -51,5 +52,14 @@ merge(UsingSymbol& I, UsingSymbol&& Other) } } +void +tag_invoke( + dom::ValueFromTag, + dom::Value& v, + UsingClass kind) +{ + v = toString(kind); +} + } // mrdocs diff --git a/src/lib/Support/LegibleNames.cpp b/src/lib/Support/LegibleNames.cpp index bca33e95de..5594733924 100644 --- a/src/lib/Support/LegibleNames.cpp +++ b/src/lib/Support/LegibleNames.cpp @@ -49,24 +49,24 @@ getUnnamedInfoName(Symbol const& I) if (auto const* FI = I.asFunctionPtr()) { // don't use the reserved prefix for overloaded operators - if(FI->Class == FunctionClass::Normal && + if(FI->FuncClass == FunctionClass::Normal && FI->OverloadedOperator != OperatorKind::None) { return std::string(getSafeOperatorName( FI->OverloadedOperator, true)); } - func_idx = to_underlying(FI->Class); + func_idx = to_underlying(FI->FuncClass); } if (auto const* FI = I.asOverloadsPtr()) { // don't use the reserved prefix for overloaded operators - if(FI->Class == FunctionClass::Normal && + if(FI->FuncClass == FunctionClass::Normal && FI->OverloadedOperator != OperatorKind::None) { return std::string(getSafeOperatorName( FI->OverloadedOperator, true)); } - func_idx = to_underlying(FI->Class); + func_idx = to_underlying(FI->FuncClass); } MRDOCS_ASSERT(func_idx < std::size(func_reserved)); return std::string(func_reserved[func_idx]); @@ -219,7 +219,7 @@ class LegibleNames::Impl { // functions can be explicitly specialized, // and can be overloaded - if (t.Class != FunctionClass::Normal || + if (t.FuncClass != FunctionClass::Normal || t.OverloadedOperator != OperatorKind::None) { return getUnnamedInfoName(t); diff --git a/src/lib/Support/Reflection/EnumToString.hpp b/src/lib/Support/Reflection/EnumToString.hpp new file mode 100644 index 0000000000..3f80f34ef9 --- /dev/null +++ b/src/lib/Support/Reflection/EnumToString.hpp @@ -0,0 +1,53 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_LIB_SUPPORT_REFLECTION_ENUMTOSTRING_HPP +#define MRDOCS_LIB_SUPPORT_REFLECTION_ENUMTOSTRING_HPP + +#include "Reflection.hpp" +#include +#include +#include +#include + +namespace mrdocs { + +/** Convert a Boost.Describe'd enumerator to string form. + + @param e The enumerator to convert. + @return The string form of the enumerator. +*/ +template + requires boost::describe::has_describe_enumerators::value +std::string +toString(Enum e) +{ + std::string result; + boost::mp11::mp_for_each< + boost::describe::describe_enumerators>( + [&](auto const& D) + { + if (D.value == e) + { + result = toKebabCase(D.name); + } + }); + + if (!result.empty()) + { + return result; + } + + MRDOCS_UNREACHABLE(); +} + +} + +#endif diff --git a/src/lib/Support/Reflection/MapReflectedType.hpp b/src/lib/Support/Reflection/MapReflectedType.hpp new file mode 100644 index 0000000000..96e0c7d0c5 --- /dev/null +++ b/src/lib/Support/Reflection/MapReflectedType.hpp @@ -0,0 +1,259 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_LIB_SUPPORT_REFLECTION_MAPREFLECTEDTYPE_HPP +#define MRDOCS_LIB_SUPPORT_REFLECTION_MAPREFLECTEDTYPE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mrdocs { + +class DomCorpus; + +namespace detail { + +/** Type traits to identify special types that need custom handling. +*/ +template +struct is_vector : std::false_type {}; + +template +struct is_vector> : std::true_type {}; + +template +inline constexpr bool is_vector_v = is_vector::value; + +/** Helper to determine if a member should be mapped based on its value. +*/ +template +constexpr bool +shouldMapValue(T const& value) +{ + if constexpr (std::is_same_v) + { + return !value.empty(); + } + else if constexpr (std::is_same_v) + { + return value != ConstexprKind::None; + } + else if constexpr (std::is_same_v) + { + return value != ReferenceKind::None; + } + else if constexpr (std::is_same_v) + { + return value != StorageClassKind::None; + } + else if constexpr (std::is_same_v) + { + return !value.Written.empty(); + } + else + { + // All other types are always mapped. + return true; + } +} + +/** Convert a member name to the corresponding DOM name. + + E.g.: + - IsVariadic -> isVariadic +*/ +inline +std::string +normalizeMemberName(std::string_view name) +{ + // Special cases. + if (name == "Constexpr") + { + return "constexprKind"; + } + else if (name == "ReturnType") + { + return "return"; + } + else if (name == "Noexcept") + { + return "exceptionSpec"; + } + else if (name == "Explicit") + { + return "explicitSpec"; + } + else if (name == "KeyKind") + { + return "tag"; + } + else if (name == "Class") + { + return "usingClass"; + } + else + { + std::string result(name); + if (!result.empty()) + { + result.front() = std::tolower(result.front(), std::locale::classic()); + } + return result; + } +} + +/** Map a single member to the IO object. + + This function template also decides how to map the member based on its type. +*/ +template +void +mapMember( + IO& io, + std::string_view name, + T const& value, + DomCorpus const* domCorpus) +{ + std::string const domName = detail::normalizeMemberName(name); + + if constexpr (detail::is_vector_v) + { + // Vectors become lazy arrays — the decision is encapsulated here. + MRDOCS_ASSERT(domCorpus != nullptr); + io.map(domName, dom::LazyArray(value, domCorpus)); + } + else if constexpr (dom::HasValueFromWithContext) + { + MRDOCS_ASSERT(domCorpus != nullptr); + io.map(domName, dom::ValueFrom(value, domCorpus)); + } + else + { + io.map(domName, dom::ValueFrom(value)); + } +} + +} + +/** Automatically map all Boost.Describe'd members of a type to the DOM. + + This replaces the manual `tag_invoke()` implementations with a single + call that handles all member mappings via reflection. + + @param io The IO object to use for mapping. + @param obj The object to be mapped. + @param domCorpus The DomCorpus used to create the DOM values, or a null pointer. + + Usage in a Symbol type: + + @code + template + void tag_invoke( + dom::LazyObjectMapTag t, + IO& io, + FunctionSymbol const& I, + DomCorpus const* domCorpus) + { + // First, map base Symbol members. + tag_invoke(t, io, I.asInfo(), domCorpus); + + // Then, automatically map all FunctionSymbol-specific members. + mapReflectedType(io, I, domCorpus); + } + @endcode +*/ +template + requires boost::describe::has_describe_members::value +void +mapReflectedType( + IO& io, + T const& obj, + DomCorpus const* domCorpus) +{ + // First, map all bases. + boost::mp11::mp_for_each>( + [&](auto const& descriptor) + { + using BaseType = typename std::decay_t::type; + + if constexpr (boost::describe::has_describe_members::value) + { + // Base is described: recurse. + mapReflectedType(io, static_cast(obj), domCorpus); + } + else + { + // Base is not described: map directly. + tag_invoke(dom::LazyObjectMapTag{}, io, static_cast(obj), domCorpus); + } + } + ); + + // Then, map all members. + boost::mp11::mp_for_each>( + [&](auto const& descriptor) { + using Descriptor = std::decay_t; + using MemberType = std::decay_t; + + constexpr char const* name = Descriptor::name; + auto const& value = obj.*Descriptor::pointer; + + static_assert( + detail::is_vector_v || + dom::HasValueFrom, + "No ValueFrom() overload found for this member type"); + + if (detail::shouldMapValue(value)) + { + detail::mapMember(io, detail::normalizeMemberName(name), value, domCorpus); + } + }); +} + +/** Map all Boost.Describe'd members without converting values. + + This version passes raw member values to `io.map()`, letting + the IO object handle conversion with its stored context. + + @param io The IO object to use for mapping. + @param obj The object to be mapped. +*/ +template + requires boost::describe::has_describe_members::value +void +mapReflectedType( + IO& io, + T const& obj) +{ + boost::mp11::mp_for_each>( + [&](auto const& descriptor) + { + using Descriptor = std::decay_t; + constexpr char const* name = Descriptor::name; + auto const& value = obj.*Descriptor::pointer; + if (detail::shouldMapValue(value)) + { + io.map(detail::normalizeMemberName(name), value); + } + }); +} + +} + +#endif diff --git a/src/lib/Support/Reflection/Reflection.cpp b/src/lib/Support/Reflection/Reflection.cpp new file mode 100644 index 0000000000..b554669af0 --- /dev/null +++ b/src/lib/Support/Reflection/Reflection.cpp @@ -0,0 +1,507 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#include "Reflection.hpp" +#include "MapReflectedType.hpp" + +namespace mrdocs { + +//------------------------------------------------------ +// Symbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + Symbol const& I, + DomCorpus const* domCorpus) +{ + MRDOCS_ASSERT(domCorpus); + mapReflectedType(io, I, domCorpus); + io.map("class", std::string("symbol")); + io.map("isRegular", I.Extraction == ExtractionMode::Regular); + io.map("isSeeBelow", I.Extraction == ExtractionMode::SeeBelow); + io.map("isImplementationDefined", I.Extraction == ExtractionMode::ImplementationDefined); + io.map("isDependency", I.Extraction == ExtractionMode::Dependency); + if (I.doc) + { + io.map("doc", dom::ValueFrom(*I.doc, domCorpus)); + } +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + Symbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// ImageInline. +//------------------------------------------------------ + +template +void +doc::tag_invoke( + dom::LazyObjectMapTag t, + IO& io, + doc::ImageInline const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +doc::tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + doc::ImageInline const&, + DomCorpus const*); + +//------------------------------------------------------ +// ConceptSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + ConceptSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + ConceptSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// DocComment. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + DocComment const& I, + DomCorpus const* domCorpus) +{ + boost::mp11::mp_for_each>([&](auto D) + { + constexpr std::string_view name = D.name; + + if constexpr (name == "Document") + { + io.defer("description", [&I, domCorpus] + { + return dom::LazyArray(I.Document, domCorpus); + }); + } + else if constexpr (name == "brief") + { + if (I.brief && !I.brief->children.empty()) + { + io.map("brief", I.brief); + } + } + else + { + io.defer(D.name, [&I, domCorpus, ptr = D.pointer] + { + return dom::LazyArray(I.*ptr, domCorpus); + }); + } + }); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + DocComment const&, + DomCorpus const* +); + +//------------------------------------------------------ +// EnumConstantSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + EnumConstantSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + EnumConstantSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// EnumSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + EnumSymbol const& I, + DomCorpus const* domCorpus) +{ + tag_invoke(dom::LazyObjectMapTag{}, io, I.asInfo(), domCorpus); + io.map("type", I.UnderlyingType); + io.map("isScoped", I.Scoped); + io.map("constants", dom::LazyArray(I.Constants, domCorpus)); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + EnumSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// FunctionSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + FunctionSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + FunctionSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// GuideSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + GuideSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + GuideSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// NamespaceTranche. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + NamespaceTranche const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + NamespaceTranche const&, + DomCorpus const*); + +//------------------------------------------------------ +// NamespaceSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + NamespaceSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + NamespaceSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// NamespaceAliasSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + NamespaceAliasSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + NamespaceAliasSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// OverloadsSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + OverloadsSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + OverloadsSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// RecordTranche. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + RecordTranche const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + RecordTranche const&, + DomCorpus const*); + +//------------------------------------------------------ +// RecordInterface. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + RecordInterface const& I, + DomCorpus const*) +{ + mapReflectedType(io, I); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + RecordInterface const&, + DomCorpus const*); + +//------------------------------------------------------ +// RecordSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + RecordSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); + io.map("defaultAccess", getDefaultAccessString(I.KeyKind)); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + RecordSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// TypedefSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + TypedefSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + TypedefSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// UsingSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + UsingSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + UsingSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// VariableSymbol. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + VariableSymbol const& I, + DomCorpus const* domCorpus) +{ + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + VariableSymbol const&, + DomCorpus const*); + +//------------------------------------------------------ +// FriendInfo. +//------------------------------------------------------ + +template +void +tag_invoke( + dom::LazyObjectMapTag, + IO& io, + FriendInfo const& I, + DomCorpus const* domCorpus) +{ + if (I.id) + { + io.defer("name", [&I, domCorpus]{ + return dom::ValueFrom(I.id, domCorpus).get("name"); + }); + io.map("symbol", I.id); + } + else if (I.Type) + { + io.defer("name", [&]{ + return dom::ValueFrom(I.Type, domCorpus).get("name"); + }); + } + mapReflectedType(io, I, domCorpus); +} + +template +void +tag_invoke( + dom::LazyObjectMapTag, + LazyObjectIOType&, + FriendInfo const&, + DomCorpus const*); + +} // mrdocs diff --git a/src/lib/Support/Reflection/Reflection.hpp b/src/lib/Support/Reflection/Reflection.hpp new file mode 100644 index 0000000000..063fd1febd --- /dev/null +++ b/src/lib/Support/Reflection/Reflection.hpp @@ -0,0 +1,209 @@ +// +// 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 Gennaro Prota (gennaro.prota@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_LIB_SUPPORT_REFLECTION_REFLECTION_HPP +#define MRDOCS_LIB_SUPPORT_REFLECTION_REFLECTION_HPP + +#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 + +namespace mrdocs { + +BOOST_DESCRIBE_STRUCT( + DocComment, + (), + (Document, brief, returns, params, tparams, + exceptions, sees, preconditions, postconditions, + relates, related) +) + +namespace doc { + +BOOST_DESCRIBE_STRUCT( + ImageInline, + (InlineCommonBase, InlineContainer), + (src, alt) +) + +} + +BOOST_DESCRIBE_STRUCT( + ConceptSymbol, + (SymbolCommonBase), + (Template, Constraint) +) + +BOOST_DESCRIBE_STRUCT( + EnumSymbol, + (SymbolCommonBase), + (Scoped, UnderlyingType, Constants) +) + +BOOST_DESCRIBE_STRUCT( + EnumConstantSymbol, + (SymbolCommonBase), + (Initializer) +) + +BOOST_DESCRIBE_STRUCT( + FriendInfo, + (), + (Type) // `id` intentionally omitted. +) + +BOOST_DESCRIBE_STRUCT( + FunctionSymbol, + (SymbolCommonBase), + (ReturnType, Params, Template, FuncClass, Noexcept, Requires, + IsVariadic, IsDefaulted, IsExplicitlyDefaulted, IsDeleted, + IsDeletedAsWritten, IsNoReturn, HasOverrideAttr, HasTrailingReturn, + IsNodiscard, IsExplicitObjectMemberFunction, Constexpr, + OverloadedOperator, StorageClass, IsRecordMethod, IsVirtual, + IsVirtualAsWritten, IsPure, IsConst, IsVolatile, IsFinal, + RefQualifier, Explicit, Attributes) +) + +BOOST_DESCRIBE_STRUCT( + GuideSymbol, + (SymbolCommonBase), + (Deduced, Template, Params, Explicit) +) + +BOOST_DESCRIBE_STRUCT( + Location, + (), + (FullPath, ShortPath, SourcePath, LineNumber, ColumnNumber, Documented) +) + +BOOST_DESCRIBE_STRUCT( + NamespaceTranche, + (), + (Namespaces, NamespaceAliases, Typedefs, Records, Enums, + Functions, Variables, Concepts, Guides, Usings) +) + +BOOST_DESCRIBE_STRUCT( + NamespaceSymbol, + (SymbolCommonBase), + (IsInline, IsAnonymous, UsingDirectives, Members) +) + +BOOST_DESCRIBE_STRUCT( + NamespaceAliasSymbol, + (SymbolCommonBase), + (AliasedSymbol) +) + +BOOST_DESCRIBE_STRUCT( + OverloadsSymbol, + (SymbolCommonBase), + (FuncClass, OverloadedOperator, Members) // `ReturnType` intentionally omitted. +) + +BOOST_DESCRIBE_STRUCT( + Param, + (), + (Type, Name, Default) +) + +BOOST_DESCRIBE_STRUCT( + RecordSymbol, + (SymbolCommonBase), + (KeyKind, Template, IsTypeDef, IsFinal, IsFinalDestructor, + Bases, Derived, Interface, Friends) +) + +BOOST_DESCRIBE_STRUCT( + BaseInfo, + (), + (Type, Access, IsVirtual) +) + +BOOST_DESCRIBE_STRUCT( + RecordInterface, + (), + (Public, Protected, Private) +) + +BOOST_DESCRIBE_STRUCT( + RecordTranche, + (), + (NamespaceAliases, Typedefs, Records, Enums, Functions, + StaticFunctions, Variables, StaticVariables, Concepts, Guides, Usings) +) + +BOOST_DESCRIBE_STRUCT( + Symbol, + (), + (Name, Loc, Kind, id, Access, + Extraction, IsCopyFromInherited, Parent) // `doc` intentionally omitted. +) + +BOOST_DESCRIBE_STRUCT( + TypedefSymbol, + (SymbolCommonBase), + (Type, IsUsing, Template) +) + +BOOST_DESCRIBE_STRUCT( + UsingSymbol, + (SymbolCommonBase), + (Class, IntroducedName, ShadowDeclarations) +) + +BOOST_DESCRIBE_STRUCT( + VariableSymbol, + (SymbolCommonBase), + (Type, Template, Initializer, StorageClass, IsInline, + IsConstexpr, IsConstinit, IsThreadLocal, Attributes, IsMaybeUnused, + IsDeprecated, HasNoUniqueAddress, IsRecordField, IsMutable, IsVariant, + IsBitfield, BitfieldWidth) +) + +BOOST_DESCRIBE_ENUM( + ExtractionMode, Regular, SeeBelow, ImplementationDefined, Dependency) + +BOOST_DESCRIBE_ENUM(FileKind, Source, System, Other) + +BOOST_DESCRIBE_ENUM(FunctionClass, Normal, Constructor, Conversion, Destructor) + +BOOST_DESCRIBE_ENUM(RecordKeyKind, Struct, Class, Union) + +BOOST_DESCRIBE_ENUM(UsingClass, Normal, Typename, Enum) + +} + +#endif diff --git a/third-party/patches/boost_describe/CMakeLists.txt b/third-party/patches/boost_describe/CMakeLists.txt new file mode 100644 index 0000000000..8c38d3ad63 --- /dev/null +++ b/third-party/patches/boost_describe/CMakeLists.txt @@ -0,0 +1,52 @@ +# +# 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 Gennaro Prota (gennaro.prota@gmail.com) +# +# Official repository: https://github.com/cppalliance/mrdocs +# + +cmake_minimum_required(VERSION 3.16) +project(boost_describe) + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +add_library(boost_describe INTERFACE) +add_library(Boost::describe ALIAS boost_describe) + +set_target_properties(boost_describe PROPERTIES EXPORT_NAME describe) + +target_include_directories(boost_describe INTERFACE + $ + $ +) + +target_compile_features(boost_describe INTERFACE cxx_std_14) + +install(DIRECTORY include/boost + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(TARGETS boost_describe + EXPORT boost_describe-targets + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(EXPORT boost_describe-targets + FILE boost_describe-targets.cmake + NAMESPACE Boost:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/boost_describe +) + +configure_package_config_file( + ${CMAKE_CURRENT_SOURCE_DIR}/boost_describe-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/boost_describe-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/boost_describe +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/boost_describe-config.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/boost_describe +) \ No newline at end of file diff --git a/third-party/patches/boost_describe/boost_describe-config.cmake.in b/third-party/patches/boost_describe/boost_describe-config.cmake.in new file mode 100644 index 0000000000..4c27bf0164 --- /dev/null +++ b/third-party/patches/boost_describe/boost_describe-config.cmake.in @@ -0,0 +1,14 @@ +# +# 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 Gennaro Prota (gennaro.prota@gmail.com) +# +# Official repository: https://github.com/cppalliance/mrdocs +# + +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/boost_describe-targets.cmake") +check_required_components(boost_describe) diff --git a/third-party/patches/boost_mp11/CMakeLists.txt b/third-party/patches/boost_mp11/CMakeLists.txt new file mode 100644 index 0000000000..67a5a3ca60 --- /dev/null +++ b/third-party/patches/boost_mp11/CMakeLists.txt @@ -0,0 +1,52 @@ +# +# 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 Gennaro Prota (gennaro.prota@gmail.com) +# +# Official repository: https://github.com/cppalliance/mrdocs +# + +cmake_minimum_required(VERSION 3.16) +project(boost_mp11) + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +add_library(boost_mp11 INTERFACE) +add_library(Boost::mp11 ALIAS boost_mp11) + +set_target_properties(boost_mp11 PROPERTIES EXPORT_NAME mp11) + +target_include_directories(boost_mp11 INTERFACE + $ + $ +) + +target_compile_features(boost_mp11 INTERFACE cxx_std_11) + +install(DIRECTORY include/boost + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(TARGETS boost_mp11 + EXPORT boost_mp11-targets + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +install(EXPORT boost_mp11-targets + FILE boost_mp11-targets.cmake + NAMESPACE Boost:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/boost_mp11 +) + +configure_package_config_file( + ${CMAKE_CURRENT_SOURCE_DIR}/boost_mp11-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/boost_mp11-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/boost_mp11 +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/boost_mp11-config.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/boost_mp11 +) \ No newline at end of file diff --git a/third-party/patches/boost_mp11/boost_mp11-config.cmake.in b/third-party/patches/boost_mp11/boost_mp11-config.cmake.in new file mode 100644 index 0000000000..27617c8017 --- /dev/null +++ b/third-party/patches/boost_mp11/boost_mp11-config.cmake.in @@ -0,0 +1,14 @@ +# +# 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 Gennaro Prota (gennaro.prota@gmail.com) +# +# Official repository: https://github.com/cppalliance/mrdocs +# + +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/boost_mp11-targets.cmake") +check_required_components(boost_mp11) diff --git a/third-party/recipes/boost_describe.json b/third-party/recipes/boost_describe.json new file mode 100644 index 0000000000..85bf30e11f --- /dev/null +++ b/third-party/recipes/boost_describe.json @@ -0,0 +1,19 @@ +{ + "name": "boost_describe", + "version": "1.90.0", + "source": { + "type": "zip", + "url": "https://github.com/boostorg/describe/archive/refs/tags/boost-1.90.0.zip" + }, + "dependencies": [ + "boost_mp11" + ], + "build": [ + { + "type": "cmake", + "options": [] + } + ], + "package_root_var": "boost_describe_ROOT", + "install_scope": "global" +} diff --git a/third-party/recipes/boost_mp11.json b/third-party/recipes/boost_mp11.json new file mode 100644 index 0000000000..380a2b9b3b --- /dev/null +++ b/third-party/recipes/boost_mp11.json @@ -0,0 +1,17 @@ +{ + "name": "boost_mp11", + "version": "1.90.0", + "source": { + "type": "zip", + "url": "https://github.com/boostorg/mp11/archive/refs/tags/boost-1.90.0.zip" + }, + "dependencies": [], + "build": [ + { + "type": "cmake", + "options": [] + } + ], + "package_root_var": "boost_mp11_ROOT", + "install_scope": "global" +}
{{> symbol/qualified-name . }} {{> doc/block/inline-brief doc.brief }}
{{> symbol/qualified-name . }}