From aa4e6ff02317576ee22a73ef0c697a56353aafcc Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Fri, 8 Dec 2023 09:52:14 -0500 Subject: [PATCH] feat: represent possibly-qualified names with NameInfo --- include/mrdocs/Metadata.hpp | 1 + include/mrdocs/Metadata/Name.hpp | 112 ++ include/mrdocs/Metadata/Type.hpp | 6 + include/mrdocs/MetadataFwd.hpp | 1 + .../partials/declarator-before.adoc.hbs | 3 +- .../asciidoc/partials/name-info.adoc.hbs | 8 + src/lib/AST/ASTVisitor.cpp | 1297 ++++++++++------- src/lib/AST/AnyBlock.hpp | 83 ++ src/lib/AST/BitcodeIDs.hpp | 5 + src/lib/AST/BitcodeWriter.cpp | 33 +- src/lib/AST/BitcodeWriter.hpp | 1 + src/lib/Metadata/DomMetadata.cpp | 29 + src/lib/Metadata/Finalize.cpp | 16 + src/lib/Metadata/Interface.cpp | 3 +- src/lib/Metadata/Name.cpp | 30 + 15 files changed, 1123 insertions(+), 505 deletions(-) create mode 100644 include/mrdocs/Metadata/Name.hpp create mode 100644 share/mrdocs/addons/generator/asciidoc/partials/name-info.adoc.hbs create mode 100644 src/lib/Metadata/Name.cpp diff --git a/include/mrdocs/Metadata.hpp b/include/mrdocs/Metadata.hpp index e0f6ceb27..a7474c88a 100644 --- a/include/mrdocs/Metadata.hpp +++ b/include/mrdocs/Metadata.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/include/mrdocs/Metadata/Name.hpp b/include/mrdocs/Metadata/Name.hpp new file mode 100644 index 000000000..4b79a5d1d --- /dev/null +++ b/include/mrdocs/Metadata/Name.hpp @@ -0,0 +1,112 @@ +// +// 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_NAME_HPP +#define MRDOCS_API_METADATA_NAME_HPP + +#include +#include +#include +#include +#include + +namespace clang { +namespace mrdocs { + +enum class NameKind +{ + Identifier = 1, // for bitstream + Specialization +}; + +MRDOCS_DECL +dom::String +toString(NameKind kind) noexcept; + +/** Represents a (possibly qualified) symbol name. +*/ +struct NameInfo +{ + /** The kind of name this is. + */ + NameKind Kind; + + /** The SymbolID of the named symbol, if it exists. + */ + SymbolID id = SymbolID::invalid; + + /** The unqualified name. + */ + std::string Name; + + /** The parent name info, if any. + */ + std::unique_ptr Prefix; + + constexpr + NameInfo() noexcept + : NameInfo(NameKind::Identifier) + { + } + + constexpr + NameInfo(NameKind kind) noexcept + : Kind(kind) + { + } + + virtual ~NameInfo() = default; +}; + +/** Represents a (possibly qualified) symbol name with template arguments. +*/ +struct SpecializationNameInfo + : NameInfo +{ + /** The template arguments. + */ + std::vector> TemplateArgs; + + constexpr + SpecializationNameInfo() noexcept + : NameInfo(NameKind::Specialization) + { + } +}; + +template< + class NameInfoTy, + class Fn, + class... Args> + requires std::derived_from +decltype(auto) +visit( + NameInfoTy& info, + Fn&& fn, + Args&&... args) +{ + auto visitor = makeVisitor( + info, std::forward(fn), + std::forward(args)...); + switch(info.Kind) + { + case NameKind::Identifier: + return visitor.template visit(); + case NameKind::Specialization: + return visitor.template visit(); + default: + MRDOCS_UNREACHABLE(); + } +} + +} // mrdocs +} // clang + +#endif diff --git a/include/mrdocs/Metadata/Type.hpp b/include/mrdocs/Metadata/Type.hpp index 5ea1e381e..75da21c28 100644 --- a/include/mrdocs/Metadata/Type.hpp +++ b/include/mrdocs/Metadata/Type.hpp @@ -122,6 +122,8 @@ struct BuiltinTypeInfo { QualifierKind CVQualifiers = QualifierKind::None; std::string Name; + + std::unique_ptr Name_; }; struct TagTypeInfo @@ -131,6 +133,8 @@ struct TagTypeInfo std::unique_ptr ParentType; std::string Name; SymbolID id = SymbolID::invalid; + + std::unique_ptr Name_; }; struct SpecializationTypeInfo @@ -141,6 +145,8 @@ struct SpecializationTypeInfo std::string Name; SymbolID id = SymbolID::invalid; std::vector> TemplateArgs; + + std::unique_ptr Name_; }; struct DecltypeTypeInfo diff --git a/include/mrdocs/MetadataFwd.hpp b/include/mrdocs/MetadataFwd.hpp index b345c5d91..d91270699 100644 --- a/include/mrdocs/MetadataFwd.hpp +++ b/include/mrdocs/MetadataFwd.hpp @@ -46,6 +46,7 @@ struct Info; class Javadoc; struct Location; struct NamespaceInfo; +struct NameInfo; struct RecordInfo; struct Param; struct SpecializationInfo; diff --git a/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs index ccfb40f19..8b768f25c 100644 --- a/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs +++ b/share/mrdocs/addons/generator/asciidoc/partials/declarator-before.adoc.hbs @@ -12,7 +12,8 @@ {{#if cv-qualifiers~}} {{#if pointee-type}} {{cv-qualifiers}}{{else}}{{cv-qualifiers}} {{/if~}} {{/if~}} -{{#if (and symbol (not parent-type))}}{{>qualified-path symbol=symbol.parent nolink=nolink}}{{/if~}} +{{#if prefix~}}{{>name-info prefix nolink=nolink}}{{/if~}} +{{!-- {{#if (and symbol (not parent-type))}}{{>qualified-path symbol=symbol.parent nolink=nolink}}{{/if~}} --~}} {{#if (and symbol (not nolink))~}} xref:{{symbol.ref}}[{{name}}] {{~else if name}}{{name~}} diff --git a/share/mrdocs/addons/generator/asciidoc/partials/name-info.adoc.hbs b/share/mrdocs/addons/generator/asciidoc/partials/name-info.adoc.hbs new file mode 100644 index 000000000..7d9bca427 --- /dev/null +++ b/share/mrdocs/addons/generator/asciidoc/partials/name-info.adoc.hbs @@ -0,0 +1,8 @@ +{{#unless (or (contains @root.symbol.namespace symbol) (eq @root.symbol symbol))~}} +{{#if prefix~}} +{{>name-info prefix nolink=nolink~}} +{{else~}} +{{/if~}} +{{#if (and symbol.ref (not nolink))}}xref:{{symbol.ref}}[{{name}}]{{else~}} +{{name}}{{/if}}{{#if args}}{{>template-args args=args nolink=nolink}}{{/if}}:: +{{~/unless}} \ No newline at end of file diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 25e8ec010..93bd6699e 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -438,6 +439,14 @@ class ASTVisitor return {static_cast(*info), created}; } + void + getDependencyID( + const Decl* D, + SymbolID& id) + { + return getDependencyID(const_cast(D), id); + } + void getDependencyID( Decl* D, @@ -484,7 +493,8 @@ class ASTVisitor while((DC = DC->getParent())); // add the adjusted declaration to the set of dependencies - dependencies_.insert(Outer); + if(! isa(Outer)) + dependencies_.insert(Outer); } //------------------------------------------------ @@ -717,513 +727,29 @@ class ASTVisitor return result; } - std::string getTypeAsString(QualType T) - { - return T.getAsString(context_.getPrintingPolicy()); - } - - NamedDecl* - lookupTypedefInPrimary( - TypedefNameDecl* TD) + std::string getTypeAsString(const Type* T) { - if(auto* R = dyn_cast( - TD->getDeclContext())) + if(auto* AT = dyn_cast_if_present(T)) { - if(CXXRecordDecl* IP = R->getTemplateInstantiationPattern()) - R = IP; - if(DeclarationName TDN = TD->getDeclName(); - R && ! TDN.isEmpty()) + switch(AT->getKeyword()) { - auto found = R->lookup(TDN); - MRDOCS_ASSERT(found.isSingleResult()); - MRDOCS_ASSERT(isa(found.front()) || - isa(found.front())); - return found.front(); + case AutoTypeKeyword::Auto: + case AutoTypeKeyword::GNUAutoType: + return "auto"; + case AutoTypeKeyword::DecltypeAuto: + return "decltype(auto)"; + default: + MRDOCS_UNREACHABLE(); } } - return nullptr; - } - - template - std::unique_ptr - makeTypeInfo( - const IdentifierInfo* II, - unsigned quals) - { - auto I = std::make_unique(); - I->CVQualifiers = convertToQualifierKind(quals); - if(II) - I->Name = II->getName(); - return I; - } - - template - std::unique_ptr - makeTypeInfo( - NamedDecl* N, - unsigned quals) - { - auto I = makeTypeInfo( - N->getIdentifier(), quals); - - N = getInstantiatedFrom(N); - // do not generate references to implicit declarations, - // template template parameters, or builtin templates - if(! isa(N) && - ! isa(N)) + if(auto* TTPT = dyn_cast_if_present(T)) { - if(auto* TD = dyn_cast(N)) - { - if(auto* PTD = lookupTypedefInPrimary(TD)) - N = PTD; - } - else if(auto* ATD = dyn_cast(N)) - { - if(auto* MT = ATD->getInstantiatedFromMemberTemplate()) - ATD = MT; - auto* TD = ATD->getTemplatedDecl(); - if(auto* R = dyn_cast(TD->getDeclContext())) - { - // KRYSTIAN FIXME: this appears to not work - if(auto* PATD = lookupTypedefInPrimary(TD)) - N = PATD; - } - } - - getDependencyID(N, I->id); - } - return I; - } - - template< - std::same_as TypeInfoTy, - typename DeclOrName, - typename TArgsRange> - std::unique_ptr - makeTypeInfo( - DeclOrName&& N, - unsigned quals, - TArgsRange&& targs) - { - auto I = makeTypeInfo( - std::forward(N), quals); - buildTemplateArgs(I->TemplateArgs, - std::forward(targs)); - return I; - } - - void - buildParentTypeInfo( - std::unique_ptr& Parent, - const NestedNameSpecifier* NNS, - ExtractMode extract_mode) - { - if(! NNS) - return; - // extraction for parents of a terminal TypeInfo - // node use the same mode as that node - if(const auto* T = NNS->getAsType()) - { - Parent = buildTypeInfo( - QualType(T, 0), - extract_mode); - } - else if(const auto* II = NNS->getAsIdentifier()) - { - auto R = std::make_unique(); - buildParentTypeInfo( - R->ParentType, - NNS->getPrefix(), - extract_mode); - R->Name = II->getName(); - Parent = std::move(R); - } - } - - std::unique_ptr - buildTypeInfo( - QualType qt, - ExtractMode extract_mode = ExtractMode::IndirectDependency) - { - // extract_mode is only used during the extraction - // the terminal type & its parents; the extraction of - // function parameters, template arguments, and the parent class - // of member pointers is done in ExtractMode::IndirectDependency - ExtractionScope scope = enterMode(extract_mode); - - std::unique_ptr result; - std::unique_ptr* inner = &result; - - // nested name specifier used for the terminal type node - NestedNameSpecifier* NNS = nullptr; - - // whether this is a pack expansion - bool is_pack_expansion = false; - - while(true) - { - // should never be called for a null QualType - MRDOCS_ASSERT(! qt.isNull()); - const Type* type = qt.getTypePtr(); - unsigned quals = qt.getLocalFastQualifiers(); - - switch(qt->getTypeClass()) - { - // parenthesized types - case Type::Paren: - { - auto* T = cast(type); - qt = T->getInnerType().withFastQualifiers(quals); - continue; - } - case Type::MacroQualified: - { - auto* T = cast(type); - qt = T->getUnderlyingType().withFastQualifiers(quals); - continue; - } - // type with __atribute__ - case Type::Attributed: - { - auto* T = cast(type); - qt = T->getModifiedType().withFastQualifiers(quals); - continue; - } - // adjusted and decayed types - case Type::Decayed: - case Type::Adjusted: - { - auto* T = cast(type); - qt = T->getOriginalType().withFastQualifiers(quals); - continue; - } - // using declarations - case Type::Using: - { - auto* T = cast(type); - // look through the using declaration and - // use the the type from the referenced declaration - qt = T->getUnderlyingType().withFastQualifiers(quals); - continue; - } - case Type::SubstTemplateTypeParm: - { - auto* T = cast(type); - qt = T->getReplacementType().withFastQualifiers(quals); - continue; - } - // pack expansion - case Type::PackExpansion: - { - auto* T = cast(type); - // we just use a flag to represent whether this is - // a pack expansion rather than a type kind - is_pack_expansion = true; - qt = T->getPattern().withFastQualifiers(quals); - continue; - } - // pointers - case Type::Pointer: - { - auto* T = cast(type); - auto I = std::make_unique(); - I->CVQualifiers = convertToQualifierKind(quals); - *std::exchange(inner, &I->PointeeType) = std::move(I); - qt = T->getPointeeType(); - continue; - } - // references - case Type::LValueReference: - { - auto* T = cast(type); - auto I = std::make_unique(); - *std::exchange(inner, &I->PointeeType) = std::move(I); - qt = T->getPointeeType(); - continue; - } - case Type::RValueReference: - { - auto* T = cast(type); - auto I = std::make_unique(); - *std::exchange(inner, &I->PointeeType) = std::move(I); - qt = T->getPointeeType(); - continue; - } - // pointer to members - case Type::MemberPointer: - { - auto* T = cast(type); - auto I = std::make_unique(); - I->CVQualifiers = convertToQualifierKind(quals); - // do not set NNS because the parent type is *not* - // a nested-name-specifier which qualifies the pointee type - I->ParentType = buildTypeInfo(QualType(T->getClass(), 0)); - *std::exchange(inner, &I->PointeeType) = std::move(I); - qt = T->getPointeeType(); - continue; - } - // KRYSTIAN NOTE: we don't handle FunctionNoProto here, - // and it's unclear if we should. we should not encounter - // such types in c++ (but it might be possible?) - // functions - case Type::FunctionProto: - { - auto* T = cast(type); - auto I = std::make_unique(); - for(QualType PT : T->getParamTypes()) - I->ParamTypes.emplace_back(buildTypeInfo(PT)); - I->RefQualifier = convertToReferenceKind( - T->getRefQualifier()); - I->CVQualifiers = convertToQualifierKind( - T->getMethodQuals().getFastQualifiers()); - buildNoexceptInfo(I->ExceptionSpec, T); - *std::exchange(inner, &I->ReturnType) = std::move(I); - qt = T->getReturnType(); - continue; - } - // KRYSTIAN FIXME: do we handle variables arrays? - // they can only be created within function scope - // arrays - case Type::IncompleteArray: - { - auto* T = cast(type); - auto I = std::make_unique(); - *std::exchange(inner, &I->ElementType) = std::move(I); - qt = T->getElementType(); - continue; - } - case Type::ConstantArray: - { - auto* T = cast(type); - auto I = std::make_unique(); - // KRYSTIAN FIXME: this is broken; cannonical - // constant array types never have a size expression - buildExprInfo(I->Bounds, T->getSizeExpr(), T->getSize()); - *std::exchange(inner, &I->ElementType) = std::move(I); - qt = T->getElementType(); - continue; - } - case Type::DependentSizedArray: - { - auto* T = cast(type); - auto I = std::make_unique(); - buildExprInfo(I->Bounds, T->getSizeExpr()); - *std::exchange(inner, &I->ElementType) = std::move(I); - qt = T->getElementType(); - continue; - } - - // ------------------------------------------------ - // terminal TypeInfo nodes - case Type::Decltype: - { - auto* T = cast(type); - auto I = std::make_unique(); - buildExprInfo(I->Operand, T->getUnderlyingExpr()); - I->CVQualifiers = convertToQualifierKind(quals); - *inner = std::move(I); - break; - } - case Type::Auto: - { - auto* T = cast(type); - QualType deduced = T->getDeducedType(); - // KRYSTIAN NOTE: we don't use isDeduced because it will - // return true if the type is dependent - // if the type has been deduced, use the deduced type - if(! deduced.isNull()) - { - qt = deduced; - continue; - } - // otherwise, use the placeholder type specifier - auto I = std::make_unique(); - I->Name = getTypeAsString( - qt.withoutLocalFastQualifiers()); - I->CVQualifiers = convertToQualifierKind(quals); - *inner = std::move(I); - break; - } - case Type::DeducedTemplateSpecialization: - { - auto* T = cast(type); - QualType deduced = T->getDeducedType(); - // if(! T->isDeduced()) - if(! deduced.isNull()) - { - qt = deduced; - continue; - } - *inner = makeTypeInfo( - T->getTemplateName().getAsTemplateDecl(), quals); - break; - } - // elaborated type specifier or - // type with nested name specifier - case Type::Elaborated: - { - auto* T = cast(type); - // there should only ever be one - // nested-name-specifier for the terminal type - MRDOCS_ASSERT(! NNS || ! T->getQualifier()); - NNS = T->getQualifier(); - qt = T->getNamedType().withFastQualifiers(quals); - continue; - } - // qualified dependent name with template keyword - case Type::DependentTemplateSpecialization: - { - auto* T = cast(type); - auto I = makeTypeInfo( - T->getIdentifier(), quals, T->template_arguments()); - // there should only ever be one - // nested-name-specifier for the terminal type - MRDOCS_ASSERT(! NNS || ! T->getQualifier()); - NNS = T->getQualifier(); - *inner = std::move(I); - break; - } - // dependent typename-specifier - case Type::DependentName: - { - auto* T = cast(type); - auto I = makeTypeInfo( - T->getIdentifier(), quals); - // there should only ever be one - // nested-name-specifier for the terminal type - MRDOCS_ASSERT(! NNS || ! T->getQualifier()); - NNS = T->getQualifier(); - *inner = std::move(I); - break; - } - // specialization of a class/alias template or - // template template parameter - case Type::TemplateSpecialization: - { - auto* T = cast(type); - auto name = T->getTemplateName(); - MRDOCS_ASSERT(! name.isNull()); - NamedDecl* ND = name.getAsTemplateDecl(); - // if this is a specialization of a alias template, - // the canonical type will be the named type. in such cases, - // we will use the template name. otherwise, we use the - // canonical type whenever possible. - if(! T->isTypeAlias()) - { - auto* CT = qt.getCanonicalType().getTypePtrOrNull(); - if(auto* ICT = dyn_cast_or_null(CT)) - ND = ICT->getDecl(); - else if(auto* RT = dyn_cast_or_null(CT)) - ND = RT->getDecl(); - } - *inner = makeTypeInfo( - ND, quals, T->template_arguments()); - break; - } - case Type::Record: - { - auto* T = cast(type); - RecordDecl* RD = T->getDecl(); - // if this is an instantiation of a class template, - // create a SpecializationTypeInfo & extract the template arguments - if(auto* CTSD = dyn_cast(RD)) - *inner = makeTypeInfo( - CTSD, quals, CTSD->getTemplateArgs().asArray()); - else - *inner = makeTypeInfo(RD, quals); - break; - } - // enum types, as well as injected class names - // within a class template (or specializations thereof) - case Type::InjectedClassName: - case Type::Enum: - { - *inner = makeTypeInfo( - type->getAsTagDecl(), quals); - break; - } - // typedef/alias type - case Type::Typedef: - { - auto* T = cast(type); - *inner = makeTypeInfo( - T->getDecl(), quals); - break; - } - case Type::TemplateTypeParm: - { - auto* T = cast(type); - auto I = std::make_unique(); - I->CVQualifiers = convertToQualifierKind(quals); - if(auto* D = T->getDecl()) - { - // special case for implicit template parameters - // resulting from abbreviated function templates - if(D->isImplicit()) - I->Name = "auto"; - else if(auto* II = D->getIdentifier()) - I->Name = II->getName(); - } - *inner = std::move(I); - break; - } - // this only seems to appear when a template parameter pack - // from an enclosing template appears in a pack expansion which contains - // a template parameter pack from an inner template. this does not seem - // to appear when both packs are template arguments; e.g. - // A will use this, but A...> will not - case Type::SubstTemplateTypeParmPack: - { - auto* T = cast(type); - *inner = makeTypeInfo( - T->getIdentifier(), quals); - break; - } - // builtin/unhandled type - default: - { - auto I = std::make_unique(); - I->CVQualifiers = convertToQualifierKind(quals); - I->Name = getTypeAsString( - qt.withoutLocalFastQualifiers()); - *inner = std::move(I); - break; - } - } - // the terminal type must be BuiltinTypeInfo, - // TagTypeInfo, or SpecializationTypeInfo - MRDOCS_ASSERT( - (*inner)->isBuiltin() || - (*inner)->isDecltype() || - (*inner)->isTag() || - (*inner)->isSpecialization()); - - // set whether the root node is a pack - if(result) - result->IsPackExpansion = is_pack_expansion; - - // if there is no nested-name-specifier for - // the terminal type, then we are done - if(! NNS) - return result; - - // KRYSTIAN FIXME: nested-name-specifier on builtin type? - visit(**inner, [&](T& t) - { - if constexpr(requires { t.ParentType; }) - { - // build the TypeInfo for the nested-name-specifier - // using the same mode used for this TypeInfo - buildParentTypeInfo( - t.ParentType, - NNS, - extract_mode); - } - }); - - return result; + if(TemplateTypeParmDecl* TTPD = TTPT->getDecl(); + TTPD && TTPD->isImplicit()) + return "auto"; } - + return QualType(T, 0).getAsString( + context_.getPrintingPolicy()); } /** Get the user-written `Decl` for a `Decl` @@ -1263,6 +789,31 @@ class ASTVisitor getInstantiatedFrom(D)); } + template + requires std::derived_from || + std::same_as> + TypedefNameDecl* getInstantiatedFrom(DeclTy* D) + { + return dyn_cast_if_present( + getInstantiatedFrom(D)); + } + + std::unique_ptr + buildTypeInfo( + QualType qt, + ExtractMode extract_mode = ExtractMode::IndirectDependency); + + std::unique_ptr + buildNameInfo( + const NestedNameSpecifier* NNS, + ExtractMode extract_mode = ExtractMode::IndirectDependency); + + std::unique_ptr + buildNameInfo( + const NamedDecl* ND, + ExtractMode extract_mode = ExtractMode::IndirectDependency); + + template Integer getValue(const llvm::APInt& V) @@ -2876,6 +2427,17 @@ class InstantiatedFromVisitor return D->getTemplatedDecl(); } + TypedefNameDecl* VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl* D) + { + if(auto* MT = D->getInstantiatedFromMemberTemplate()) + { + // KRYSTIAN NOTE: we don't really need to check this + if(! D->isMemberSpecialization()) + D = MT; + } + return VisitTypedefNameDecl(D->getTemplatedDecl()); + } + FunctionDecl* VisitFunctionDecl(FunctionDecl* D) { const FunctionDecl* DD = nullptr; @@ -3001,6 +2563,26 @@ class InstantiatedFromVisitor } return D; } + + TypedefNameDecl* VisitTypedefNameDecl(TypedefNameDecl* D) + { + DeclContext* Context = D->getNonTransparentDeclContext(); + if(Context->isFileContext()) + return D; + DeclContext* ContextPattern = + cast(Visit(cast(Context))); + if(Context == ContextPattern) + return D; + auto lookup = ContextPattern->lookup(D->getDeclName()); + for(NamedDecl* ND : lookup) + { + if(auto* TND = dyn_cast(ND)) + return TND; + if(auto* TATD = dyn_cast(ND)) + return TATD->getTemplatedDecl(); + } + return D; + } }; template @@ -3014,6 +2596,718 @@ getInstantiatedFrom(DeclTy* D) const_cast(static_cast(D)))); } +//------------------------------------------------ + +template +class TerminalTypeVisitor + : public TypeVisitor, bool> +{ + friend class TerminalTypeVisitor::TypeVisitor; + + ASTVisitor& Visitor_; + + unsigned Quals_ = 0; + bool IsPack_ = false; + const NestedNameSpecifier* NNS_ = nullptr; + + Derived& getDerived() + { + return static_cast(*this); + } + + bool VisitParenType( + const ParenType* T) + { + return Visit(T->getInnerType()); + } + + bool VisitMacroQualified( + const MacroQualifiedType* T) + { + return Visit(T->getUnderlyingType()); + } + + bool VisitAttributedType( + const AttributedType* T) + { + return Visit(T->getModifiedType()); + } + + bool VisitAdjustedType( + const AdjustedType* T) + { + return Visit(T->getOriginalType()); + } + + bool VisitUsingType( + const UsingType* T) + { + return Visit(T->getUnderlyingType()); + } + + bool VisitSubstTemplateTypeParmType( + const SubstTemplateTypeParmType* T) + { + return Visit(T->getReplacementType()); + } + + // ---------------------------------------------------------------- + + bool VisitElaboratedType( + const ElaboratedType* T) + { + NNS_ = T->getQualifier(); + return Visit(T->getNamedType()); + } + + bool VisitPackExpansionType( + const PackExpansionType* T) + { + IsPack_ = true; + return Visit(T->getPattern()); + } + + // ---------------------------------------------------------------- + + bool VisitPointerType( + const PointerType* T) + { + getDerived().buildPointer(T, std::exchange(Quals_, 0)); + return Visit(T->getPointeeType()); + } + + bool VisitLValueReferenceType( + const LValueReferenceType* T) + { + getDerived().buildLValueReference(T); + Quals_ = 0; + return Visit(T->getPointeeType()); + } + + bool VisitRValueReferenceType( + const RValueReferenceType* T) + { + getDerived().buildRValueReference(T); + Quals_ = 0; + return Visit(T->getPointeeType()); + } + + bool VisitMemberPointerType( + const MemberPointerType* T) + { + getDerived().buildMemberPointer(T, std::exchange(Quals_, 0)); + return Visit(T->getPointeeType()); + } + + bool VisitFunctionType( + const FunctionType* T) + { + getDerived().buildFunction(T); + return Visit(T->getReturnType()); + } + + bool VisitArrayType( + const ArrayType* T) + { + getDerived().buildArray(T); + return Visit(T->getElementType()); + } + + // ---------------------------------------------------------------- + + bool VisitDecltypeType( + const DecltypeType* T) + { + getDerived().buildDecltype(T, Quals_, IsPack_); + return true; + } + + bool VisitAutoType( + const AutoType* T) + { + if(QualType DT = T->getDeducedType(); ! DT.isNull()) + return Visit(DT); + getDerived().buildTerminal(NNS_, T, Quals_, IsPack_); + return true; + } + + bool VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType* T) + { + if(QualType DT = T->getDeducedType(); ! DT.isNull()) + return Visit(DT); + TemplateName TN = T->getTemplateName(); + MRDOCS_ASSERT(! TN.isNull()); + NamedDecl* ND = TN.getAsTemplateDecl(); + getDerived().buildTerminal(NNS_, ND, + std::nullopt, Quals_, IsPack_); + return true; + } + + bool VisitDependentNameType( + const DependentNameType* T) + { + if(auto* NNS = T->getQualifier()) + NNS_ = NNS; + getDerived().buildTerminal(NNS_, T->getIdentifier(), + std::nullopt, Quals_, IsPack_); + return true; + } + + bool VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType* T) + { + if(auto* NNS = T->getQualifier()) + NNS_ = NNS; + getDerived().buildTerminal(NNS_, T->getIdentifier(), + T->template_arguments(), Quals_, IsPack_); + return true; + } + + bool VisitTemplateSpecializationType( + const TemplateSpecializationType* T) + { + TemplateName TN = T->getTemplateName(); + MRDOCS_ASSERT(! TN.isNull()); + NamedDecl* ND = TN.getAsTemplateDecl(); + if(! T->isTypeAlias()) + { + auto* CT = T->getCanonicalTypeInternal().getTypePtrOrNull(); + if(auto* ICT = dyn_cast_or_null(CT)) + ND = ICT->getDecl(); + else if(auto* RT = dyn_cast_or_null(CT)) + ND = RT->getDecl(); + } + getDerived().buildTerminal(NNS_, ND, + T->template_arguments(), Quals_, IsPack_); + return true; + } + + bool VisitRecordType( + const RecordType* T) + { + RecordDecl* RD = T->getDecl(); + // if this is an instantiation of a class template, + // create a SpecializationTypeInfo & extract the template arguments + std::optional> TArgs = std::nullopt; + if(auto* CTSD = dyn_cast(RD)) + TArgs = CTSD->getTemplateArgs().asArray(); + getDerived().buildTerminal(NNS_, RD, + TArgs, Quals_, IsPack_); + return true; + } + + bool VisitInjectedClassNameType( + const InjectedClassNameType* T) + { + getDerived().buildTerminal(NNS_, T->getDecl(), + std::nullopt, Quals_, IsPack_); + return true; + } + + bool VisitEnumType( + const EnumType* T) + { + getDerived().buildTerminal(NNS_, T->getDecl(), + std::nullopt, Quals_, IsPack_); + return true; + } + + bool VisitTypedefType( + const TypedefType* T) + { + getDerived().buildTerminal(NNS_, T->getDecl(), + std::nullopt, Quals_, IsPack_); + return true; + } + + bool VisitTemplateTypeParmType( + const TemplateTypeParmType* T) + { + const IdentifierInfo* II = nullptr; + if(TemplateTypeParmDecl* D = T->getDecl()) + { + if(D->isImplicit()) + { + // special case for implicit template parameters + // resulting from abbreviated function templates + getDerived().buildTerminal( + NNS_, T, Quals_, IsPack_); + return true; + } + II = D->getIdentifier(); + } + getDerived().buildTerminal(NNS_, II, + std::nullopt, Quals_, IsPack_); + return true; + } + + bool VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType* T) + { + getDerived().buildTerminal(NNS_, T->getIdentifier(), + std::nullopt, Quals_, IsPack_); + return true; + } + + bool VisitType(const Type* T) + { + getDerived().buildTerminal( + NNS_, T, Quals_, IsPack_); + return true; + } + +public: + TerminalTypeVisitor( + ASTVisitor& Visitor) + : Visitor_(Visitor) + { + } + + ASTVisitor& getASTVisitor() + { + return Visitor_; + } + + using TerminalTypeVisitor::TypeVisitor::Visit; + + bool Visit(QualType QT) + { + Quals_ |= QT.getLocalFastQualifiers(); + return Visit(QT.getTypePtrOrNull()); + } + + void + buildPointer + (const PointerType* T, + unsigned quals) + { + } + + void + buildLValueReference( + const LValueReferenceType* T) + { + } + + void + buildRValueReference( + const RValueReferenceType* T) + { + } + + void + buildMemberPointer( + const MemberPointerType* T, unsigned quals) + { + } + + void + buildArray( + const ArrayType* T) + { + } + + void + buildFunction( + const FunctionType* T) + { + } + + void + buildDecltype( + const DecltypeType* T, + unsigned quals, + bool pack) + { + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const Type* T, + unsigned quals, + bool pack) + { + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const IdentifierInfo* II, + std::optional> TArgs, + unsigned quals, + bool pack) + { + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const NamedDecl* D, + std::optional> TArgs, + unsigned quals, + bool pack) + { + } +}; + +class TypeInfoBuilder + : public TerminalTypeVisitor +{ + std::unique_ptr Result; + std::unique_ptr* Inner = &Result; + +public: + TypeInfoBuilder(ASTVisitor& Visitor) + : TerminalTypeVisitor(Visitor) + { + } + + std::unique_ptr result() + { + return std::move(Result); + } + + void buildPointer(const PointerType* T, unsigned quals) + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + *std::exchange(Inner, &I->PointeeType) = std::move(I); + } + + void buildLValueReference(const LValueReferenceType* T) + { + auto I = std::make_unique(); + *std::exchange(Inner, &I->PointeeType) = std::move(I); + } + + void buildRValueReference(const RValueReferenceType* T) + { + auto I = std::make_unique(); + *std::exchange(Inner, &I->PointeeType) = std::move(I); + } + + void buildMemberPointer(const MemberPointerType* T, unsigned quals) + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + // do not set NNS because the parent type is *not* + // a nested-name-specifier which qualifies the pointee type + I->ParentType = getASTVisitor().buildTypeInfo( + QualType(T->getClass(), 0)); + *std::exchange(Inner, &I->PointeeType) = std::move(I); + } + + void buildArray(const ArrayType* T) + { + auto I = std::make_unique(); + if(auto* CAT = dyn_cast(T)) + getASTVisitor().buildExprInfo( + I->Bounds, CAT->getSizeExpr(), CAT->getSize()); + else if(auto* DAT = dyn_cast(T)) + getASTVisitor().buildExprInfo( + I->Bounds, DAT->getSizeExpr()); + *std::exchange(Inner, &I->ElementType) = std::move(I); + } + + void buildFunction(const FunctionType* T) + { + auto* FPT = cast(T); + auto I = std::make_unique(); + for(QualType PT : FPT->getParamTypes()) + I->ParamTypes.emplace_back( + getASTVisitor().buildTypeInfo(PT)); + I->RefQualifier = convertToReferenceKind( + FPT->getRefQualifier()); + I->CVQualifiers = convertToQualifierKind( + FPT->getMethodQuals().getFastQualifiers()); + getASTVisitor().buildNoexceptInfo(I->ExceptionSpec, FPT); + *std::exchange(Inner, &I->ReturnType) = std::move(I); + } + + void + buildDecltype( + const DecltypeType* T, + unsigned quals, + bool pack) + { + auto I = std::make_unique(); + getASTVisitor().buildExprInfo( + I->Operand, T->getUnderlyingExpr()); + I->CVQualifiers = convertToQualifierKind(quals); + *Inner = std::move(I); + Result->IsPackExpansion = pack; + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const Type* T, + unsigned quals, + bool pack) + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + I->Name = getASTVisitor().getTypeAsString(T); + I->Name_ = getASTVisitor().buildNameInfo(NNS); + *Inner = std::move(I); + Result->IsPackExpansion = pack; + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const IdentifierInfo* II, + std::optional> TArgs, + unsigned quals, + bool pack) + { + ASTVisitor& V = getASTVisitor(); + if(TArgs) + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + if(II) + I->Name = II->getName(); + I->Name_ = V.buildNameInfo(NNS); + V.buildTemplateArgs(I->TemplateArgs, *TArgs); + *Inner = std::move(I); + } + else + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + if(II) + I->Name = II->getName(); + I->Name_ = V.buildNameInfo(NNS); + *Inner = std::move(I); + } + Result->IsPackExpansion = pack; + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const NamedDecl* D, + std::optional> TArgs, + unsigned quals, + bool pack) + { + ASTVisitor& V = getASTVisitor(); + const IdentifierInfo* II = D->getIdentifier(); + if(TArgs) + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + if(II) + I->Name = II->getName(); + V.getDependencyID(V.getInstantiatedFrom(D), I->id); + if(NNS) + I->Name_ = V.buildNameInfo(NNS); + else + I->Name_ = V.buildNameInfo(D); + V.buildTemplateArgs(I->TemplateArgs, *TArgs); + *Inner = std::move(I); + } + else + { + auto I = std::make_unique(); + I->CVQualifiers = convertToQualifierKind(quals); + if(II) + I->Name = II->getName(); + V.getDependencyID(V.getInstantiatedFrom(D), I->id); + if(NNS) + I->Name_ = V.buildNameInfo(NNS); + else + I->Name_ = V.buildNameInfo(D); + *Inner = std::move(I); + } + Result->IsPackExpansion = pack; + } +}; + +std::unique_ptr +ASTVisitor:: +buildTypeInfo( + QualType qt, + ExtractMode extract_mode) +{ + // extract_mode is only used during the extraction + // the terminal type & its parents; the extraction of + // function parameters, template arguments, and the parent class + // of member pointers is done in ExtractMode::IndirectDependency + ExtractionScope scope = enterMode(extract_mode); + // build the TypeInfo representation for the type + TypeInfoBuilder Builder(*this); + Builder.Visit(qt); + return Builder.result(); +} + +class NameInfoBuilder + : public TerminalTypeVisitor +{ + std::unique_ptr Result; + +public: + NameInfoBuilder(ASTVisitor& Visitor) + : TerminalTypeVisitor(Visitor) + { + } + + std::unique_ptr result() + { + return std::move(Result); + } + + void + buildDecltype( + const DecltypeType* T, + unsigned quals, + bool pack) + { + // KRYSTIAN TODO: support decltype in names + // (e.g. within nested-name-specifiers). + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const Type* T, + unsigned quals, + bool pack) + { + auto I = std::make_unique(); + I->Name = getASTVisitor().getTypeAsString(T); + Result = std::move(I); + if(NNS) + Result->Prefix = getASTVisitor().buildNameInfo(NNS); + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const IdentifierInfo* II, + std::optional> TArgs, + unsigned quals, + bool pack) + { + ASTVisitor& V = getASTVisitor(); + if(TArgs) + { + auto I = std::make_unique(); + if(II) + I->Name = II->getName(); + V.buildTemplateArgs(I->TemplateArgs, *TArgs); + Result = std::move(I); + } + else + { + auto I = std::make_unique(); + if(II) + I->Name = II->getName(); + Result = std::move(I); + } + if(NNS) + Result->Prefix = V.buildNameInfo(NNS); + } + + void + buildTerminal( + const NestedNameSpecifier* NNS, + const NamedDecl* D, + std::optional> TArgs, + unsigned quals, + bool pack) + { + ASTVisitor& V = getASTVisitor(); + const IdentifierInfo* II = D->getIdentifier(); + if(TArgs) + { + auto I = std::make_unique(); + if(II) + I->Name = II->getName(); + V.getDependencyID(V.getInstantiatedFrom(D), I->id); + V.buildTemplateArgs(I->TemplateArgs, *TArgs); + Result = std::move(I); + } + else + { + auto I = std::make_unique(); + if(II) + I->Name = II->getName(); + V.getDependencyID(V.getInstantiatedFrom(D), I->id); + Result = std::move(I); + } + if(NNS) + Result->Prefix = V.buildNameInfo(NNS); + else + Result->Prefix = V.buildNameInfo(D); + } +}; + +std::unique_ptr +ASTVisitor:: +buildNameInfo( + const NestedNameSpecifier* NNS, + ExtractMode extract_mode) +{ + ExtractionScope scope = enterMode(extract_mode); + + std::unique_ptr I = nullptr; + if(! NNS) + return I; + if(const Type* T = NNS->getAsType()) + { + NameInfoBuilder Builder(*this); + Builder.Visit(T); + I = Builder.result(); + } + else if(const IdentifierInfo* II = NNS->getAsIdentifier()) + { + I = std::make_unique(); + I->Name = II->getName(); + I->Prefix = buildNameInfo(NNS->getPrefix(), extract_mode); + } + else if(const NamespaceDecl* ND = NNS->getAsNamespace()) + { + I = std::make_unique(); + I->Name = ND->getIdentifier()->getName(); + getDependencyID(ND, I->id); + I->Prefix = buildNameInfo(ND, extract_mode); + } + else if(const NamespaceAliasDecl* ND = NNS->getAsNamespaceAlias()) + { + I = std::make_unique(); + I->Name = ND->getIdentifier()->getName(); + getDependencyID(ND->getNamespace(), I->id); + I->Prefix = buildNameInfo(ND->getNamespace(), extract_mode); + } + return I; +} + +std::unique_ptr +ASTVisitor:: +buildNameInfo( + const NamedDecl* ND, + ExtractMode extract_mode) +{ + if(! ND) + return nullptr; + const NamedDecl* PD = dyn_cast_if_present< + NamedDecl>(getParentDecl(ND)); + if(! PD || PD->getKind() == Decl::TranslationUnit) + return nullptr; + auto I = std::make_unique(); + if(const IdentifierInfo* II = PD->getIdentifier()) + I->Name = II->getName(); + getDependencyID(getInstantiatedFrom(PD), I->id); + I->Prefix = buildNameInfo(PD, extract_mode); + return I; +} + +//------------------------------------------------ + #if 0 class ASTInstantiationCallbacks : public TemplateInstantiationCallback @@ -3072,6 +3366,7 @@ class ASTInstantiationCallbacks }; #endif + //------------------------------------------------ // // ASTVisitorConsumer diff --git a/src/lib/AST/AnyBlock.hpp b/src/lib/AST/AnyBlock.hpp index 99ec2dd0a..2aab0b721 100644 --- a/src/lib/AST/AnyBlock.hpp +++ b/src/lib/AST/AnyBlock.hpp @@ -621,6 +621,8 @@ class SourceInfoBlock //------------------------------------------------ + + class LookupBlock : public BitcodeReader::AnyBlock { @@ -1138,6 +1140,74 @@ class TemplateParamBlock //------------------------------------------------ +class NameInfoBlock + : public BitcodeReader::AnyBlock +{ +protected: + BitcodeReader& br_; + std::unique_ptr& I; + +public: + NameInfoBlock( + std::unique_ptr& I, + BitcodeReader& br) noexcept + : br_(br) + , I(I) + { + } + + Error + parseRecord( + Record const& R, + unsigned ID, + llvm::StringRef Blob) override + { + switch(ID) + { + case NAME_INFO_KIND: + NameKind kind{}; + if(auto err = decodeRecord(R, kind, Blob)) + return err; + if(kind == NameKind::Specialization) + I = std::make_unique(); + else + I = std::make_unique(); + return Error::success(); + case NAME_INFO_ID: + return decodeRecord(R, I->id, Blob); + case NAME_INFO_NAME: + return decodeRecord(R, I->Name, Blob); + default: + return AnyBlock::parseRecord(R, ID, Blob); + } + } + + Error + readSubBlock( + unsigned ID) override + { + switch(ID) + { + case BI_NAME_INFO_ID: + { + NameInfoBlock B(I->Prefix, br_); + return br_.readBlock(B, ID); + } + case BI_TEMPLATE_ARG_BLOCK_ID: + { + SpecializationNameInfo* S = + static_cast(I.get()); + TemplateArgBlock B(S->TemplateArgs.emplace_back(), br_); + return br_.readBlock(B, ID); + } + default: + return AnyBlock::readSubBlock(ID); + } + } +}; + +//------------------------------------------------ + class TemplateBlock : public BitcodeReader::AnyBlock { @@ -1265,6 +1335,19 @@ readSubBlock(unsigned ID) } return Error("wrong TypeInfo kind"); } + case BI_NAME_INFO_ID: + { + std::unique_ptr* NI = nullptr; + visit(*I_, [&](T& t) + { + if constexpr(requires { t.Name_; }) + NI = &t.Name_; + }); + if(! NI) + return Error("wrong TypeInfo kind"); + NameInfoBlock B(*NI, br_); + return br_.readBlock(B, ID); + } default: return AnyBlock::readSubBlock(ID); } diff --git a/src/lib/AST/BitcodeIDs.hpp b/src/lib/AST/BitcodeIDs.hpp index 60579d0c4..330215cf3 100644 --- a/src/lib/AST/BitcodeIDs.hpp +++ b/src/lib/AST/BitcodeIDs.hpp @@ -54,6 +54,7 @@ enum BlockID BI_SOURCE_INFO_ID, BI_SCOPE_INFO_ID, + BI_NAME_INFO_ID, BI_LOOKUP_INFO_ID, BI_BASE_BLOCK_ID, BI_ENUM_BLOCK_ID, @@ -100,6 +101,10 @@ enum RecordID LOOKUP_NAME, LOOKUP_MEMBERS, + NAME_INFO_KIND, + NAME_INFO_ID, + NAME_INFO_NAME, + NAMESPACE_BITS, TYPEINFO_KIND, TYPEINFO_IS_PACK, diff --git a/src/lib/AST/BitcodeWriter.cpp b/src/lib/AST/BitcodeWriter.cpp index 3ddc2be64..85ad3d5d9 100644 --- a/src/lib/AST/BitcodeWriter.cpp +++ b/src/lib/AST/BitcodeWriter.cpp @@ -256,6 +256,7 @@ BlockIdNameMap = []() {BI_FRIEND_BLOCK_ID, "FriendBlock"}, {BI_ENUMERATOR_BLOCK_ID, "EnumeratorBlock"}, {BI_VARIABLE_BLOCK_ID, "VarBlock"}, + {BI_NAME_INFO_ID, "NameInfoBlock"}, }; MRDOCS_ASSERT(Inits.size() == BlockIdCount); for (const auto& Init : Inits) @@ -305,6 +306,9 @@ RecordIDNameMap = []() {JAVADOC_NODE_SYMBOLREF, {"JavadocNodeSymbol", &SymbolIDAbbrev}}, {JAVADOC_PARAM_DIRECTION, {"JavadocParamDirection", &Integer32Abbrev}}, {NAMESPACE_BITS, {"NamespaceBits", &Integer32ArrayAbbrev}}, + {NAME_INFO_KIND, {"NameKind", &Integer32Abbrev}}, + {NAME_INFO_ID, {"NameID", &SymbolIDAbbrev}}, + {NAME_INFO_NAME, {"NameName", &StringAbbrev}}, {RECORD_KEY_KIND, {"KeyKind", &Integer32Abbrev}}, {RECORD_IS_TYPE_DEF, {"IsTypeDef", &BoolAbbrev}}, {RECORD_BITS, {"Bits", &Integer32ArrayAbbrev}}, @@ -436,8 +440,9 @@ RecordsByBlock{ {BI_VARIABLE_BLOCK_ID, {VARIABLE_BITS}}, // GuideInfo {BI_GUIDE_BLOCK_ID, {GUIDE_EXPLICIT}}, -}; - + {BI_NAME_INFO_ID, + {NAME_INFO_KIND, NAME_INFO_ID, NAME_INFO_NAME}}, + }; //------------------------------------------------ BitcodeWriter:: @@ -1029,6 +1034,12 @@ emitBlock( emitRecord(t.RefQualifier, TYPEINFO_REFQUAL); emitRecord(t.ExceptionSpec, TYPEINFO_NOEXCEPT); } + + if constexpr(requires { t.Name_; }) + { + if(t.Name_) + emitBlock(*t.Name_); + } }); } @@ -1124,6 +1135,24 @@ emitBlock( emitBlock(tparam); } +void +BitcodeWriter:: +emitBlock(NameInfo const& I) +{ + StreamSubBlockGuard Block(Stream, BI_NAME_INFO_ID); + emitRecord(I.Kind, NAME_INFO_KIND); + emitRecord(I.id, NAME_INFO_ID); + emitRecord(I.Name, NAME_INFO_NAME); + if(I.Prefix) + emitBlock(*I.Prefix); + if(I.Kind == NameKind::Specialization) + { + for(const auto& targ : static_cast< + const SpecializationNameInfo&>(I).TemplateArgs) + emitBlock(targ); + } +} + void BitcodeWriter:: emitBlock( diff --git a/src/lib/AST/BitcodeWriter.hpp b/src/lib/AST/BitcodeWriter.hpp index 836847639..62010a046 100644 --- a/src/lib/AST/BitcodeWriter.hpp +++ b/src/lib/AST/BitcodeWriter.hpp @@ -130,6 +130,7 @@ class BitcodeWriter void emitBlock(FieldInfo const& I); void emitBlock(FriendInfo const& I); void emitBlock(EnumeratorInfo const& I); + void emitBlock(NameInfo const& I); void emitBlock(std::unique_ptr const& TI); void emitBlock(std::unique_ptr const& TI, BlockID ID); diff --git a/src/lib/Metadata/DomMetadata.cpp b/src/lib/Metadata/DomMetadata.cpp index 5957abf91..798db115b 100644 --- a/src/lib/Metadata/DomMetadata.cpp +++ b/src/lib/Metadata/DomMetadata.cpp @@ -421,6 +421,31 @@ domCreate( //------------------------------------------------ +static +dom::Value +domCreate( + std::unique_ptr const& I, + DomCorpus const& domCorpus) +{ + if(! I) + return nullptr; + dom::Object::storage_type entries = { + { "kind", toString(I->Kind) } + }; + visit(*I, [&](const T& t) + { + entries.emplace_back("name", t.Name); + entries.emplace_back("symbol", domCorpus.get(t.id)); + + if constexpr(requires { t.TemplateArgs; }) + entries.emplace_back("args", + dom::newArray(t.TemplateArgs, domCorpus)); + + entries.emplace_back("prefix", domCreate(t.Prefix, domCorpus)); + }); + return dom::Object(std::move(entries)); +} + static dom::Value domCreate( @@ -438,6 +463,10 @@ domCreate( if constexpr(requires { t.Name; }) entries.emplace_back("name", t.Name); + if constexpr(requires { t.Name_; }) + entries.emplace_back("prefix", + domCreate(t.Name_, domCorpus)); + if constexpr(requires { t.id; }) entries.emplace_back("symbol", domCorpus.get(t.id)); diff --git a/src/lib/Metadata/Finalize.cpp b/src/lib/Metadata/Finalize.cpp index 8cae5d295..405df8f84 100644 --- a/src/lib/Metadata/Finalize.cpp +++ b/src/lib/Metadata/Finalize.cpp @@ -144,11 +144,27 @@ class Finalizer if constexpr(requires { T.id; }) finalize(T.id); + if constexpr(requires { T.Name_; }) + finalize(T.Name_); + if constexpr(Ty::isSpecialization()) finalize(T.TemplateArgs); }); } + void finalize(NameInfo& name) + { + visit(name, [this](Ty& T) + { + finalize(T.Prefix); + + if constexpr(requires { T.TemplateArgs; }) + finalize(T.TemplateArgs); + + finalize(T.id); + }); + } + void finalize(doc::Node& node) { visit(node, [&](NodeTy& N) diff --git a/src/lib/Metadata/Interface.cpp b/src/lib/Metadata/Interface.cpp index b42b7cc8d..7ccdf5aec 100644 --- a/src/lib/Metadata/Interface.cpp +++ b/src/lib/Metadata/Interface.cpp @@ -186,7 +186,8 @@ class TrancheBuilder continue; const Info* Base = lookThroughTypedefs( getTypeAsTag(B.Type)); - if(! Base || ! Base->isRecord()) + if(! Base || Base->id == I.id || + ! Base->isRecord()) continue; addFrom(*static_cast< const RecordInfo*>(Base), actualAccess); diff --git a/src/lib/Metadata/Name.cpp b/src/lib/Metadata/Name.cpp new file mode 100644 index 000000000..d848a2bfa --- /dev/null +++ b/src/lib/Metadata/Name.cpp @@ -0,0 +1,30 @@ +// +// 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 +// + +#include + +namespace clang { +namespace mrdocs { + +dom::String toString(NameKind kind) noexcept +{ + switch(kind) + { + case NameKind::Identifier: + return "identifier"; + case NameKind::Specialization: + return "specialization"; + default: + MRDOCS_UNREACHABLE(); + } +} + +} // mrdocs +} // clang