From 22ac9ec29867e0f625a283e2a5e2e049fbbc771f Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Wed, 1 Nov 2023 16:00:29 -0400 Subject: [PATCH 1/2] feat: add EnumeratorInfo and FriendInfo --- include/mrdocs/Corpus.hpp | 17 ++ include/mrdocs/Metadata.hpp | 2 + include/mrdocs/Metadata/Enum.hpp | 30 +- include/mrdocs/Metadata/Enumerator.hpp | 45 +++ include/mrdocs/Metadata/Field.hpp | 4 +- include/mrdocs/Metadata/Friend.hpp | 48 +++ include/mrdocs/Metadata/Function.hpp | 4 +- include/mrdocs/Metadata/Info.hpp | 35 ++- include/mrdocs/Metadata/Interface.hpp | 2 + include/mrdocs/Metadata/Namespace.hpp | 4 +- include/mrdocs/Metadata/Record.hpp | 8 +- include/mrdocs/Metadata/Specialization.hpp | 4 +- include/mrdocs/Metadata/Typedef.hpp | 4 +- include/mrdocs/Metadata/Variable.hpp | 4 +- include/mrdocs/MetadataFwd.hpp | 3 +- mrdocs.rnc | 42 ++- .../generator/asciidoc/partials/enum.adoc.hbs | 10 - .../asciidoc/partials/enumerator.adoc.hbs | 20 ++ .../asciidoc/partials/friend.adoc.hbs | 26 ++ ...on-sig.adoc.hbs => function-decl.adoc.hbs} | 2 + .../asciidoc/partials/function.adoc.hbs | 2 +- .../asciidoc/partials/record-decl.adoc.hbs | 27 ++ .../asciidoc/partials/record.adoc.hbs | 24 +- .../asciidoc/partials/tranche.adoc.hbs | 4 + .../html/partials/enumerator.html.hbs | 1 + .../generator/html/partials/friend.html.hbs | 1 + src/lib/-HTML/Builder.cpp | 2 + src/lib/-HTML/MultiPageVisitor.cpp | 5 +- src/lib/-HTML/SinglePageVisitor.cpp | 3 + src/lib/-XML/CXXTags.cpp | 7 +- src/lib/-XML/CXXTags.hpp | 1 + src/lib/-XML/XMLWriter.cpp | 81 +++-- src/lib/-XML/XMLWriter.hpp | 2 + src/lib/-adoc/Builder.cpp | 2 + src/lib/-adoc/MultiPageVisitor.cpp | 5 +- src/lib/-adoc/SinglePageVisitor.cpp | 3 + src/lib/-bitcode/BitcodeGenerator.cpp | 10 +- src/lib/AST/ASTVisitor.cpp | 276 +++++++++++------- src/lib/AST/AnyBlock.hpp | 259 +++++++--------- src/lib/AST/BitcodeIDs.hpp | 9 +- src/lib/AST/BitcodeReader.cpp | 16 +- src/lib/AST/BitcodeWriter.cpp | 85 +++--- src/lib/AST/BitcodeWriter.hpp | 3 +- src/lib/Lib/Corpus.cpp | 7 +- src/lib/Lib/Lookup.cpp | 21 +- src/lib/Metadata/DomMetadata.cpp | 83 +++--- src/lib/Metadata/Finalize.cpp | 16 +- src/lib/Metadata/Info.cpp | 68 +---- src/lib/Metadata/Interface.cpp | 6 + src/lib/Metadata/Reduce.cpp | 25 +- src/lib/Metadata/Reduce.hpp | 2 + src/lib/Support/Debug.cpp | 52 +--- src/lib/Support/SafeNames.cpp | 22 +- test-files/old-tests/enum.cpp | 47 +++ test-files/old-tests/enum.xml | 99 +++++++ test-files/old-tests/friend-1.xml | 10 +- test-files/old-tests/friend-2.xml | 10 +- test-files/old-tests/friend-3.xml | 15 +- test-files/old-tests/friend-4.xml | 15 +- test-files/old-tests/friend-5.xml | 10 +- test-files/old-tests/friend-6.cpp | 23 ++ test-files/old-tests/friend-6.xml | 66 +++++ test-files/old-tests/noreturn.xml | 6 +- 63 files changed, 1111 insertions(+), 634 deletions(-) create mode 100644 include/mrdocs/Metadata/Enumerator.hpp create mode 100644 include/mrdocs/Metadata/Friend.hpp create mode 100644 share/mrdocs/addons/generator/asciidoc/partials/enumerator.adoc.hbs create mode 100644 share/mrdocs/addons/generator/asciidoc/partials/friend.adoc.hbs rename share/mrdocs/addons/generator/asciidoc/partials/{function-sig.adoc.hbs => function-decl.adoc.hbs} (97%) create mode 100644 share/mrdocs/addons/generator/asciidoc/partials/record-decl.adoc.hbs create mode 100644 share/mrdocs/addons/generator/html/partials/enumerator.html.hbs create mode 100644 share/mrdocs/addons/generator/html/partials/friend.html.hbs create mode 100644 test-files/old-tests/enum.cpp create mode 100644 test-files/old-tests/enum.xml create mode 100644 test-files/old-tests/friend-6.cpp create mode 100644 test-files/old-tests/friend-6.xml diff --git a/include/mrdocs/Corpus.hpp b/include/mrdocs/Corpus.hpp index ca1b9ba71..498f76b9e 100644 --- a/include/mrdocs/Corpus.hpp +++ b/include/mrdocs/Corpus.hpp @@ -111,6 +111,11 @@ class MRDOCS_VISIBLE RecordInfo const& I, F&& f, Args&&... args) const; + template + void traverse( + EnumInfo const& I, + F&& f, Args&&... args) const; + template void traverse( SpecializationInfo const& I, @@ -178,6 +183,18 @@ traverse( std::forward(args)...); } +template +void +Corpus:: +traverse( + EnumInfo const& I, + F&& f, Args&&... args) const +{ + for(auto const& id : I.Members) + visit(get(id), std::forward(f), + std::forward(args)...); +} + template void Corpus:: diff --git a/include/mrdocs/Metadata.hpp b/include/mrdocs/Metadata.hpp index 3a07e800a..c1518c8bf 100644 --- a/include/mrdocs/Metadata.hpp +++ b/include/mrdocs/Metadata.hpp @@ -18,8 +18,10 @@ // metadata extracted from AST #include +#include #include #include +#include #include #include #include diff --git a/include/mrdocs/Metadata/Enum.hpp b/include/mrdocs/Metadata/Enum.hpp index 652a3eea0..2f19d64c0 100644 --- a/include/mrdocs/Metadata/Enum.hpp +++ b/include/mrdocs/Metadata/Enum.hpp @@ -25,30 +25,6 @@ namespace clang { namespace mrdocs { -// Information for a single possible value of an enumeration. -struct EnumValueInfo -{ - std::string Name; - - /** The initializer expression, if any */ - ConstantExprInfo Initializer; - - /** The documentation for the value, if any. - */ - std::unique_ptr javadoc; - - //-------------------------------------------- - - explicit - EnumValueInfo( - std::string_view Name = "") - : Name(Name) - { - } -}; - -//------------------------------------------------ - // TODO: Expand to allow for documenting templating. // Info for types. struct EnumInfo @@ -64,13 +40,11 @@ struct EnumInfo std::unique_ptr UnderlyingType; // Enumeration members. - std::vector Members; + std::vector Members; //-------------------------------------------- - explicit - EnumInfo( - SymbolID ID = SymbolID::invalid) + explicit EnumInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/Metadata/Enumerator.hpp b/include/mrdocs/Metadata/Enumerator.hpp new file mode 100644 index 000000000..2ecc68c4c --- /dev/null +++ b/include/mrdocs/Metadata/Enumerator.hpp @@ -0,0 +1,45 @@ +// +// Licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (c) 2023 Krystian Stasiowski (sdkrystian@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_ENUMERATOR_HPP +#define MRDOCS_API_METADATA_ENUMERATOR_HPP + +#include +#include +#include +#include +#include +#include + +namespace clang { +namespace mrdocs { + +/** Info for enumerators. +*/ +struct EnumeratorInfo + : IsInfo + , SourceInfo +{ + /** The initializer expression, if any + */ + ConstantExprInfo Initializer; + + //-------------------------------------------- + + explicit EnumeratorInfo(SymbolID ID) noexcept + : IsInfo(ID) + { + } +}; + +} // mrdocs +} // clang + +#endif diff --git a/include/mrdocs/Metadata/Field.hpp b/include/mrdocs/Metadata/Field.hpp index 2991aae9a..35f0a32f4 100644 --- a/include/mrdocs/Metadata/Field.hpp +++ b/include/mrdocs/Metadata/Field.hpp @@ -64,9 +64,7 @@ struct FieldInfo //-------------------------------------------- - explicit - FieldInfo( - SymbolID ID = SymbolID::invalid) noexcept + explicit FieldInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/Metadata/Friend.hpp b/include/mrdocs/Metadata/Friend.hpp new file mode 100644 index 000000000..e87b89e95 --- /dev/null +++ b/include/mrdocs/Metadata/Friend.hpp @@ -0,0 +1,48 @@ +// +// 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 Krystian Stasiowski (sdkrystian@gmail.com) +// +// Official repository: https://github.com/cppalliance/mrdocs +// + +#ifndef MRDOCS_API_METADATA_FRIEND_HPP +#define MRDOCS_API_METADATA_FRIEND_HPP + +#include +#include +#include +#include +#include + +namespace clang { +namespace mrdocs { + +/** Info for friend declarations. +*/ +struct FriendInfo + : IsInfo + , SourceInfo +{ + /** Befriended symbol. + */ + SymbolID FriendSymbol = SymbolID::invalid; + + /** Befriended type. + */ + std::unique_ptr FriendType; + + //-------------------------------------------- + + explicit FriendInfo(SymbolID ID) noexcept + : IsInfo(ID) + { + } +}; + +} // mrdocs +} // clang + +#endif diff --git a/include/mrdocs/Metadata/Function.hpp b/include/mrdocs/Metadata/Function.hpp index 564ef5aec..4799e9cae 100644 --- a/include/mrdocs/Metadata/Function.hpp +++ b/include/mrdocs/Metadata/Function.hpp @@ -159,9 +159,7 @@ struct FunctionInfo //-------------------------------------------- - explicit - FunctionInfo( - SymbolID ID = SymbolID::invalid) + explicit FunctionInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/Metadata/Info.hpp b/include/mrdocs/Metadata/Info.hpp index 693f486cc..e8f8a0bb6 100644 --- a/include/mrdocs/Metadata/Info.hpp +++ b/include/mrdocs/Metadata/Info.hpp @@ -35,19 +35,23 @@ struct FieldInfo; struct TypedefInfo; struct VariableInfo; struct SpecializationInfo; +struct FriendInfo; +struct EnumeratorInfo; /** Info variant discriminator */ enum class InfoKind { - Namespace = 0, + Namespace = 1, // for bitstream Record, Function, Enum, Typedef, Variable, Field, - Specialization + Specialization, + Friend, + Enumerator }; MRDOCS_DECL dom::String toString(InfoKind kind) noexcept; @@ -59,7 +63,7 @@ struct MRDOCS_VISIBLE { /** The unique identifier for this symbol. */ - SymbolID id = SymbolID::invalid; + SymbolID id; /** The unqualified name. */ @@ -91,7 +95,7 @@ struct MRDOCS_VISIBLE conditions for extraction, but was extracted due to it being used by a primary `Info`. */ - bool Implicit = true; + bool Implicit = false; /** In-order List of parent namespaces. */ @@ -110,20 +114,12 @@ struct MRDOCS_VISIBLE explicit Info( InfoKind kind, - SymbolID ID = SymbolID::invalid) noexcept + SymbolID ID) noexcept : id(ID) , Kind(kind) { } - // - // Observers - // - - MRDOCS_DECL - std::string - extractName() const; - constexpr bool isNamespace() const noexcept { return Kind == InfoKind::Namespace; } constexpr bool isRecord() const noexcept { return Kind == InfoKind::Record; } constexpr bool isFunction() const noexcept { return Kind == InfoKind::Function; } @@ -132,6 +128,8 @@ struct MRDOCS_VISIBLE constexpr bool isVariable() const noexcept { return Kind == InfoKind::Variable; } constexpr bool isField() const noexcept { return Kind == InfoKind::Field; } constexpr bool isSpecialization() const noexcept { return Kind == InfoKind::Specialization; } + constexpr bool isFriend() const noexcept { return Kind == InfoKind::Friend; } + constexpr bool isEnumerator() const noexcept { return Kind == InfoKind::Enumerator; } }; //------------------------------------------------ @@ -157,13 +155,10 @@ struct IsInfo : Info static constexpr bool isVariable() noexcept { return K == InfoKind::Variable; } static constexpr bool isField() noexcept { return K == InfoKind::Field; } static constexpr bool isSpecialization() noexcept { return K == InfoKind::Specialization; } + static constexpr bool isFriend() noexcept { return K == InfoKind::Friend; } + static constexpr bool isEnumerator() noexcept { return K == InfoKind::Enumerator; } protected: - constexpr IsInfo() - : Info(K) - { - } - constexpr explicit IsInfo(SymbolID ID) : Info(K, ID) { @@ -204,6 +199,10 @@ visit( return visitor.template visit(); case InfoKind::Specialization: return visitor.template visit(); + case InfoKind::Friend: + return visitor.template visit(); + case InfoKind::Enumerator: + return visitor.template visit(); default: MRDOCS_UNREACHABLE(); } diff --git a/include/mrdocs/Metadata/Interface.hpp b/include/mrdocs/Metadata/Interface.hpp index e8e48941e..fa5348c60 100644 --- a/include/mrdocs/Metadata/Interface.hpp +++ b/include/mrdocs/Metadata/Interface.hpp @@ -39,6 +39,7 @@ class Interface std::span Data; std::span StaticFunctions; std::span StaticData; + std::span Friends; }; Corpus const& corpus; @@ -74,6 +75,7 @@ class Interface std::vector data_; std::vector staticfuncs_; std::vector staticdata_; + std::vector friends_; }; //------------------------------------------------ diff --git a/include/mrdocs/Metadata/Namespace.hpp b/include/mrdocs/Metadata/Namespace.hpp index 71289f81c..2c5f6a1a7 100644 --- a/include/mrdocs/Metadata/Namespace.hpp +++ b/include/mrdocs/Metadata/Namespace.hpp @@ -40,9 +40,7 @@ struct NamespaceInfo //-------------------------------------------- - explicit - NamespaceInfo( - SymbolID ID = SymbolID::invalid) + explicit NamespaceInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/Metadata/Record.hpp b/include/mrdocs/Metadata/Record.hpp index c94b9f145..492efbce1 100644 --- a/include/mrdocs/Metadata/Record.hpp +++ b/include/mrdocs/Metadata/Record.hpp @@ -97,10 +97,6 @@ struct RecordInfo */ std::vector Bases; - /** List of friend functions. - */ - std::vector Friends; - /** Record members */ std::vector Members; @@ -111,9 +107,7 @@ struct RecordInfo //-------------------------------------------- - explicit - RecordInfo( - SymbolID ID = SymbolID::invalid) + explicit RecordInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/Metadata/Specialization.hpp b/include/mrdocs/Metadata/Specialization.hpp index fc72ad25e..606f93895 100644 --- a/include/mrdocs/Metadata/Specialization.hpp +++ b/include/mrdocs/Metadata/Specialization.hpp @@ -63,9 +63,7 @@ struct SpecializationInfo */ std::vector Members; - explicit - SpecializationInfo( - SymbolID ID = SymbolID::invalid) + explicit SpecializationInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/Metadata/Typedef.hpp b/include/mrdocs/Metadata/Typedef.hpp index d39019eb5..aa7e2162e 100644 --- a/include/mrdocs/Metadata/Typedef.hpp +++ b/include/mrdocs/Metadata/Typedef.hpp @@ -39,9 +39,7 @@ struct TypedefInfo //-------------------------------------------- - explicit - TypedefInfo( - SymbolID ID = SymbolID::invalid) + explicit TypedefInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/Metadata/Variable.hpp b/include/mrdocs/Metadata/Variable.hpp index 68da0209d..c4a91a052 100644 --- a/include/mrdocs/Metadata/Variable.hpp +++ b/include/mrdocs/Metadata/Variable.hpp @@ -50,9 +50,7 @@ struct VariableInfo //-------------------------------------------- - explicit - VariableInfo( - SymbolID ID = SymbolID::invalid) noexcept + explicit VariableInfo(SymbolID ID) noexcept : IsInfo(ID) { } diff --git a/include/mrdocs/MetadataFwd.hpp b/include/mrdocs/MetadataFwd.hpp index 80894674e..21e4eedc4 100644 --- a/include/mrdocs/MetadataFwd.hpp +++ b/include/mrdocs/MetadataFwd.hpp @@ -36,9 +36,10 @@ enum class ReferenceKind; enum class StorageClassKind; struct BaseInfo; -struct EnumValueInfo; struct EnumInfo; +struct EnumeratorInfo; struct FieldInfo; +struct FriendInfo; struct FunctionInfo; struct Info; class Javadoc; diff --git a/mrdocs.rnc b/mrdocs.rnc index bd0566e9d..71cd62536 100644 --- a/mrdocs.rnc +++ b/mrdocs.rnc @@ -53,7 +53,6 @@ grammar ( BaseInfo | Attr | - element friend { ID } | Javadoc? | RecordScope ) * @@ -99,13 +98,21 @@ grammar Name, attribute class {"scoped"} ?, ID, - Location *, BaseInfo ?, - element value - { - Name, - attribute value { text } - } *, + Location *, + Javadoc ?, + EnumScope + } + + #--------------------------------------------- + + Enumerator = + element enumerator + { + Name, + ID, + attribute initializer { text } ?, + Location *, Javadoc ? } @@ -163,6 +170,24 @@ grammar #--------------------------------------------- + Friend = + element friend + { + Access ?, + ID, + Location *, + Javadoc ?, + ( + element befriended + { + ID | + attribute type { text } + } + ) + } + + #--------------------------------------------- + Symbol = ( attribute Tag { text }, @@ -262,9 +287,12 @@ grammar Field | Var | Template | + Friend | Specialization )* + EnumScope = Enumerator * + #--------------------------------------------- # # diff --git a/share/mrdocs/addons/generator/asciidoc/partials/enum.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/enum.adoc.hbs index 137f08d69..4c9d23007 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/enum.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/enum.adoc.hbs @@ -28,13 +28,3 @@ enum {{symbol.name}}; {{symbol.doc.description}} {{/if}} - -{{#if symbol.members}} -{{#each symbol.members}} -{{#if doc.description}} -==== {{name}} - -{{doc.description}} -{{/if}} -{{/each}} -{{/if}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/enumerator.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/enumerator.adoc.hbs new file mode 100644 index 000000000..df53ee6e7 --- /dev/null +++ b/share/mrdocs/addons/generator/asciidoc/partials/enumerator.adoc.hbs @@ -0,0 +1,20 @@ +{{!-- enumerator --}} +== {{symbol.name}} + +{{symbol.doc.brief}} + +=== Synopsis + +[source,cpp,subs="verbatim,macros,-callouts"] +---- +{{symbol.name}}{{#if symbol.initializer}} = {{symbol.initializer}}{{~/if}} +---- + +{{>source symbol.loc}} + +{{#if symbol.doc.description}} +=== Description + +{{symbol.doc.description}} + +{{/if}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/friend.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/friend.adoc.hbs new file mode 100644 index 000000000..11735ee9e --- /dev/null +++ b/share/mrdocs/addons/generator/asciidoc/partials/friend.adoc.hbs @@ -0,0 +1,26 @@ +{{!-- friend --}} +== Friend {{#if symbol.symbol}}{{symbol.symbol.name}}{{else}}{{symbol.type.name}}{{/if}} + +{{symbol.doc.brief}} + +=== Synopsis + +{{#if symbol.type~}} +[source,cpp,subs="verbatim,macros,-callouts"] +---- +friend {{>declarator symbol.type}}; +---- +{{else if (and symbol.symbol (eq symbol.symbol.kind "record"))~}} +{{>record-decl symbol.symbol isFriend=true~}} +{{else if (and symbol.symbol (eq symbol.symbol.kind "function"))~}} +{{>function-decl symbol.symbol isFriend=true~}} +{{/if}} + +{{>source symbol.loc}} + +{{#if symbol.doc.description}} +=== Description + +{{symbol.doc.description}} + +{{/if}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/function-sig.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/function-decl.adoc.hbs similarity index 97% rename from share/mrdocs/addons/generator/asciidoc/partials/function-sig.adoc.hbs rename to share/mrdocs/addons/generator/asciidoc/partials/function-decl.adoc.hbs index 02a81375f..9d33cdf23 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/function-sig.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/function-decl.adoc.hbs @@ -2,6 +2,8 @@ ---- {{#if template}}{{>template-head template}} {{/if~}} +{{#if isFriend}}friend +{{/if~}} {{#if constexprKind}}{{constexprKind}} {{/if~}} {{#if storageClass}}{{storageClass}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/function.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/function.adoc.hbs index 733adaeec..7b130511b 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/function.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/function.adoc.hbs @@ -5,7 +5,7 @@ === Synopsis -{{>function-sig symbol}} +{{>function-decl symbol isFriend=false}} {{>source symbol.loc}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/record-decl.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/record-decl.adoc.hbs new file mode 100644 index 000000000..641d5ab31 --- /dev/null +++ b/share/mrdocs/addons/generator/asciidoc/partials/record-decl.adoc.hbs @@ -0,0 +1,27 @@ +[source,cpp,subs="verbatim,macros,-callouts"] +---- +{{#if template}}{{>template-head template}} +{{/if~}} +{{#if (or (eq template.kind "explicit") (eq template.kind "partial"))~}} + {{#if isFriend}}friend {{/if~}} + {{tag}} {{#if template.primary.id~}}xref:{{template.primary.ref}}[{{name}}]{{else}}{{name}}{{/if~}} + {{~>template-args args=template.args~}} +{{else~}} + {{#if isFriend}}friend {{/if~}} + {{tag}} {{name~}} +{{/if~}} +{{#unless bases}} +; +{{else if isFriend}} +; +{{else}} + +{{#each bases}} + {{#if @first}}:{{else}},{{/if}} + {{~#unless (eq access ../defaultAccess)}} {{access}}{{/unless}} + {{~#if isVirtual}} virtual{{/if}} + {{~null}} {{>declarator type}} + {{~#if @last}};{{/if}} +{{/each}} +{{/unless}} +---- diff --git a/share/mrdocs/addons/generator/asciidoc/partials/record.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/record.adoc.hbs index 536e41ac0..724cd0f48 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/record.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/record.adoc.hbs @@ -5,29 +5,7 @@ === Synopsis -[source,cpp,subs="verbatim,macros,-callouts"] ----- -{{#if template}}{{>template-head symbol.template}} -{{/if~}} -{{#if (or (eq symbol.template.kind "explicit") (eq symbol.template.kind "partial"))~}} - {{symbol.tag}} {{#if symbol.template.primary.id~}}xref:{{symbol.template.primary.ref}}[{{symbol.name}}]{{else}}{{symbol.name}}{{/if~}} - {{~>template-args args=symbol.template.args~}} -{{else~}} - {{symbol.tag}} {{symbol.name~}} -{{/if~}} -{{#unless symbol.bases}} -; -{{else}} - -{{#each symbol.bases}} - {{#if @first}}:{{else}},{{/if}} - {{~#unless (eq access ../symbol.defaultAccess)}} {{access}}{{/unless}} - {{~#if isVirtual}} virtual{{/if}} - {{~null}} {{>declarator type}} - {{~#if @last}};{{/if}} -{{/each}} -{{/unless}} ----- +{{>record-decl symbol isFriend=false}} {{>source symbol.loc}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/tranche.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/tranche.adoc.hbs index c39b5ae7a..bbc48c05a 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/tranche.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/tranche.adoc.hbs @@ -30,3 +30,7 @@ ==={{label}} Static Data Members {{>info-list tranche.staticdata}} {{/if}} +{{#if tranche.friends}} +==={{label}} Friends +{{>info-list tranche.friends}} +{{/if}} diff --git a/share/mrdocs/addons/generator/html/partials/enumerator.html.hbs b/share/mrdocs/addons/generator/html/partials/enumerator.html.hbs new file mode 100644 index 000000000..b5bd0765f --- /dev/null +++ b/share/mrdocs/addons/generator/html/partials/enumerator.html.hbs @@ -0,0 +1 @@ +{{!-- enumerator --}} diff --git a/share/mrdocs/addons/generator/html/partials/friend.html.hbs b/share/mrdocs/addons/generator/html/partials/friend.html.hbs new file mode 100644 index 000000000..8679899fb --- /dev/null +++ b/share/mrdocs/addons/generator/html/partials/friend.html.hbs @@ -0,0 +1 @@ +{{!-- friend --}} diff --git a/src/lib/-HTML/Builder.cpp b/src/lib/-HTML/Builder.cpp index 01b59be42..65cf12dc4 100644 --- a/src/lib/-HTML/Builder.cpp +++ b/src/lib/-HTML/Builder.cpp @@ -209,6 +209,8 @@ DEFINE(TypedefInfo); DEFINE(VariableInfo); DEFINE(FieldInfo); DEFINE(SpecializationInfo); +DEFINE(FriendInfo); +DEFINE(EnumeratorInfo); } // html } // mrdocs diff --git a/src/lib/-HTML/MultiPageVisitor.cpp b/src/lib/-HTML/MultiPageVisitor.cpp index 52e5f48e2..6aa6ededa 100644 --- a/src/lib/-HTML/MultiPageVisitor.cpp +++ b/src/lib/-HTML/MultiPageVisitor.cpp @@ -24,7 +24,8 @@ operator()(T const& I) renderPage(I); if constexpr( T::isNamespace() || - T::isRecord()) + T::isRecord() || + T::isEnum()) corpus_.traverse(I, *this); } @@ -68,6 +69,8 @@ DEFINE(TypedefInfo); DEFINE(VariableInfo); DEFINE(FieldInfo); DEFINE(SpecializationInfo); +DEFINE(FriendInfo); +DEFINE(EnumeratorInfo); } // html } // mrdocs diff --git a/src/lib/-HTML/SinglePageVisitor.cpp b/src/lib/-HTML/SinglePageVisitor.cpp index 75d7dcec7..17f1c3b0e 100644 --- a/src/lib/-HTML/SinglePageVisitor.cpp +++ b/src/lib/-HTML/SinglePageVisitor.cpp @@ -24,6 +24,7 @@ operator()(T const& I) if constexpr( T::isNamespace() || T::isRecord() || + T::isEnum() || T::isSpecialization()) corpus_.traverse(I, *this); } @@ -94,6 +95,8 @@ DEFINE(TypedefInfo); DEFINE(VariableInfo); DEFINE(FieldInfo); DEFINE(SpecializationInfo); +DEFINE(FriendInfo); +DEFINE(EnumeratorInfo); } // html } // mrdocs diff --git a/src/lib/-XML/CXXTags.cpp b/src/lib/-XML/CXXTags.cpp index 93bf0b531..671e94f02 100644 --- a/src/lib/-XML/CXXTags.cpp +++ b/src/lib/-XML/CXXTags.cpp @@ -45,11 +45,14 @@ getTagName(Info const& I) noexcept return enumTagName; case InfoKind::Variable: return varTagName; + case InfoKind::Friend: + return friendTagName; + case InfoKind::Enumerator: + return enumeratorTagName; default: break; } - MRDOCS_ASSERT(false); - return "(unknown)"; + MRDOCS_UNREACHABLE(); } } // xml diff --git a/src/lib/-XML/CXXTags.hpp b/src/lib/-XML/CXXTags.hpp index b8e74f3da..f0f5a49b5 100644 --- a/src/lib/-XML/CXXTags.hpp +++ b/src/lib/-XML/CXXTags.hpp @@ -39,6 +39,7 @@ constexpr auto classTagName = "class"; constexpr auto dataMemberTagName = "field"; constexpr auto javadocTagName = "doc"; constexpr auto enumTagName = "enum"; +constexpr auto enumeratorTagName = "enumerator"; constexpr auto friendTagName = "friend"; constexpr auto functionTagName = "function"; constexpr auto namespaceTagName = "namespace"; diff --git a/src/lib/-XML/XMLWriter.cpp b/src/lib/-XML/XMLWriter.cpp index d2f64ca08..d359c6aa9 100644 --- a/src/lib/-XML/XMLWriter.cpp +++ b/src/lib/-XML/XMLWriter.cpp @@ -226,6 +226,10 @@ operator()( writeVar(I); if constexpr(T::isSpecialization()) writeSpecialization(I); + if constexpr(T::isEnumerator()) + writeEnumerator(I); + if constexpr(T::isFriend()) + writeFriend(I); } //------------------------------------------------ @@ -250,34 +254,61 @@ writeEnum( writeSourceInfo(I); - for(auto const& V : I.Members) - { - std::string val = V.Initializer.Value ? - std::to_string(*V.Initializer.Value) : - V.Initializer.Written; - if(! V.javadoc) - { - tags_.write("value", {}, { - { "name", V.Name }, - { "value", val }, - }); - } - else - { - tags_.open("value", { - { "name", V.Name }, - { "value", val } - }); - writeJavadoc(V.javadoc); - tags_.close("value"); - } - } - writeJavadoc(I.javadoc); + corpus_.traverse(I, *this); + tags_.close(enumTagName); } +void +XMLWriter:: +writeEnumerator( + EnumeratorInfo const& I) +{ + std::string val = I.Initializer.Value ? + std::to_string(*I.Initializer.Value) : + I.Initializer.Written; + + tags_.open(enumeratorTagName, { + { "name", I.Name }, + { "initializer", val }, + { I.Access }, + { I.id } + }); + + writeSourceInfo(I); + + writeJavadoc(I.javadoc); + + tags_.close(enumeratorTagName); +} + +void +XMLWriter:: +writeFriend( + FriendInfo const& I) +{ + tags_.open(friendTagName, { + { I.Access }, + { I.id } + }); + + writeSourceInfo(I); + + writeJavadoc(I.javadoc); + + Attributes attrs = {}; + if(I.FriendSymbol) + attrs.push({I.FriendSymbol}); + else if(I.FriendType) + attrs.push({"type", toString(*I.FriendType)}); + + tags_.write("befriended", {}, attrs); + + tags_.close(friendTagName); +} + void XMLWriter:: writeFunction( @@ -339,10 +370,6 @@ writeRecord( tags_.close(baseTagName); } - // Friends - for(auto const& id : I.Friends) - tags_.write(friendTagName, "", { { id } }); - writeJavadoc(I.javadoc); corpus_.traverse(I, *this); diff --git a/src/lib/-XML/XMLWriter.hpp b/src/lib/-XML/XMLWriter.hpp index dec15d889..6d8c8e406 100644 --- a/src/lib/-XML/XMLWriter.hpp +++ b/src/lib/-XML/XMLWriter.hpp @@ -62,6 +62,8 @@ class XMLWriter void writeRecord(RecordInfo const&); void writeFunction(FunctionInfo const&); void writeEnum(EnumInfo const&); + void writeEnumerator(EnumeratorInfo const&); + void writeFriend(FriendInfo const&); void writeField(FieldInfo const&); void writeTypedef(TypedefInfo const&); void writeVar(VariableInfo const&); diff --git a/src/lib/-adoc/Builder.cpp b/src/lib/-adoc/Builder.cpp index 86889499e..b6d3b8b39 100644 --- a/src/lib/-adoc/Builder.cpp +++ b/src/lib/-adoc/Builder.cpp @@ -216,6 +216,8 @@ DEFINE(TypedefInfo); DEFINE(VariableInfo); DEFINE(FieldInfo); DEFINE(SpecializationInfo); +DEFINE(FriendInfo); +DEFINE(EnumeratorInfo); } // adoc } // mrdocs diff --git a/src/lib/-adoc/MultiPageVisitor.cpp b/src/lib/-adoc/MultiPageVisitor.cpp index 4dc73271b..9b2d47dd0 100644 --- a/src/lib/-adoc/MultiPageVisitor.cpp +++ b/src/lib/-adoc/MultiPageVisitor.cpp @@ -24,7 +24,8 @@ operator()(T const& I) renderPage(I); if constexpr( T::isNamespace() || - T::isRecord()) + T::isRecord() || + T::isEnum()) corpus_.traverse(I, *this); } @@ -73,6 +74,8 @@ DEFINE(TypedefInfo); DEFINE(VariableInfo); DEFINE(FieldInfo); DEFINE(SpecializationInfo); +DEFINE(FriendInfo); +DEFINE(EnumeratorInfo); } // adoc } // mrdocs diff --git a/src/lib/-adoc/SinglePageVisitor.cpp b/src/lib/-adoc/SinglePageVisitor.cpp index 6f14f6a54..c30318673 100644 --- a/src/lib/-adoc/SinglePageVisitor.cpp +++ b/src/lib/-adoc/SinglePageVisitor.cpp @@ -24,6 +24,7 @@ operator()(T const& I) if constexpr( T::isNamespace() || T::isRecord() || + T::isEnum() || T::isSpecialization()) corpus_.traverse(I, *this); } @@ -94,6 +95,8 @@ DEFINE(TypedefInfo); DEFINE(VariableInfo); DEFINE(FieldInfo); DEFINE(SpecializationInfo); +DEFINE(FriendInfo); +DEFINE(EnumeratorInfo); } // adoc } // mrdocs diff --git a/src/lib/-bitcode/BitcodeGenerator.cpp b/src/lib/-bitcode/BitcodeGenerator.cpp index 306162e8f..401f25960 100644 --- a/src/lib/-bitcode/BitcodeGenerator.cpp +++ b/src/lib/-bitcode/BitcodeGenerator.cpp @@ -75,7 +75,10 @@ class MultiFileBuilder Error(ec).Throw(); }); - if constexpr(T::isRecord()) + if constexpr( + T::isRecord() || + T::isNamespace() || + T::isEnum()) corpus_.traverse(I, *this); } }; @@ -109,7 +112,10 @@ class SingleFileBuilder { auto bc = writeBitcode(I); os_.write(bc.data(), bc.size()); - if constexpr(T::isRecord()) + if constexpr( + T::isRecord() || + T::isNamespace() || + T::isEnum()) corpus_.traverse(I, *this); } }; diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 8c598b02c..3ef288e1d 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -284,16 +284,15 @@ class ASTVisitor getOrCreateInfo(const SymbolID& id) { Info* info = getInfo(id); - bool created = false; + bool created = ! info; if(! info) { - auto [it, inserted] = info_.emplace( - std::make_unique(id)); - info = it->get(); - created = true; + info = info_.emplace(std::make_unique< + InfoTy>(id)).first->get(); + if(currentMode() != ExtractMode::Normal) + info->Implicit = true; } MRDOCS_ASSERT(info->Kind == InfoTy::kind_id); - info->Implicit &= currentMode() != ExtractMode::Normal; return {static_cast(*info), created}; } @@ -348,6 +347,54 @@ class ASTVisitor //------------------------------------------------ + /** Generates a USR for a declaration. + + Returns true if USR generation failed, + and false otherwise. + */ + bool + generateUSR(const Decl* D) + { + MRDOCS_ASSERT(D); + MRDOCS_ASSERT(usr_.empty()); + // KRYSTIAN NOTE: clang doesn't currently support + // generating USRs for friend declarations, so we + // will improvise until i can merge a patch which + // adds support for them + if(const auto* FD = dyn_cast(D)) + { + // first, generate the USR for the containing class + if(index::generateUSRForDecl( + cast(FD->getDeclContext()), usr_)) + return true; + // add a seperator for uniqueness + usr_.append("@FD"); + // if the friend declaration names a type, + // use the USR generator for types + if(TypeSourceInfo* TSI = FD->getFriendType()) + return index::generateUSRForType( + TSI->getType(), context_, usr_); + // otherwise, fallthrough and append the + // USR of the nominated declaration + if(! (D = FD->getFriendDecl())) + return true; + } + // functions require their parameter types to be decayed + // prior to USR generator to ensure that declarations + // with parameter types which decay to the same type + // generate the same USR + if(const auto* FD = dyn_cast(D)) + { + // apply the type adjustments specified in [dcl.fct] p5 + // to ensure that the USR of the corresponding function matches + // other declarations of the function that have parameters declared + // with different top-level cv-qualifiers. + for(ParmVarDecl* P : FD->parameters()) + P->setType(context_.getSignatureParameterType(P->getType())); + } + return index::generateUSRForDecl(D, usr_); + } + // Function to hash a given USR value for storage. // As USRs (Unified Symbol Resolution) could bef // large, especially for functions with long type @@ -355,20 +402,13 @@ class ASTVisitor // guarantee the uniqueness of symbols while using // a relatively small amount of memory (vs storing // USRs directly). - // bool extractSymbolID( const Decl* D, SymbolID& id) { - // functions require their parameter types to be decayed - // prior to USR generator to ensure that declarations - // with parameter types which decay to the same type - // generate the same USR - if(const auto* FD = dyn_cast(D)) - applyDecayToParameters(FD); usr_.clear(); - if(index::generateUSRForDecl(D, usr_)) + if(generateUSR(D)) return false; id = SymbolID(llvm::SHA1::hash( arrayRefFromStringRef(usr_)).data()); @@ -446,8 +486,7 @@ class ASTVisitor //------------------------------------------------ unsigned - getLine( - const NamedDecl* D) const + getLine(const Decl* D) const { return source_.getPresumedLoc( D->getBeginLoc()).getLine(); @@ -1184,6 +1223,23 @@ class ASTVisitor return VD; } + // ------------------------------------------------ + // EnumDecl + + // VarTemplate + if constexpr(kind == Decl::Enum) + { + EnumDecl* ED = DT; + while(MemberSpecializationInfo* MSI = + ED->getMemberSpecializationInfo()) + { + if(MSI->isExplicitSpecialization()) + break; + ED = cast(MSI->getInstantiatedFrom()); + } + return ED; + } + return DT; }); } @@ -1523,19 +1579,6 @@ class ASTVisitor } } - void - applyDecayToParameters( - const FunctionDecl* D) - { - // apply the type adjustments specified in [dcl.fct] p5 - // to ensure that the USR of the corresponding function matches - // other declarations of the function that have parameters declared - // with different top-level cv-qualifiers. - // this needs to be done prior to USR generation for the function - for(ParmVarDecl* P : D->parameters()) - P->setType(context_.getSignatureParameterType(P->getType())); - } - void parseRawComment( std::unique_ptr& javadoc, @@ -1853,9 +1896,14 @@ class ASTVisitor emplaceChild(P, child_id); break; } - // KRYSTIAN FIXME: we may need to handle - // enumerators separately at some point - // case Decl::Enum: + case Decl::Enum: + { + auto [P, created] = getOrCreateInfo< + EnumInfo>(parent_id); + buildEnum(P, created, cast(parent)); + emplaceChild(P, child_id); + break; + } default: // we consider all other DeclContexts to be "transparent" // and do not include them in the list of parents. @@ -2020,18 +2068,29 @@ class ASTVisitor I.UnderlyingType = buildTypeInfo( D->getIntegerType()); - for(const EnumConstantDecl* E : D->enumerators()) - { - auto& M = I.Members.emplace_back( - E->getNameAsString()); + getParentNamespaces(I, D); + } - buildExprInfo( - M.Initializer, - E->getInitExpr(), - E->getInitVal()); + //------------------------------------------------ - parseRawComment(I.Members.back().javadoc, E); - } + void + buildEnumerator( + EnumeratorInfo& I, + bool created, + EnumConstantDecl* D) + { + parseRawComment(I.javadoc, D); + addSourceLocation(I, getLine(D), true); + + if(! created) + return; + + I.Name = extractName(D); + + buildExprInfo( + I.Initializer, + D->getInitExpr(), + D->getInitVal()); getParentNamespaces(I, D); } @@ -2289,60 +2348,40 @@ class ASTVisitor void buildFriend( + FriendInfo& I, + bool created, FriendDecl* D) { - if(NamedDecl* ND = D->getFriendDecl()) - { - // D does not name a type - if(FunctionDecl* FD = dyn_cast(ND)) - { - if(! shouldExtract(FD, AccessSpecifier::AS_none)) - return; - - SymbolID id; - if(! extractSymbolID(FD, id)) - return; - auto [I, created] = getOrCreateInfo(id); - buildFunction(I, created, FD); - - const DeclContext* DC = D->getDeclContext(); - const auto* RD = dyn_cast(DC); - // the semantic DeclContext of a FriendDecl must be a class - MRDOCS_ASSERT(RD); - SymbolID parent_id = extractSymbolID(RD); - if(Info* parent = getInfo(parent_id)) - { - MRDOCS_ASSERT(parent->isRecord()); - parent->Implicit &= currentMode() != ExtractMode::Normal; - static_cast(parent)->Friends.emplace_back(I.id); - } - return; - } - if(FunctionTemplateDecl* FT = dyn_cast(ND)) - { - // VFALCO TODO - (void)FT; - return; - } - if(ClassTemplateDecl* CT = dyn_cast(ND)) - { - // VFALCO TODO - (void)CT; - return; - } + parseRawComment(I.javadoc, D); + addSourceLocation(I, getLine(D), true); - MRDOCS_UNREACHABLE(); - } - else if(TypeSourceInfo* TS = D->getFriendType()) - { - (void)TS; + if(! created) return; - } - else + + // A NamedDecl nominated by a FriendDecl + // will be one of the following: + // - FunctionDecl + // - FunctionTemplateDecl + // - ClassTemplateDecl + if(NamedDecl* ND = D->getFriendDecl()) { - MRDOCS_UNREACHABLE(); + extractSymbolID(ND, I.FriendSymbol); + // If this is a friend function declaration naming + // a previously undeclared function, traverse it. + // in addition to this, traverse the declaration if + // it's a class templates first declared as a friend + if((ND->isFunctionOrFunctionTemplate() && + ND->getFriendObjectKind() == Decl::FOK_Undeclared) || + (isa(ND) && ND->isFirstDecl())) + traverseDecl(ND); } - return; + // Since a friend declaration which name non-class types + // will be ignored, a type nominated by a FriendDecl can + // essentially be anything + if(TypeSourceInfo* TSI = D->getFriendType()) + I.FriendType = buildTypeInfo(TSI->getType()); + + getParentNamespaces(I, D); } //------------------------------------------------ @@ -2353,8 +2392,10 @@ class ASTVisitor // enums bool traverse(EnumDecl*); - // KRYSTIAN TODO: friends are a can of worms - // we do not wish to open just yet + // enumerators + bool traverse(EnumConstantDecl*); + + // friends bool traverse(FriendDecl*); // non-static data members @@ -2440,12 +2481,12 @@ traverse(EnumDecl* D) SymbolID id; if(! extractSymbolID(D, id)) - return false; + return true; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); buildEnum(I, created, D); - return true; + return traverseContext(D); } //------------------------------------------------ @@ -2461,7 +2502,7 @@ traverse(FieldDecl* D) SymbolID id; if(! extractSymbolID(D, id)) - return false; + return true; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2469,6 +2510,27 @@ traverse(FieldDecl* D) return true; } +//------------------------------------------------ +// EnumConstantDecl + +bool +ASTVisitor:: +traverse(EnumConstantDecl* D) +{ + AccessSpecifier access = getAccess(D); + if(! shouldExtract(D, access)) + return true; + + SymbolID id; + if(! extractSymbolID(D, id)) + return true; + auto [I, created] = getOrCreateInfo(id); + I.Access = convertToAccessKind(access); + + buildEnumerator(I, created, D); + return true; +} + //------------------------------------------------ // FriendDecl @@ -2476,7 +2538,18 @@ bool ASTVisitor:: traverse(FriendDecl* D) { - buildFriend(D); + AccessSpecifier access = getAccess(D); + if(! shouldExtract(D, access)) + return true; + + SymbolID id; + if(! extractSymbolID(D, id)) + return true; + + auto [I, created] = getOrCreateInfo(id); + I.Access = convertToAccessKind(access); + + buildFriend(I, created, D); return true; } @@ -2494,7 +2567,7 @@ traverse(CXXRecordTy* D, SymbolID id; if(! extractSymbolID(D, id)) - return false; + return true; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2537,7 +2610,7 @@ traverse(VarTy* D, SymbolID id; if(! extractSymbolID(D, id)) - return false; + return true; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2581,7 +2654,7 @@ traverse(FunctionTy* D, SymbolID id; if(! extractSymbolID(D, id)) - return false; + return true; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2622,7 +2695,7 @@ traverse(TypedefNameTy* D, SymbolID id; if(! extractSymbolID(D, id)) - return false; + return true; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2706,8 +2779,7 @@ traverseContext( { MRDOCS_ASSERT(D); for(auto* C : D->decls()) - if(! traverseDecl(C)) - return false; + traverseDecl(C); return true; } diff --git a/src/lib/AST/AnyBlock.hpp b/src/lib/AST/AnyBlock.hpp index e5330fc09..593538cbd 100644 --- a/src/lib/AST/AnyBlock.hpp +++ b/src/lib/AST/AnyBlock.hpp @@ -71,6 +71,7 @@ decodeRecord( Enum& value, llvm::StringRef blob) { + static_assert(! std::same_as); std::underlying_type_t temp; if(auto err = decodeRecord(R, temp, blob)) return err; @@ -143,30 +144,6 @@ decodeRecord( return Error::success(); } -inline -Error -decodeRecord( - Record const& R, - InfoKind& Kind, - llvm::StringRef Blob) -{ - Kind = static_cast(R[0]); - switch(Kind) - { - case InfoKind::Namespace: - case InfoKind::Record: - case InfoKind::Function: - case InfoKind::Enum: - case InfoKind::Typedef: - case InfoKind::Variable: - case InfoKind::Field: - case InfoKind::Specialization: - return Error::success(); - default: - return formatError("InfoKind is invalid"); - } -} - inline Error decodeRecord( @@ -521,23 +498,21 @@ class JavadocBlock //------------------------------------------------ +template class InfoPartBlock : public BitcodeReader::AnyBlock { protected: BitcodeReader& br_; - Info& I; + std::unique_ptr& I_; public: InfoPartBlock( - Info& I, + std::unique_ptr& I, BitcodeReader& br) noexcept : br_(br) - , I(I) + , I_(I) { - // we have to clear Info::Implicit here - // because bitstream elides zero values - I.Implicit = false; } Error @@ -547,15 +522,21 @@ class InfoPartBlock switch(ID) { case INFO_PART_ID: - return decodeRecord(R, I.id, Blob); + { + SymbolID id = SymbolID::invalid; + if(auto err = decodeRecord(R, id, Blob)) + return err; + I_ = std::make_unique(id); + return Error::success(); + } case INFO_PART_ACCESS: - return decodeRecord(R, I.Access, Blob); + return decodeRecord(R, I_->Access, Blob); case INFO_PART_IMPLICIT: - return decodeRecord(R, I.Implicit, Blob); + return decodeRecord(R, I_->Implicit, Blob); case INFO_PART_NAME: - return decodeRecord(R, I.Name, Blob); + return decodeRecord(R, I_->Name, Blob); case INFO_PART_PARENTS: - return decodeRecord(R, I.Namespace, Blob); + return decodeRecord(R, I_->Namespace, Blob); default: return AnyBlock::parseRecord(R, ID, Blob); } @@ -569,7 +550,7 @@ class InfoPartBlock { case BI_JAVADOC_BLOCK_ID: { - JavadocBlock B(I.javadoc, br_); + JavadocBlock B(I_->javadoc, br_); return br_.readBlock(B, ID); } default: @@ -845,58 +826,6 @@ class BaseBlock //------------------------------------------------ -class EnumValueBlock : - public BitcodeReader::AnyBlock -{ - EnumValueInfo& I_; - BitcodeReader& br_; - -public: - EnumValueBlock( - EnumValueInfo& I, - BitcodeReader& br) noexcept - : I_(I) - , br_(br) - { - } - - Error - parseRecord(Record const& R, - unsigned ID, llvm::StringRef Blob) override - { - switch(ID) - { - case ENUM_VALUE_NAME: - return decodeRecord(R, I_.Name, Blob); - default: - return AnyBlock::parseRecord(R, ID, Blob); - } - } - - Error - readSubBlock( - unsigned ID) override - { - switch(ID) - { - case BI_JAVADOC_BLOCK_ID: - { - JavadocBlock B(I_.javadoc, br_); - return br_.readBlock(B, ID); - } - case BI_EXPR_BLOCK_ID: - { - ExprBlock B(I_.Initializer, br_); - return br_.readBlock(B, ID); - } - default: - return AnyBlock::readSubBlock(ID); - } - } -}; - -//------------------------------------------------ - class TemplateArgBlock : public BitcodeReader::AnyBlock { @@ -1285,13 +1214,12 @@ class TopLevelBlock BitcodeReader& br_; public: - std::unique_ptr I; + std::unique_ptr I = nullptr; explicit TopLevelBlock( BitcodeReader& br) : br_(br) - , I(std::make_unique()) { } @@ -1303,14 +1231,8 @@ class TopLevelBlock class NamespaceBlock : public TopLevelBlock { - public: - explicit - NamespaceBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord( @@ -1338,12 +1260,7 @@ class RecordBlock : public TopLevelBlock { public: - explicit - RecordBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord( @@ -1359,8 +1276,6 @@ class RecordBlock return decodeRecord(R, I->IsTypeDef, Blob); case RECORD_BITS: return decodeRecord(R, {&I->specs.raw}, Blob); - case RECORD_FRIENDS: - return decodeRecord(R, I->Friends, Blob); case RECORD_MEMBERS: return decodeRecord(R, I->Members, Blob); case RECORD_SPECIALIZATIONS: @@ -1399,12 +1314,7 @@ class FunctionBlock : public TopLevelBlock { public: - explicit - FunctionBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord(Record const& R, @@ -1454,14 +1364,8 @@ class FunctionBlock class TypedefBlock : public TopLevelBlock { - public: - explicit - TypedefBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord(Record const& R, @@ -1505,12 +1409,7 @@ class EnumBlock : public TopLevelBlock { public: - explicit - EnumBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord(Record const& R, @@ -1520,6 +1419,8 @@ class EnumBlock { case ENUM_SCOPED: return decodeRecord(R, I->Scoped, Blob); + case ENUM_MEMBERS: + return decodeRecord(R, I->Members, Blob); default: return TopLevelBlock::parseRecord(R, ID, Blob); } @@ -1536,12 +1437,6 @@ class EnumBlock TypeInfoBlock B(I->UnderlyingType, br_); return br_.readBlock(B, ID); } - case BI_ENUM_VALUE_BLOCK_ID: - { - I->Members.emplace_back(); - EnumValueBlock B(I->Members.back(), br_); - return br_.readBlock(B, ID); - } default: return TopLevelBlock::readSubBlock(ID); } @@ -1553,14 +1448,8 @@ class EnumBlock class VarBlock : public TopLevelBlock { - public: - explicit - VarBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord(Record const& R, @@ -1604,12 +1493,7 @@ class FieldBlock : public TopLevelBlock { public: - explicit - FieldBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord( @@ -1660,12 +1544,7 @@ class SpecializationBlock : public TopLevelBlock { public: - explicit - SpecializationBlock( - BitcodeReader& br) - : TopLevelBlock(br) - { - } + using TopLevelBlock::TopLevelBlock; Error parseRecord( @@ -1710,6 +1589,86 @@ class SpecializationBlock //------------------------------------------------ +class FriendBlock + : public TopLevelBlock +{ +public: + using TopLevelBlock::TopLevelBlock; + + Error + parseRecord( + Record const& R, + unsigned ID, + llvm::StringRef Blob) override + { + switch(ID) + { + case FRIEND_SYMBOL: + return decodeRecord(R, I->FriendSymbol, Blob); + default: + return TopLevelBlock::parseRecord(R, ID, Blob); + } + } + + Error + readSubBlock( + unsigned ID) override + { + switch(ID) + { + case BI_TYPEINFO_BLOCK_ID: + { + TypeInfoBlock B(I->FriendType, br_); + return br_.readBlock(B, ID); + } + default: + return TopLevelBlock::readSubBlock(ID); + } + } +}; + +//------------------------------------------------ + +class EnumeratorBlock + : public TopLevelBlock +{ +public: + using TopLevelBlock::TopLevelBlock; + + #if 0 + Error + parseRecord( + Record const& R, + unsigned ID, + llvm::StringRef Blob) override + { + switch(ID) + { + default: + return TopLevelBlock::parseRecord(R, ID, Blob); + } + } + #endif + + Error + readSubBlock( + unsigned ID) override + { + switch(ID) + { + case BI_EXPR_BLOCK_ID: + { + ExprBlock B(I->Initializer, br_); + return br_.readBlock(B, ID); + } + default: + return TopLevelBlock::readSubBlock(ID); + } + } +}; + +//------------------------------------------------ + template Error TopLevelBlock:: @@ -1722,7 +1681,7 @@ readSubBlock( { if constexpr(std::derived_from) { - InfoPartBlock B(*I.get(), br_); + InfoPartBlock B(I, br_); return br_.readBlock(B, ID); } break; diff --git a/src/lib/AST/BitcodeIDs.hpp b/src/lib/AST/BitcodeIDs.hpp index 5f488238e..119046806 100644 --- a/src/lib/AST/BitcodeIDs.hpp +++ b/src/lib/AST/BitcodeIDs.hpp @@ -55,7 +55,6 @@ enum BlockID BI_BASE_BLOCK_ID, BI_ENUM_BLOCK_ID, - BI_ENUM_VALUE_BLOCK_ID, BI_EXPR_BLOCK_ID, BI_FIELD_BLOCK_ID, BI_FUNCTION_BLOCK_ID, @@ -69,6 +68,8 @@ enum BlockID BI_TEMPLATE_BLOCK_ID, BI_TEMPLATE_PARAM_BLOCK_ID, BI_SPECIALIZATION_BLOCK_ID, + BI_FRIEND_BLOCK_ID, + BI_ENUMERATOR_BLOCK_ID, BI_TYPEINFO_BLOCK_ID, BI_TYPEINFO_PARENT_BLOCK_ID, BI_TYPEINFO_CHILD_BLOCK_ID, @@ -108,6 +109,7 @@ enum RecordID FIELD_DEFAULT, FIELD_IS_MUTABLE, FIELD_IS_BITFIELD, + FRIEND_SYMBOL, FUNCTION_BITS, FUNCTION_CLASS, FUNCTION_PARAM_NAME, @@ -121,13 +123,10 @@ enum RecordID JAVADOC_NODE_SYMBOLREF, JAVADOC_PARAM_DIRECTION, ENUM_SCOPED, - ENUM_VALUE_NAME, - ENUM_VALUE_VALUE, - ENUM_VALUE_EXPR, + ENUM_MEMBERS, EXPR_WRITTEN, EXPR_VALUE, RECORD_BITS, - RECORD_FRIENDS, RECORD_IS_TYPE_DEF, RECORD_KEY_KIND, RECORD_MEMBERS, diff --git a/src/lib/AST/BitcodeReader.cpp b/src/lib/AST/BitcodeReader.cpp index deeedc444..b5ed6c213 100644 --- a/src/lib/AST/BitcodeReader.cpp +++ b/src/lib/AST/BitcodeReader.cpp @@ -94,8 +94,6 @@ getInfos() Infos.emplace_back(std::move(I)); continue; } - // although fields can only be members of records, - // they are emitted as top-level blocks anyway case BI_FIELD_BLOCK_ID: { MRDOCS_TRY(auto I, readInfo(ID)); @@ -109,6 +107,18 @@ getInfos() Infos.emplace_back(std::move(I)); continue; } + case BI_FRIEND_BLOCK_ID: + { + MRDOCS_TRY(auto I, readInfo(ID)); + Infos.emplace_back(std::move(I)); + continue; + } + case BI_ENUMERATOR_BLOCK_ID: + { + MRDOCS_TRY(auto I, readInfo(ID)); + Infos.emplace_back(std::move(I)); + continue; + } default: // return formatError("invalid top level block"); if (llvm::Error err = Stream.SkipBlock()) @@ -169,7 +179,7 @@ readInfo( T B(*this); if(auto err = readBlock(B, ID)) return Unexpected(err); - return std::move(B.I); + return std::unique_ptr(B.I.release()); } Error diff --git a/src/lib/AST/BitcodeWriter.cpp b/src/lib/AST/BitcodeWriter.cpp index e6015203f..b88d84b8c 100644 --- a/src/lib/AST/BitcodeWriter.cpp +++ b/src/lib/AST/BitcodeWriter.cpp @@ -207,7 +207,6 @@ BlockIdNameMap = []() {BI_SOURCE_INFO_ID, "SourceInfoBlock"}, {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"}, {BI_ENUM_BLOCK_ID, "EnumBlock"}, - {BI_ENUM_VALUE_BLOCK_ID, "EnumValueBlock"}, {BI_EXPR_BLOCK_ID, "ExprBlock"}, {BI_TYPEDEF_BLOCK_ID, "TypedefBlock"}, {BI_TYPEINFO_BLOCK_ID, "TypeInfoBlock"}, @@ -225,6 +224,8 @@ BlockIdNameMap = []() {BI_TEMPLATE_BLOCK_ID, "TemplateBlock"}, {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}, {BI_SPECIALIZATION_BLOCK_ID, "SpecializationBlock"}, + {BI_FRIEND_BLOCK_ID, "FriendBlock"}, + {BI_ENUMERATOR_BLOCK_ID, "EnumeratorBlock"}, {BI_VARIABLE_BLOCK_ID, "VarBlock"} }; MRDOCS_ASSERT(Inits.size() == BlockIdCount); @@ -248,15 +249,14 @@ RecordIDNameMap = []() {BASE_ACCESS, {"BaseAccess", &Integer32Abbrev}}, {BASE_IS_VIRTUAL, {"BaseIsVirtual", &BoolAbbrev}}, {ENUM_SCOPED, {"Scoped", &BoolAbbrev}}, - {ENUM_VALUE_NAME, {"Name", &StringAbbrev}}, - {ENUM_VALUE_VALUE, {"Value", &StringAbbrev}}, - {ENUM_VALUE_EXPR, {"Expr", &StringAbbrev}}, + {ENUM_MEMBERS, {"EnumMembers", &SymbolIDsAbbrev}}, {EXPR_WRITTEN, {"ExprWritten", &StringAbbrev}}, {EXPR_VALUE, {"ExprValue", &Integer64Abbrev}}, {FIELD_DEFAULT, {"DefaultValue", &StringAbbrev}}, {FIELD_ATTRIBUTES, {"FieldAttributes", &Integer32ArrayAbbrev}}, {FIELD_IS_MUTABLE, {"FieldIsMutable", &BoolAbbrev}}, {FIELD_IS_BITFIELD, {"FieldIsBitfield", &BoolAbbrev}}, + {FRIEND_SYMBOL, {"FriendSymbol", &SymbolIDAbbrev}}, {FUNCTION_BITS, {"Bits", &Integer32ArrayAbbrev}}, {FUNCTION_CLASS, {"FunctionClass", &Integer32Abbrev}}, {FUNCTION_PARAM_NAME, {"Name", &StringAbbrev}}, @@ -280,7 +280,6 @@ RecordIDNameMap = []() {RECORD_KEY_KIND, {"KeyKind", &Integer32Abbrev}}, {RECORD_IS_TYPE_DEF, {"IsTypeDef", &BoolAbbrev}}, {RECORD_BITS, {"Bits", &Integer32ArrayAbbrev}}, - {RECORD_FRIENDS, {"Friends", &SymbolIDsAbbrev}}, {RECORD_MEMBERS, {"RecordMembers", &SymbolIDsAbbrev}}, {RECORD_SPECIALIZATIONS, {"RecordSpecializations", &SymbolIDsAbbrev}}, {SPECIALIZATION_PRIMARY, {"SpecializationPrimary", &SymbolIDAbbrev}}, @@ -335,13 +334,10 @@ RecordsByBlock{ {BASE_ACCESS, BASE_IS_VIRTUAL}}, // EnumInfo {BI_ENUM_BLOCK_ID, - {ENUM_SCOPED}}, + {ENUM_SCOPED, ENUM_MEMBERS}}, // ExprInfo and ConstantExprInfo {BI_EXPR_BLOCK_ID, {EXPR_WRITTEN, EXPR_VALUE}}, - // EnumValue - {BI_ENUM_VALUE_BLOCK_ID, - {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}}, // FieldInfo {BI_FIELD_BLOCK_ID, {FIELD_DEFAULT, FIELD_ATTRIBUTES, @@ -369,7 +365,7 @@ RecordsByBlock{ // RecordInfo {BI_RECORD_BLOCK_ID, {RECORD_KEY_KIND, RECORD_IS_TYPE_DEF, RECORD_BITS, - RECORD_FRIENDS, RECORD_MEMBERS, RECORD_SPECIALIZATIONS}}, + RECORD_MEMBERS, RECORD_SPECIALIZATIONS}}, // TArg {BI_TEMPLATE_ARG_BLOCK_ID, {TEMPLATE_ARG_KIND, TEMPLATE_ARG_IS_PACK, @@ -384,6 +380,12 @@ RecordsByBlock{ // SpecializationInfo {BI_SPECIALIZATION_BLOCK_ID, {SPECIALIZATION_PRIMARY, SPECIALIZATION_MEMBERS}}, + // FriendInfo + {BI_FRIEND_BLOCK_ID, + {FRIEND_SYMBOL}}, + // FriendInfo + {BI_ENUMERATOR_BLOCK_ID, + {}}, // TypeInfo {BI_TYPEINFO_BLOCK_ID, {TYPEINFO_KIND, TYPEINFO_IS_PACK, TYPEINFO_ID, TYPEINFO_NAME, @@ -787,31 +789,6 @@ emitBlock( emitBlock(I.Type); } -void -BitcodeWriter:: -emitBlock( - EnumInfo const& I) -{ - StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID); - emitInfoPart(I); - emitSourceInfo(I); - emitRecord(I.Scoped, ENUM_SCOPED); - emitBlock(I.UnderlyingType); - for (const auto& N : I.Members) - emitBlock(N); -} - -void -BitcodeWriter:: -emitBlock( - EnumValueInfo const& I) -{ - StreamSubBlockGuard Block(Stream, BI_ENUM_VALUE_BLOCK_ID); - emitRecord(I.Name, ENUM_VALUE_NAME); - emitBlock(I.Initializer); - emitBlock(I.javadoc); -} - void BitcodeWriter:: emitBlock( @@ -1007,11 +984,23 @@ emitBlock( emitRecord({I.specs.raw}, RECORD_BITS); for (const auto& B : I.Bases) emitBlock(B); - emitRecord(I.Friends, RECORD_FRIENDS); emitRecord(I.Members, RECORD_MEMBERS); emitRecord(I.Specializations, RECORD_SPECIALIZATIONS); } +void +BitcodeWriter:: +emitBlock( + EnumInfo const& I) +{ + StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID); + emitInfoPart(I); + emitSourceInfo(I); + emitRecord(I.Scoped, ENUM_SCOPED); + emitRecord(I.Members, ENUM_MEMBERS); + emitBlock(I.UnderlyingType); +} + void BitcodeWriter:: emitBlock( @@ -1032,6 +1021,30 @@ emitBlock( emitRecord(members, SPECIALIZATION_MEMBERS); } + +void +BitcodeWriter:: +emitBlock( + const FriendInfo& I) +{ + StreamSubBlockGuard Block(Stream, BI_FRIEND_BLOCK_ID); + emitInfoPart(I); + emitSourceInfo(I); + emitRecord(I.FriendSymbol, FRIEND_SYMBOL); + emitBlock(I.FriendType); +} + +void +BitcodeWriter:: +emitBlock( + const EnumeratorInfo& I) +{ + StreamSubBlockGuard Block(Stream, BI_ENUMERATOR_BLOCK_ID); + emitInfoPart(I); + emitSourceInfo(I); + emitBlock(I.Initializer); +} + void BitcodeWriter:: emitBlock( diff --git a/src/lib/AST/BitcodeWriter.hpp b/src/lib/AST/BitcodeWriter.hpp index a678e6d64..6f85f7224 100644 --- a/src/lib/AST/BitcodeWriter.hpp +++ b/src/lib/AST/BitcodeWriter.hpp @@ -107,7 +107,6 @@ class BitcodeWriter void emitBlock(BaseInfo const& I); void emitBlock(EnumInfo const& I); - void emitBlock(EnumValueInfo const& I); void emitBlock(FunctionInfo const& I); void emitBlock(Param const& I); void emitBlock(std::unique_ptr const& jd); @@ -121,6 +120,8 @@ class BitcodeWriter void emitBlock(TypedefInfo const& I); void emitBlock(VariableInfo const& I); void emitBlock(FieldInfo const& I); + void emitBlock(FriendInfo const& I); + void emitBlock(EnumeratorInfo const& I); void emitBlock(std::unique_ptr const& TI); void emitBlock(std::unique_ptr const& TI, BlockID ID); diff --git a/src/lib/Lib/Corpus.cpp b/src/lib/Lib/Corpus.cpp index df724fc58..b85fb4fec 100644 --- a/src/lib/Lib/Corpus.cpp +++ b/src/lib/Lib/Corpus.cpp @@ -67,8 +67,11 @@ getFullyQualifiedName( temp.append("::"); } - auto s = I.extractName(); - temp.append(s.data(), s.size()); + if(I.Name.empty()) + fmt::format_to(std::back_inserter(temp), + "", toString(I.Kind)); + else + temp.append(I.Name); return temp; } diff --git a/src/lib/Lib/Lookup.cpp b/src/lib/Lib/Lookup.cpp index c2f0356a3..594f9a241 100644 --- a/src/lib/Lib/Lookup.cpp +++ b/src/lib/Lib/Lookup.cpp @@ -21,6 +21,7 @@ bool supportsLookup(const Info* info) return info && (info->isRecord() || info->isNamespace() || + info->isEnum() || info->isSpecialization()); } @@ -32,7 +33,10 @@ buildLookups( { visit(info, [&](const InfoTy& I) { - if constexpr(InfoTy::isRecord() || InfoTy::isNamespace()) + if constexpr( + InfoTy::isRecord() || + InfoTy::isNamespace() || + InfoTy::isEnum()) { for(const SymbolID& M : I.Members) { @@ -124,7 +128,7 @@ lookupInContext( context = lookThroughTypedefs(context); // KRYSTIAN FIXME: enumerators need to have their own // info type for lookup to work - if(! context || context->isEnum()) + if(! context) return nullptr; LookupTable& table = lookup_tables_.at(context); // KRYSTIAN FIXME: disambiguation based on signature @@ -135,13 +139,12 @@ lookupInContext( // - namespaces, // - types, and // - templates whose specializations are types - if(for_nns && - (! result->isNamespace() && - ! result->isRecord() && - ! result->isEnum() && - ! result->isTypedef())) - continue; - return result; + if(! for_nns || + result->isNamespace() || + result->isRecord() || + result->isEnum() || + result->isTypedef()) + return result; } // if this is a record and nothing was found, diff --git a/src/lib/Metadata/DomMetadata.cpp b/src/lib/Metadata/DomMetadata.cpp index de1e50f1f..6c8be9cfd 100644 --- a/src/lib/Metadata/DomMetadata.cpp +++ b/src/lib/Metadata/DomMetadata.cpp @@ -455,44 +455,6 @@ class DomBaseArray : public dom::ArrayImpl } }; -//------------------------------------------------ -// -// EnumValueInfo -// -//------------------------------------------------ - -class DomEnumValueArray : public dom::ArrayImpl -{ - std::vector const& list_; - DomCorpus const& domCorpus_; - -public: - DomEnumValueArray( - std::vector const& list, - DomCorpus const& domCorpus) noexcept - : list_(list) - , domCorpus_(domCorpus) - { - } - - std::size_t size() const noexcept override - { - return list_.size(); - } - - dom::Value get(std::size_t i) const override - { - auto const& I = list_.at(i); - return dom::Object({ - { "name", I.Name }, - { "value", I.Initializer.Value ? - dom::Value(*I.Initializer.Value) : dom::Value() }, - { "expr", I.Initializer.Written }, - { "doc", domCreate(I.javadoc, domCorpus_) } - }); - } -}; - //------------------------------------------------ // // Interface @@ -558,7 +520,8 @@ class DomTranche : public dom::DefaultObjectImpl { "types", init(tranche.Types, sp, domCorpus) }, { "field", init(tranche.Data, sp, domCorpus) }, { "staticfuncs",init(tranche.StaticFunctions, sp, domCorpus) }, - { "staticdata", init(tranche.StaticData, sp, domCorpus) } + { "staticdata", init(tranche.StaticData, sp, domCorpus) }, + { "friends", init(tranche.Friends, sp, domCorpus) } }) , sp_(sp) , tranche_(tranche) @@ -647,11 +610,12 @@ DomInfo::construct() const { "kind", toString(I_.Kind) }, { "access", toString(I_.Access) }, { "implicit", I_.Implicit }, - { "name", I_.Name }, { "namespace", dom::newArray( I_.Namespace, domCorpus_) }, { "doc", domCreate(I_.javadoc, domCorpus_) } }); + if(! I_.Name.empty()) + entries.emplace_back("name", I_.Name); if(! I_.Namespace.empty()) entries.emplace_back("parent", domCorpus_.get(I_.Namespace.front())); @@ -675,13 +639,21 @@ DomInfo::construct() const { "defaultAccess", getDefaultAccess(I_) }, { "isTypedef", I_.IsTypeDef }, { "bases", dom::newArray(I_.Bases, domCorpus_) }, - { "friends", dom::newArray(I_.Friends, domCorpus_) }, { "members", dom::newArray(I_.Members, domCorpus_) }, { "specializations",dom::newArray(I_.Specializations, domCorpus_) }, { "interface", dom::newObject(I_, domCorpus_) }, { "template", domCreate(I_.Template, domCorpus_) } }); } + if constexpr(T::isEnum()) + { + entries.insert(entries.end(), { + { "type", domCreate(I_.UnderlyingType, domCorpus_) }, + { "members", dom::newArray( + I_.Members, domCorpus_) }, + { "isScoped", I_.Scoped } + }); + } if constexpr(T::isFunction()) { auto const set_flag = @@ -726,14 +698,6 @@ DomInfo::construct() const { "overloadedOperator", I_.specs0.overloadedOperator.get() }, }); } - if constexpr(T::isEnum()) - { - entries.insert(entries.end(), { - { "type", domCreate(I_.UnderlyingType, domCorpus_) }, - { "members", dom::newArray(I_.Members, domCorpus_) }, - { "isScoped", I_.Scoped } - }); - } if constexpr(T::isTypedef()) { entries.insert(entries.end(), { @@ -771,6 +735,27 @@ DomInfo::construct() const if constexpr(T::isSpecialization()) { } + if constexpr(T::isFriend()) + { + if(I_.FriendSymbol) + { + auto befriended = domCorpus_.get(I_.FriendSymbol); + entries.emplace_back("name", befriended.get("name")); + entries.emplace_back("symbol", befriended); + } + else if(I_.FriendType) + { + auto befriended = domCreate(I_.FriendType, domCorpus_); + entries.emplace_back("name", befriended.get("name")); + entries.emplace_back("type", befriended); + } + } + if constexpr(T::isEnumerator()) + { + entries.insert(entries.end(), { + { "initializer", dom::stringOrNull(I_.Initializer.Written) } + }); + } return dom::Object(std::move(entries)); } diff --git a/src/lib/Metadata/Finalize.cpp b/src/lib/Metadata/Finalize.cpp index f1f379931..a1c7998d7 100644 --- a/src/lib/Metadata/Finalize.cpp +++ b/src/lib/Metadata/Finalize.cpp @@ -260,7 +260,6 @@ class Finalizer finalize(I.Specializations); finalize(I.Template); finalize(I.Bases); - // finalize(I.Friends); } void operator()(SpecializationInfo& I) @@ -292,6 +291,7 @@ class Finalizer void operator()(EnumInfo& I) { check(I.Namespace); + check(I.Members); finalize(I.javadoc); finalize(I.UnderlyingType); } @@ -310,6 +310,20 @@ class Finalizer finalize(I.Template); finalize(I.Type); } + + void operator()(FriendInfo& I) + { + check(I.Namespace); + finalize(I.javadoc); + finalize(I.FriendSymbol); + finalize(I.FriendType); + } + + void operator()(EnumeratorInfo& I) + { + check(I.Namespace); + finalize(I.javadoc); + } }; void finalize(InfoSet& Info, SymbolLookup& Lookup) diff --git a/src/lib/Metadata/Info.cpp b/src/lib/Metadata/Info.cpp index 2139a3e3d..30e0f9063 100644 --- a/src/lib/Metadata/Info.cpp +++ b/src/lib/Metadata/Info.cpp @@ -20,70 +20,6 @@ namespace clang { namespace mrdocs { -std::string -Info:: -extractName() const -{ - if (!Name.empty()) - return Name; - - switch(Kind) - { - case InfoKind::Namespace: - // Cover the case where the project contains a base namespace called - // 'GlobalNamespace' (i.e. a namespace at the same level as the global - // namespace, which would conflict with the hard-coded global namespace name - // below.) - if (Name == "GlobalNamespace" && Namespace.empty()) - return "@GlobalNamespace"; - // The case of anonymous namespaces is taken care of in serialization, - // so here we can safely assume an unnamed namespace is the global - // one. - return {}; //return std::string("GlobalNamespace"); - - // VFALCO This API makes assumptions about what is - // valid in the output format. We could for - // example use base64 or base41... - case InfoKind::Record: - return std::string("@nonymous_record_") + - toBase16(id); - case InfoKind::Function: - return std::string("@nonymous_function_") + - toBase16(id); - case InfoKind::Enum: - return std::string("@nonymous_enum_") + - toBase16(id); - case InfoKind::Typedef: - return std::string("@nonymous_typedef_") + - toBase16(id); - case InfoKind::Variable: - return std::string("@nonymous_var_") + - toBase16(id); - default: - // invalid InfoKind - MRDOCS_UNREACHABLE(); - } -} - -//------------------------------------------------ -#if 0 -std::string& -Info:: -getFullyQualifiedName( - std::string& temp) const -{ - temp.clear(); - for(auto const& ns : llvm::reverse(Namespace)) - { - temp.append(ns.Name.data(), ns.Name.size()); - temp.append("::"); - } - auto s = extractName(); - temp.append(s.data(), s.size()); - return temp; -} -#endif - dom::String toString(InfoKind kind) noexcept { @@ -105,6 +41,10 @@ toString(InfoKind kind) noexcept return "variable"; case InfoKind::Specialization: return "specialization"; + case InfoKind::Friend: + return "friend"; + case InfoKind::Enumerator: + return "enumerator"; default: MRDOCS_UNREACHABLE(); } diff --git a/src/lib/Metadata/Interface.cpp b/src/lib/Metadata/Interface.cpp index 6f0a689e6..aac2441eb 100644 --- a/src/lib/Metadata/Interface.cpp +++ b/src/lib/Metadata/Interface.cpp @@ -44,6 +44,7 @@ class Interface::Build Table data_; Table staticfuncs_; Table staticdata_; + Table friends_; public: Build( @@ -148,6 +149,10 @@ class Interface::Build staticdata_.push_back({ actualAccess, static_cast(&I) }); break; + case InfoKind::Friend: + friends_.push_back({ actualAccess, + static_cast(&I) }); + break; default: MRDOCS_UNREACHABLE(); } @@ -207,6 +212,7 @@ class Interface::Build sort(&Interface::Tranche::Data, I_.data_, data_); sort(&Interface::Tranche::StaticFunctions, I_.staticfuncs_,staticfuncs_); sort(&Interface::Tranche::StaticData, I_.staticdata_, staticdata_); + sort(&Interface::Tranche::Friends, I_.friends_, friends_); #if 0 MRDOCS_ASSERT(I_.Private.Records.empty()); MRDOCS_ASSERT(I_.Private.Functions.empty()); diff --git a/src/lib/Metadata/Reduce.cpp b/src/lib/Metadata/Reduce.cpp index a82183985..051d5583b 100644 --- a/src/lib/Metadata/Reduce.cpp +++ b/src/lib/Metadata/Reduce.cpp @@ -179,7 +179,6 @@ void merge(RecordInfo& I, RecordInfo&& Other) if (I.Bases.empty()) I.Bases = std::move(Other.Bases); // Reduce members if necessary. - reduceSymbolIDs(I.Friends, std::move(Other.Friends)); reduceSymbolIDs(I.Members, std::move(Other.Members)); reduceSymbolIDs(I.Specializations, std::move(Other.Specializations)); // KRYSTIAN FIXME: really should use explicit cases here. @@ -226,8 +225,9 @@ void merge(EnumInfo& I, EnumInfo&& Other) MRDOCS_ASSERT(canMerge(I, Other)); if(! I.Scoped) I.Scoped = Other.Scoped; - if (I.Members.empty()) - I.Members = std::move(Other.Members); + if (! I.UnderlyingType) + I.UnderlyingType = std::move(Other.UnderlyingType); + reduceSymbolIDs(I.Members, std::move(Other.Members)); mergeSourceInfo(I, std::move(Other)); mergeInfo(I, std::move(Other)); } @@ -275,6 +275,25 @@ void merge(SpecializationInfo& I, SpecializationInfo&& Other) } +void merge(FriendInfo& I, FriendInfo&& Other) +{ + MRDOCS_ASSERT(canMerge(I, Other)); + mergeSourceInfo(I, std::move(Other)); + mergeInfo(I, std::move(Other)); + if(! I.FriendSymbol) + I.FriendSymbol = Other.FriendSymbol; + if(! I.FriendType) + I.FriendType = std::move(Other.FriendType); +} + +void merge(EnumeratorInfo& I, EnumeratorInfo&& Other) +{ + MRDOCS_ASSERT(canMerge(I, Other)); + if(I.Initializer.Written.empty()) + I.Initializer = std::move(Other.Initializer); + mergeSourceInfo(I, std::move(Other)); + mergeInfo(I, std::move(Other)); +} } // mrdocs } // clang diff --git a/src/lib/Metadata/Reduce.hpp b/src/lib/Metadata/Reduce.hpp index 787734eb8..1e2b239fe 100644 --- a/src/lib/Metadata/Reduce.hpp +++ b/src/lib/Metadata/Reduce.hpp @@ -29,6 +29,8 @@ void merge(EnumInfo& I, EnumInfo&& Other); void merge(FieldInfo& I, FieldInfo&& Other); void merge(VariableInfo& I, VariableInfo&& Other); void merge(SpecializationInfo& I, SpecializationInfo&& Other); +void merge(FriendInfo& I, FriendInfo&& Other); +void merge(EnumeratorInfo& I, EnumeratorInfo&& Other); // // This file defines the merging of different types of infos. The data in the diff --git a/src/lib/Support/Debug.cpp b/src/lib/Support/Debug.cpp index e94a8731b..a22222909 100644 --- a/src/lib/Support/Debug.cpp +++ b/src/lib/Support/Debug.cpp @@ -51,37 +51,7 @@ format( clang::mrdocs::InfoKind t, fmt::format_context& ctx) const { - const char* str = ""; - switch(t) - { - case clang::mrdocs::InfoKind::Namespace: - str = "namespace"; - break; - case clang::mrdocs::InfoKind::Record: - str = "record"; - break; - case clang::mrdocs::InfoKind::Function: - str = "function"; - break; - case clang::mrdocs::InfoKind::Enum: - str = "enum"; - break; - case clang::mrdocs::InfoKind::Typedef: - str = "typedef"; - break; - case clang::mrdocs::InfoKind::Variable: - str = "variable"; - break; - case clang::mrdocs::InfoKind::Field: - str = "field"; - break; - case clang::mrdocs::InfoKind::Specialization: - str = "specialization"; - break; - default: - break; - } - return fmt::formatter::format(str, ctx); + return fmt::formatter::format(toString(t).str(), ctx); } fmt::format_context::iterator @@ -90,25 +60,7 @@ format( clang::mrdocs::AccessKind a, fmt::format_context& ctx) const { - const char* str = ""; - switch(a) - { - case clang::mrdocs::AccessKind::Public: - str = "public"; - break; - case clang::mrdocs::AccessKind::Protected: - str = "protected"; - break; - case clang::mrdocs::AccessKind::Private: - str = "private"; - break; - case clang::mrdocs::AccessKind::None: - str = "none"; - break; - default: - break; - } - return fmt::formatter::format(str, ctx); + return fmt::formatter::format(toString(a).str(), ctx); } fmt::format_context::iterator diff --git a/src/lib/Support/SafeNames.cpp b/src/lib/Support/SafeNames.cpp index 627ba7c60..dcffca57f 100644 --- a/src/lib/Support/SafeNames.cpp +++ b/src/lib/Support/SafeNames.cpp @@ -69,6 +69,8 @@ class SafeNames::Impl "5variable", "6field", "7specialization", + "8friend", + "9enumeration", }; if(I.isFunction()) { @@ -96,7 +98,7 @@ class SafeNames::Impl return func_reserved[func_idx]; } - std::size_t idx = to_underlying(I.Kind); + std::size_t idx = to_underlying(I.Kind) - 1; MRDOCS_ASSERT(idx < std::size(reserved)); return reserved[idx]; } @@ -183,6 +185,17 @@ class SafeNames::Impl return t.Name; } + if constexpr(T::isFriend()) + { + return getReserved(t); + } + + if constexpr(T::isEnumerator()) + { + MRDOCS_ASSERT(! t.Name.empty()); + return t.Name; + } + MRDOCS_UNREACHABLE(); }); } @@ -256,8 +269,11 @@ class SafeNames::Impl return M; }; - if constexpr(InfoTy::isSpecialization() || - InfoTy::isNamespace() || InfoTy::isRecord()) + if constexpr( + InfoTy::isSpecialization() || + InfoTy::isNamespace() || + InfoTy::isRecord() || + InfoTy::isEnum()) { std::ranges::for_each(I.Members, F, getMember); } diff --git a/test-files/old-tests/enum.cpp b/test-files/old-tests/enum.cpp new file mode 100644 index 000000000..a636a5d50 --- /dev/null +++ b/test-files/old-tests/enum.cpp @@ -0,0 +1,47 @@ +/** E0 brief. + + E0 description. +*/ +enum E0 +{ + /** e0 brief. + + e0 description. + */ + e0 = 1, + /** e1 brief. + + e1 description. + */ + e1 +}; + +enum E1 : char +{ + e2, + e3 +}; + +/** E2 brief. + + E2 description. +*/ +enum class E2 +{ + /** e4 brief. + + e4 description. + */ + e4, + /** e5 brief. + + e5 description. + */ + e5 +}; + +enum class E3 : char +{ + e6, + e7 +}; diff --git a/test-files/old-tests/enum.xml b/test-files/old-tests/enum.xml new file mode 100644 index 000000000..2211b40dc --- /dev/null +++ b/test-files/old-tests/enum.xml @@ -0,0 +1,99 @@ + + + + + + + + E0 brief. + + + E0 description. + + + + + + + e0 brief. + + + e0 description. + + + + + + + + e1 brief. + + + e1 description. + + + + + + + + + + + + + + + + + + + + + + + + E2 brief. + + + E2 description. + + + + + + + e4 brief. + + + e4 description. + + + + + + + + e5 brief. + + + e5 description. + + + + + + + + + + + + + + + + + + diff --git a/test-files/old-tests/friend-1.xml b/test-files/old-tests/friend-1.xml index c2d9143aa..01c520474 100644 --- a/test-files/old-tests/friend-1.xml +++ b/test-files/old-tests/friend-1.xml @@ -4,7 +4,15 @@ - + + + + + f + + + + diff --git a/test-files/old-tests/friend-2.xml b/test-files/old-tests/friend-2.xml index 62e7d53f5..5849affc1 100644 --- a/test-files/old-tests/friend-2.xml +++ b/test-files/old-tests/friend-2.xml @@ -4,7 +4,15 @@ - + + + + + f + + + + diff --git a/test-files/old-tests/friend-3.xml b/test-files/old-tests/friend-3.xml index 446949cd6..b3603071c 100644 --- a/test-files/old-tests/friend-3.xml +++ b/test-files/old-tests/friend-3.xml @@ -4,7 +4,15 @@ - + + + + + T::f + + + + @@ -18,7 +26,10 @@ - + + + + diff --git a/test-files/old-tests/friend-4.xml b/test-files/old-tests/friend-4.xml index 3a2adeaab..7afe157ce 100644 --- a/test-files/old-tests/friend-4.xml +++ b/test-files/old-tests/friend-4.xml @@ -4,7 +4,10 @@ - + + + + @@ -18,7 +21,15 @@ - + + + + + U::f + + + + diff --git a/test-files/old-tests/friend-5.xml b/test-files/old-tests/friend-5.xml index f5fb507e0..2ce3dfe68 100644 --- a/test-files/old-tests/friend-5.xml +++ b/test-files/old-tests/friend-5.xml @@ -4,7 +4,10 @@ - + + + + @@ -18,7 +21,10 @@ - + + + + diff --git a/test-files/old-tests/friend-6.cpp b/test-files/old-tests/friend-6.cpp new file mode 100644 index 000000000..a42012db6 --- /dev/null +++ b/test-files/old-tests/friend-6.cpp @@ -0,0 +1,23 @@ +/// Struct T brief +struct T +{ + /// Friend int brief + friend int; + + /// Friend class Z brief + friend class Z; +}; + +/// Struct U brief +struct U +{ + /// Friend T brief + friend T; +}; + +/// Struct V brief +struct V +{ + /// Friend struct U brief + friend struct U; +}; diff --git a/test-files/old-tests/friend-6.xml b/test-files/old-tests/friend-6.xml new file mode 100644 index 000000000..f2b54842c --- /dev/null +++ b/test-files/old-tests/friend-6.xml @@ -0,0 +1,66 @@ + + + + + + + + Struct T brief + + + + + + + Friend int brief + + + + + + + + + Friend class Z brief + + + + + + + + + + Struct U brief + + + + + + + Friend T brief + + + + + + + + + + Struct V brief + + + + + + + Friend struct U brief + + + + + + + diff --git a/test-files/old-tests/noreturn.xml b/test-files/old-tests/noreturn.xml index 4771a3d55..acc7ed69b 100644 --- a/test-files/old-tests/noreturn.xml +++ b/test-files/old-tests/noreturn.xml @@ -4,12 +4,10 @@ - - @@ -19,6 +17,10 @@ + + + + From 592e196c92e603cabe89be2b97ed6894526d14c9 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Mon, 6 Nov 2023 07:42:20 -0500 Subject: [PATCH 2/2] chore: ASTVisitor cleanup --- src/lib/AST/ASTVisitor.cpp | 736 +++++++++++++----------------- src/lib/AST/ASTVisitorHelpers.hpp | 1 + 2 files changed, 329 insertions(+), 408 deletions(-) diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 3ef288e1d..5201fc1e0 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -407,6 +407,8 @@ class ASTVisitor const Decl* D, SymbolID& id) { + if(! D) + return false; usr_.clear(); if(generateUSR(D)) return false; @@ -424,40 +426,13 @@ class ASTVisitor return id; } - bool - shouldSerializeInfo( - const NamedDecl* D) noexcept - { - // KRYSTIAN FIXME: getting the access of a members - // is not as simple as calling Decl::getAccessUnsafe. - // specifically, templates may not have - // their access set until they are actually instantiated. - return true; - #if 0 - if(config_.includePrivate) - return true; - if(IsOrIsInAnonymousNamespace) - return false; - // bool isPublic() - AccessSpecifier access = D->getAccessUnsafe(); - if(access == AccessSpecifier::AS_private) - return false; - Linkage linkage = D->getLinkageInternal(); - if(linkage == Linkage::ModuleLinkage || - linkage == Linkage::ExternalLinkage) - return true; - // some form of internal linkage - return false; - #endif - } - //------------------------------------------------ AccessSpecifier getAccess(const Decl* D) { // first, get the declaration this was instantiated from - D = getInstantiatedFrom(const_cast(D)); + D = getInstantiatedFrom(D); // if this is the template declaration of a template, // use the access of the template if(const TemplateDecl* TD = D->getDescribedTemplate()) @@ -581,7 +556,7 @@ class ASTVisitor auto I = makeTypeInfo( N->getIdentifier(), quals); - N = cast(getInstantiatedFrom(N)); + N = getInstantiatedFrom(N); // do not generate references to implicit declarations, // template template parameters, or builtin templates if(! isa(N) && @@ -1040,210 +1015,35 @@ class ASTVisitor which were implicitly instantiated, this will be whichever `Decl` was used as the pattern for instantiation. */ - Decl* - getInstantiatedFrom( - Decl* D) - { - if(! D) - return nullptr; + template + DeclTy* getInstantiatedFrom(DeclTy* D); - // KRYSTIAN TODO: support enums & aliases/alias templates - return visit(D, [&]( - DeclTy* DT) -> Decl* - { - constexpr Decl::Kind kind = - DeclToKind(); - - // ------------------------------------------------ - - // FunctionTemplate - if constexpr(kind == Decl::FunctionTemplate) - { - while(auto* MT = DT->getInstantiatedFromMemberTemplate()) - { - if(DT->isMemberSpecialization()) - break; - DT = MT; - } - return DT; - } - // FunctionDecl - // CXXMethodDecl - // CXXConstructorDecl - // CXXConversionDecl - // CXXDeductionGuideDecl - // CXXDestructorDecl - if constexpr(std::derived_from) - { - FunctionDecl* FD = DT; - - const FunctionDecl* DD = nullptr; - if(FD->isDefined(DD, false)) - FD = const_cast(DD); - - if(MemberSpecializationInfo* MSI = - FD->getMemberSpecializationInfo()) - { - if(! MSI->isExplicitSpecialization()) - FD = cast( - MSI->getInstantiatedFrom()); - } - else if(FD->getTemplateSpecializationKind() != - TSK_ExplicitSpecialization) - { - FD = FD->getFirstDecl(); - if(auto* FTD = FD->getPrimaryTemplate()) - { - FTD = cast( - getInstantiatedFrom(FTD)); - FD = FTD->getTemplatedDecl(); - } - } - - return FD; - } - - // ------------------------------------------------ - - // ClassTemplate - if constexpr(kind == Decl::ClassTemplate) - { - while(auto* MT = DT->getInstantiatedFromMemberTemplate()) - { - if(DT->isMemberSpecialization()) - break; - DT = MT; - } - return DT; - } - // ClassTemplatePartialSpecialization - else if constexpr(kind == Decl::ClassTemplatePartialSpecialization) - { - while(auto* MT = DT->getInstantiatedFromMember()) - { - if(DT->isMemberSpecialization()) - break; - DT = MT; - } - } - // ClassTemplateSpecialization - else if constexpr(kind == Decl::ClassTemplateSpecialization) - { - if(! DT->isExplicitSpecialization()) - { - auto inst_from = DT->getSpecializedTemplateOrPartial(); - if(auto* CTPSD = inst_from.template dyn_cast< - ClassTemplatePartialSpecializationDecl*>()) - { - MRDOCS_ASSERT(DT != CTPSD); - return getInstantiatedFrom(CTPSD); - } - // explicit instantiation declaration/definition - else if(auto* CTD = inst_from.template dyn_cast< - ClassTemplateDecl*>()) - { - return getInstantiatedFrom(CTD); - } - } - } - // CXXRecordDecl - // ClassTemplateSpecialization - // ClassTemplatePartialSpecialization - if constexpr(std::derived_from) - { - CXXRecordDecl* RD = DT; - while(MemberSpecializationInfo* MSI = - RD->getMemberSpecializationInfo()) - { - // if this is a member of an explicit specialization, - // then we have the correct declaration - if(MSI->isExplicitSpecialization()) - break; - RD = cast(MSI->getInstantiatedFrom()); - } - return RD; - } - - // ------------------------------------------------ - - // VarTemplate - if constexpr(kind == Decl::VarTemplate) - { - while(auto* MT = DT->getInstantiatedFromMemberTemplate()) - { - if(DT->isMemberSpecialization()) - break; - DT = MT; - } - return DT; - } - // VarTemplatePartialSpecialization - else if constexpr(kind == Decl::VarTemplatePartialSpecialization) - { - while(auto* MT = DT->getInstantiatedFromMember()) - { - if(DT->isMemberSpecialization()) - break; - DT = MT; - } - } - // VarTemplateSpecialization - else if constexpr(kind == Decl::VarTemplateSpecialization) - { - if(! DT->isExplicitSpecialization()) - { - auto inst_from = DT->getSpecializedTemplateOrPartial(); - if(auto* VTPSD = inst_from.template dyn_cast< - VarTemplatePartialSpecializationDecl*>()) - { - MRDOCS_ASSERT(DT != VTPSD); - return getInstantiatedFrom(VTPSD); - } - // explicit instantiation declaration/definition - else if(auto* VTD = inst_from.template dyn_cast< - VarTemplateDecl*>()) - { - return getInstantiatedFrom(VTD); - } - } - } - // VarDecl - // VarTemplateSpecialization - // VarTemplatePartialSpecialization - if constexpr(std::derived_from) - { - VarDecl* VD = DT; - while(MemberSpecializationInfo* MSI = - VD->getMemberSpecializationInfo()) - { - if(MSI->isExplicitSpecialization()) - break; - VD = cast(MSI->getInstantiatedFrom()); - } - return VD; - } - - // ------------------------------------------------ - // EnumDecl - - // VarTemplate - if constexpr(kind == Decl::Enum) - { - EnumDecl* ED = DT; - while(MemberSpecializationInfo* MSI = - ED->getMemberSpecializationInfo()) - { - if(MSI->isExplicitSpecialization()) - break; - ED = cast(MSI->getInstantiatedFrom()); - } - return ED; - } + template + requires std::derived_from || + std::same_as> + FunctionDecl* getInstantiatedFrom(DeclTy* D) + { + return dyn_cast_if_present( + getInstantiatedFrom(D)); + } - return DT; - }); + template + requires std::derived_from || + std::same_as> + CXXRecordDecl* getInstantiatedFrom(DeclTy* D) + { + return dyn_cast_if_present( + getInstantiatedFrom(D)); } + template + requires std::derived_from || + std::same_as> + VarDecl* getInstantiatedFrom(DeclTy* D) + { + return dyn_cast_if_present( + getInstantiatedFrom(D)); + } template Integer @@ -1358,6 +1158,18 @@ class ASTVisitor return TP; } + void + buildTemplateParams( + TemplateInfo& I, + const TemplateParameterList* TPL) + { + for(const NamedDecl* ND : *TPL) + { + I.Params.emplace_back( + buildTemplateParam(ND)); + } + } + std::unique_ptr buildTemplateArg( const TemplateArgument& A) @@ -1471,9 +1283,9 @@ class ASTVisitor void buildTemplateArgs( std::vector>& result, - Range&& range) + Range&& args) { - for(const TemplateArgument& arg : range) + for(const TemplateArgument& arg : args) { // KRYSTIAN NOTE: is this correct? should we have a // separate TArgKind for packs instead of "unlaminating" @@ -1486,97 +1298,16 @@ class ASTVisitor } void - parseTemplateArgs( - TemplateInfo& I, - ClassTemplateSpecializationDecl* spec) - { - if(Decl* primary = getInstantiatedFrom(spec->getSpecializedTemplate())) - extractSymbolID(primary, I.Primary); - // KRYSTIAN NOTE: when this is a partial specialization, we could use - // ClassTemplatePartialSpecializationDecl::getTemplateArgsAsWritten - const TypeSourceInfo* type_written = spec->getTypeAsWritten(); - // if the type as written is nullptr (it should never be), bail - if(! type_written) - return; - auto args = type_written->getType()->getAs< - TemplateSpecializationType>()->template_arguments(); - buildTemplateArgs(I.Args, args); - } - - void - parseTemplateArgs( - TemplateInfo& I, - VarTemplateSpecializationDecl* spec) - { - // unlike function and class templates, the USR generated - // for variable templates differs from that of the VarDecl - // returned by getTemplatedDecl. this might be a clang bug. - // the USR of the templated VarDecl seems to be the correct one. - if(auto* primary = dyn_cast( - getInstantiatedFrom(spec->getSpecializedTemplate()))) - extractSymbolID(primary->getTemplatedDecl(), I.Primary); - const ASTTemplateArgumentListInfo* args_written = nullptr; - // getTemplateArgsInfo returns nullptr for partial specializations, - // so we use getTemplateArgsAsWritten if this is a partial specialization - if(auto* partial = dyn_cast(spec)) - args_written = partial->getTemplateArgsAsWritten(); - else - args_written = spec->getTemplateArgsInfo(); - if(! args_written) - return; - auto args = args_written->arguments(); - buildTemplateArgs(I.Args, std::views::transform( - args, [](auto& x) -> auto& { return x.getArgument(); })); - } - - void - parseTemplateArgs( - TemplateInfo& I, - FunctionTemplateSpecializationInfo* spec) - { - // KRYSTIAN NOTE: do we need to check I->Primary.has_value()? - if(Decl* primary = getInstantiatedFrom(spec->getTemplate())) - extractSymbolID(primary, I.Primary); - // TemplateArguments is used instead of TemplateArgumentsAsWritten - // because explicit specializations of function templates may have - // template arguments deduced from their return type and parameters - if(auto* args = spec->TemplateArguments) - buildTemplateArgs(I.Args, args->asArray()); - } - - void - parseTemplateArgs( - TemplateInfo& I, - const DependentFunctionTemplateSpecializationInfo* spec) + buildTemplateArgs( + std::vector>& result, + const ASTTemplateArgumentListInfo* args) { - // set the ID of the primary template if there is one candidate - if(auto candidates = spec->getCandidates(); - candidates.size() == 1) - { - if(Decl* primary = getInstantiatedFrom(candidates.front())) - extractSymbolID(primary, I.Primary); - } - - if(auto* args_written = spec->TemplateArgumentsAsWritten) - { - buildTemplateArgs(I.Args, std::views::transform( - args_written->arguments(), [](auto& x) -> auto& - { + return buildTemplateArgs(result, + std::views::transform(args->arguments(), + [](auto& x) -> auto& + { return x.getArgument(); - })); - } - } - - void - parseTemplateParams( - TemplateInfo& I, - const TemplateParameterList* TPL) - { - for(const NamedDecl* ND : *TPL) - { - I.Params.emplace_back( - buildTemplateParam(ND)); - } + })); } void @@ -2387,60 +2118,61 @@ class ASTVisitor //------------------------------------------------ // namespaces - bool traverse(NamespaceDecl*); + void traverse(NamespaceDecl*); // enums - bool traverse(EnumDecl*); + void traverse(EnumDecl*); // enumerators - bool traverse(EnumConstantDecl*); + void traverse(EnumConstantDecl*); // friends - bool traverse(FriendDecl*); + void traverse(FriendDecl*); // non-static data members - bool traverse(FieldDecl*); + void traverse(FieldDecl*); template CXXRecordTy> - bool traverse(CXXRecordTy*, ClassTemplateDecl* = nullptr); + void traverse(CXXRecordTy*, ClassTemplateDecl* = nullptr); template VarTy> - bool traverse(VarTy*, VarTemplateDecl* = nullptr); + void traverse(VarTy*, VarTemplateDecl* = nullptr); template FunctionTy> - bool traverse(FunctionTy*, FunctionTemplateDecl* = nullptr); + void traverse(FunctionTy*, FunctionTemplateDecl* = nullptr); template TypedefNameTy> - bool traverse(TypedefNameTy*, TypeAliasTemplateDecl* = nullptr); + void traverse(TypedefNameTy*, TypeAliasTemplateDecl* = nullptr); #if 0 // includes both linkage-specification forms in [dcl.link]: // extern string-literal { declaration-seq(opt) } // extern string-literal name-declaration - bool traverse(LinkageSpecDecl*); - bool traverse(ExternCContextDecl*); - bool traverse(ExportDecl*); + void traverse(LinkageSpecDecl*); + void traverse(ExternCContextDecl*); + void traverse(ExportDecl*); #endif // catch-all function so overload resolution does not // cause a hard error in the Traverse function for Decl template - auto traverse(Decl* D, Args&&...); + void traverse(Decl* D, Args&&...); template - bool traverseDecl(Decl* D, Args&&... args); - bool traverseContext(DeclContext* D); + void traverseDecl(Decl* D, Args&&... args); + + void traverseContext(DeclContext* DC); }; //------------------------------------------------ // NamespaceDecl -bool +void ASTVisitor:: traverse(NamespaceDecl* D) { if(! shouldExtract(D, AccessSpecifier::AS_none)) - return true; + return; if(D->isAnonymousNamespace() && config_->anonymousNamespaces != @@ -2449,125 +2181,122 @@ traverse(NamespaceDecl* D) // always skip anonymous namespaces if so configured if(config_->anonymousNamespaces == ConfigImpl::SettingsImpl::ExtractPolicy::Never) - return true; + return; // otherwise, skip extraction if this isn't a dependency // KRYSTIAN FIXME: is this correct? a namespace should not // be extracted as a dependency (until namespace aliases and // using directives are supported) if(currentMode() == ExtractMode::Normal) - return true; + return; } SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); buildNamespace(I, created, D); - return traverseContext(D); + traverseContext(D); } //------------------------------------------------ // EnumDecl -bool +void ASTVisitor:: traverse(EnumDecl* D) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); buildEnum(I, created, D); - return traverseContext(D); + traverseContext(D); } //------------------------------------------------ // FieldDecl -bool +void ASTVisitor:: traverse(FieldDecl* D) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); buildField(I, created, D); - return true; } //------------------------------------------------ // EnumConstantDecl -bool +void ASTVisitor:: traverse(EnumConstantDecl* D) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); buildEnumerator(I, created, D); - return true; } //------------------------------------------------ // FriendDecl -bool +void ASTVisitor:: traverse(FriendDecl* D) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); buildFriend(I, created, D); - return true; } //------------------------------------------------ template CXXRecordTy> -bool +void ASTVisitor:: traverse(CXXRecordTy* D, ClassTemplateDecl* CTD) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2576,41 +2305,46 @@ traverse(CXXRecordTy* D, // explicit specialization, and the described template otherwise if(CTD) { - I.Template = std::make_unique(); + auto& Template = I.Template = std::make_unique(); // if D is a partial/explicit specialization, extract the template arguments if(auto* CTSD = dyn_cast(D)) { - parseTemplateArgs(*I.Template, CTSD); + extractSymbolID(getInstantiatedFrom(CTD), Template->Primary); + // KRYSTIAN NOTE: when this is a partial specialization, we could use + // ClassTemplatePartialSpecializationDecl::getTemplateArgsAsWritten + MRDOCS_ASSERT(CTSD->getTypeAsWritten()); + const TypeSourceInfo* TSI = CTSD->getTypeAsWritten(); + buildTemplateArgs(Template->Args, TSI->getType()->getAs< + TemplateSpecializationType>()->template_arguments()); + // extract the template parameters if this is a partial specialization if(auto* CTPSD = dyn_cast(D)) - parseTemplateParams(*I.Template, - CTPSD->getTemplateParameters()); + buildTemplateParams(*I.Template, CTPSD->getTemplateParameters()); } else { // otherwise, extract the template parameter list from CTD - parseTemplateParams(*I.Template, - CTD->getTemplateParameters()); + buildTemplateParams(*I.Template, CTD->getTemplateParameters()); } } buildRecord(I, created, D); - return traverseContext(D); + traverseContext(D); } template VarTy> -bool +void ASTVisitor:: traverse(VarTy* D, VarTemplateDecl* VTD) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2619,42 +2353,46 @@ traverse(VarTy* D, // explicit specialization, and the described template otherwise if(VTD) { - I.Template = std::make_unique(); + auto& Template = I.Template = std::make_unique(); // if D is a partial/explicit specialization, extract the template arguments if(auto* VTSD = dyn_cast(D)) { - parseTemplateArgs(*I.Template, VTSD); + extractSymbolID(getInstantiatedFrom(VTD), Template->Primary); + const ASTTemplateArgumentListInfo* Args = VTSD->getTemplateArgsInfo(); // extract the template parameters if this is a partial specialization if(auto* VTPSD = dyn_cast(D)) - parseTemplateParams(*I.Template, - VTPSD->getTemplateParameters()); + { + // getTemplateArgsInfo returns nullptr for partial specializations, + // so we use getTemplateArgsAsWritten if this is a partial specialization + Args = VTPSD->getTemplateArgsAsWritten(); + buildTemplateParams(*I.Template, VTPSD->getTemplateParameters()); + } + buildTemplateArgs(Template->Args, Args); } else { // otherwise, extract the template parameter list from VTD - parseTemplateParams(*I.Template, - VTD->getTemplateParameters()); + buildTemplateParams(*I.Template, VTD->getTemplateParameters()); } } buildVariable(I, created, D); - return true; } template FunctionTy> -bool +void ASTVisitor:: traverse(FunctionTy* D, FunctionTemplateDecl* FTD) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2662,40 +2400,50 @@ traverse(FunctionTy* D, // D is the templated declaration if FTD is non-null if(FTD || D->isFunctionTemplateSpecialization()) { - I.Template = std::make_unique(); + auto& Template = I.Template = std::make_unique(); - if(FTD) + if(auto* FTSI = D->getTemplateSpecializationInfo()) { - parseTemplateParams(*I.Template, - FTD->getTemplateParameters()); + extractSymbolID(getInstantiatedFrom( + FTSI->getTemplate()), Template->Primary); + // TemplateArguments is used instead of TemplateArgumentsAsWritten + // because explicit specializations of function templates may have + // template arguments deduced from their return type and parameters + if(auto* Args = FTSI->TemplateArguments) + buildTemplateArgs(Template->Args, Args->asArray()); } - else if(auto* FTSI = D->getTemplateSpecializationInfo()) + else if(auto* DFTSI = D->getDependentSpecializationInfo()) { - parseTemplateArgs(*I.Template, FTSI); + // Only extract the ID of the primary template if there is + // a single candidate primary template. + if(auto Candidates = DFTSI->getCandidates(); Candidates.size() == 1) + extractSymbolID(getInstantiatedFrom( + Candidates.front()), Template->Primary); + if(auto* Args = DFTSI->TemplateArgumentsAsWritten) + buildTemplateArgs(Template->Args, Args); } - else if(auto* DFTSI = D->getDependentSpecializationInfo()) + else { - parseTemplateArgs(*I.Template, DFTSI); + buildTemplateParams(*Template, FTD->getTemplateParameters()); } } buildFunction(I, created, D); - return true; } template TypedefNameTy> -bool +void ASTVisitor:: traverse(TypedefNameTy* D, TypeAliasTemplateDecl* ATD) { AccessSpecifier access = getAccess(D); if(! shouldExtract(D, access)) - return true; + return; SymbolID id; if(! extractSymbolID(D, id)) - return true; + return; auto [I, created] = getOrCreateInfo(id); I.Access = convertToAccessKind(access); @@ -2706,21 +2454,19 @@ traverse(TypedefNameTy* D, if(ATD) { I.Template = std::make_unique(); - parseTemplateParams(*I.Template, + buildTemplateParams(*I.Template, ATD->getTemplateParameters()); } buildTypedef(I, created, D); - return true; } -//------------------------------------------------ - template -auto +void ASTVisitor:: traverse(Decl* D, Args&&...) { + // if this is a DeclContext, traverse its members if(auto* DC = dyn_cast(D)) traverseContext(DC); } @@ -2728,7 +2474,7 @@ traverse(Decl* D, Args&&...) //------------------------------------------------ template -bool +void ASTVisitor:: traverseDecl( Decl* D, @@ -2737,7 +2483,7 @@ traverseDecl( MRDOCS_ASSERT(D); if(D->isInvalidDecl() || D->isImplicit()) - return true; + return; SymbolFilter::FilterScope scope(symbolFilter_); @@ -2768,19 +2514,193 @@ traverseDecl( traverse(DD, std::forward(args)...); } }); +} - return true; +void +ASTVisitor:: +traverseContext(DeclContext* DC) +{ + for(auto* D : DC->decls()) + traverseDecl(D); } -bool +//------------------------------------------------ + +class InstantiatedFromVisitor + : public DeclVisitor +{ +public: + Decl* VisitDecl(Decl* D) { return D; } + + FunctionDecl* VisitFunctionTemplateDecl(FunctionTemplateDecl* D) + { + while(auto* MT = D->getInstantiatedFromMemberTemplate()) + { + if(D->isMemberSpecialization()) + break; + D = MT; + } + return D->getTemplatedDecl(); + } + + CXXRecordDecl* VisitClassTemplateDecl(ClassTemplateDecl* D) + { + while(auto* MT = D->getInstantiatedFromMemberTemplate()) + { + if(D->isMemberSpecialization()) + break; + D = MT; + } + return D->getTemplatedDecl(); + } + + VarDecl* VisitVarTemplateDecl(VarTemplateDecl* D) + { + while(auto* MT = D->getInstantiatedFromMemberTemplate()) + { + if(D->isMemberSpecialization()) + break; + D = MT; + } + return D->getTemplatedDecl(); + } + + FunctionDecl* VisitFunctionDecl(FunctionDecl* D) + { + const FunctionDecl* DD = nullptr; + if(D->isDefined(DD, false)) + D = const_cast(DD); + + if(MemberSpecializationInfo* MSI = + D->getMemberSpecializationInfo()) + { + if(! MSI->isExplicitSpecialization()) + D = cast( + MSI->getInstantiatedFrom()); + } + else if(D->getTemplateSpecializationKind() != + TSK_ExplicitSpecialization) + { + D = D->getFirstDecl(); + if(auto* FTD = D->getPrimaryTemplate()) + D = VisitFunctionTemplateDecl(FTD); + } + + return D; + } + + CXXRecordDecl* VisitClassTemplatePartialSpecializationDecl(ClassTemplatePartialSpecializationDecl* D) + { + while(auto* MT = D->getInstantiatedFromMember()) + { + if(D->isMemberSpecialization()) + break; + D = MT; + } + return VisitClassTemplateSpecializationDecl(D); + } + + CXXRecordDecl* VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl* D) + { + if(! D->isExplicitSpecialization()) + { + auto inst_from = D->getSpecializedTemplateOrPartial(); + if(auto* CTPSD = inst_from.dyn_cast< + ClassTemplatePartialSpecializationDecl*>()) + { + MRDOCS_ASSERT(D != CTPSD); + return VisitClassTemplatePartialSpecializationDecl(CTPSD); + } + // explicit instantiation declaration/definition + else if(auto* CTD = inst_from.dyn_cast< + ClassTemplateDecl*>()) + { + return VisitClassTemplateDecl(CTD); + } + } + return VisitCXXRecordDecl(D); + } + + CXXRecordDecl* VisitCXXRecordDecl(CXXRecordDecl* D) + { + while(MemberSpecializationInfo* MSI = + D->getMemberSpecializationInfo()) + { + // if this is a member of an explicit specialization, + // then we have the correct declaration + if(MSI->isExplicitSpecialization()) + break; + D = cast(MSI->getInstantiatedFrom()); + } + return D; + } + + VarDecl* VisitVarTemplatePartialSpecializationDecl(VarTemplatePartialSpecializationDecl* D) + { + while(auto* MT = D->getInstantiatedFromMember()) + { + if(D->isMemberSpecialization()) + break; + D = MT; + } + return VisitVarTemplateSpecializationDecl(D); + } + + VarDecl* VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl* D) + { + if(! D->isExplicitSpecialization()) + { + auto inst_from = D->getSpecializedTemplateOrPartial(); + if(auto* VTPSD = inst_from.dyn_cast< + VarTemplatePartialSpecializationDecl*>()) + { + MRDOCS_ASSERT(D != VTPSD); + return VisitVarTemplatePartialSpecializationDecl(VTPSD); + } + // explicit instantiation declaration/definition + else if(auto* VTD = inst_from.dyn_cast< + VarTemplateDecl*>()) + { + return VisitVarTemplateDecl(VTD); + } + } + return VisitVarDecl(D); + } + + VarDecl* VisitVarDecl(VarDecl* D) + { + while(MemberSpecializationInfo* MSI = + D->getMemberSpecializationInfo()) + { + if(MSI->isExplicitSpecialization()) + break; + D = cast(MSI->getInstantiatedFrom()); + } + return D; + } + + EnumDecl* VisitEnumDecl(EnumDecl* D) + { + while(MemberSpecializationInfo* MSI = + D->getMemberSpecializationInfo()) + { + if(MSI->isExplicitSpecialization()) + break; + D = cast(MSI->getInstantiatedFrom()); + } + return D; + } +}; + +template +DeclTy* ASTVisitor:: -traverseContext( - DeclContext* D) +getInstantiatedFrom(DeclTy* D) { - MRDOCS_ASSERT(D); - for(auto* C : D->decls()) - traverseDecl(C); - return true; + if(! D) + return nullptr; + return cast(InstantiatedFromVisitor().Visit( + const_cast(static_cast(D)))); } #if 0 diff --git a/src/lib/AST/ASTVisitorHelpers.hpp b/src/lib/AST/ASTVisitorHelpers.hpp index 84df92092..3a696cfc6 100644 --- a/src/lib/AST/ASTVisitorHelpers.hpp +++ b/src/lib/AST/ASTVisitorHelpers.hpp @@ -271,6 +271,7 @@ visit( Visitor&& visitor, Args&&... args) { + MRDOCS_ASSERT(D); switch(D->getKind()) { #define ABSTRACT_DECL(TYPE)