diff --git a/include/mrdocs/Metadata/Concept.hpp b/include/mrdocs/Metadata/Concept.hpp index abf7778e7c..be13fd2e22 100644 --- a/include/mrdocs/Metadata/Concept.hpp +++ b/include/mrdocs/Metadata/Concept.hpp @@ -28,7 +28,7 @@ struct ConceptInfo { /** The concepts template parameters */ - std::unique_ptr Template; + std::optional Template; /** The concepts constraint-expression */ diff --git a/include/mrdocs/Metadata/Function.hpp b/include/mrdocs/Metadata/Function.hpp index d29145b6c6..326fa34123 100644 --- a/include/mrdocs/Metadata/Function.hpp +++ b/include/mrdocs/Metadata/Function.hpp @@ -126,13 +126,16 @@ struct FunctionInfo : InfoCommonBase , SourceInfo { - std::unique_ptr ReturnType; // Info about the return type of this function. - std::vector Params; // List of parameters. + /// Info about the return type of this function. + std::unique_ptr ReturnType; - // When present, this function is a template or specialization. - std::unique_ptr Template; + /// List of parameters. + std::vector Params; - // the class of function this is + /// When present, this function is a template or specialization. + std::optional Template; + + /// The class of function this is FunctionClass Class = FunctionClass::Normal; NoexceptInfo Noexcept; diff --git a/include/mrdocs/Metadata/Guide.hpp b/include/mrdocs/Metadata/Guide.hpp index 5af411923d..9c616d70ac 100644 --- a/include/mrdocs/Metadata/Guide.hpp +++ b/include/mrdocs/Metadata/Guide.hpp @@ -38,7 +38,7 @@ struct GuideInfo /** Template head, if any. */ - std::unique_ptr Template; + std::optional Template; /** The parameters of the deduction guide. */ diff --git a/include/mrdocs/Metadata/Record.hpp b/include/mrdocs/Metadata/Record.hpp index c1a9d4ddf2..362f261c7c 100644 --- a/include/mrdocs/Metadata/Record.hpp +++ b/include/mrdocs/Metadata/Record.hpp @@ -85,11 +85,11 @@ struct RecordInfo */ RecordKeyKind KeyKind = RecordKeyKind::Struct; - // When present, this record is a template or specialization. - std::unique_ptr Template; + /// When present, this record is a template or specialization. + std::optional Template; - // Indicates if the record was declared using a typedef. Things like anonymous - // structs in a typedef: + // Indicates if the record was declared using a typedef. + // Things like anonymous structs in a typedef: // typedef struct { ... } foo_t; // are converted into records with the typedef as the Name + this flag set. // KRYSTIAN FIXME: this does not account for alias-declarations diff --git a/include/mrdocs/Metadata/Template.hpp b/include/mrdocs/Metadata/Template.hpp index dddb902664..343771ffd8 100644 --- a/include/mrdocs/Metadata/Template.hpp +++ b/include/mrdocs/Metadata/Template.hpp @@ -369,9 +369,14 @@ struct TemplateInfo TemplateSpecKind specializationKind() const noexcept { if(Params.empty()) + { return TemplateSpecKind::Explicit; - return Args.empty() ? TemplateSpecKind::Primary : - TemplateSpecKind::Partial; + } + if (Args.empty()) + { + return TemplateSpecKind::Primary; + } + return TemplateSpecKind::Partial; } }; @@ -388,7 +393,7 @@ void tag_invoke( dom::ValueFromTag, dom::Value& v, - std::unique_ptr const& I, + std::optional const& I, DomCorpus const* domCorpus) { if (!I) diff --git a/include/mrdocs/Metadata/Typedef.hpp b/include/mrdocs/Metadata/Typedef.hpp index b825e3d898..03ca1c3844 100644 --- a/include/mrdocs/Metadata/Typedef.hpp +++ b/include/mrdocs/Metadata/Typedef.hpp @@ -35,7 +35,7 @@ struct TypedefInfo // typedef std::vector MyVector; bool IsUsing = false; - std::unique_ptr Template; + std::optional Template; //-------------------------------------------- diff --git a/include/mrdocs/Metadata/Variable.hpp b/include/mrdocs/Metadata/Variable.hpp index 8737cb74bb..b4069aa4d9 100644 --- a/include/mrdocs/Metadata/Variable.hpp +++ b/include/mrdocs/Metadata/Variable.hpp @@ -34,7 +34,7 @@ struct VariableInfo /** The type of the variable */ std::unique_ptr Type; - std::unique_ptr Template; + std::optional Template; ExprInfo Initializer; diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 00d2e14edb..28f7da0e91 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -43,12 +43,11 @@ namespace clang::mrdocs { -ASTVisitor::FileInfo +auto ASTVisitor::FileInfo::build( - std::span> search_dirs, + std::span const> search_dirs, std::string_view const file_path, - std::string_view const sourceRoot) -{ + std::string_view const sourceRoot) -> ASTVisitor::FileInfo { FileInfo file_info; file_info.full_path = std::string(file_path); file_info.short_path = file_info.full_path; @@ -142,13 +141,13 @@ ASTVisitor( MRDOCS_ASSERT(context_.getTraversalScope() == std::vector{context_.getTranslationUnitDecl()}); - auto make_posix_absolute = [&](std::string_view old_path) + auto make_posix_absolute = [&](std::string_view const old_path) { llvm::SmallString<128> new_path(old_path); if(! llvm::sys::path::is_absolute(new_path)) { // KRYSTIAN FIXME: use FileManager::makeAbsolutePath? - auto& cwd = source_.getFileManager(). + auto const& cwd = source_.getFileManager(). getFileSystemOpts().WorkingDir; // we can't normalize a relative path // without a base directory @@ -162,14 +161,12 @@ ASTVisitor( return std::string(new_path); }; - std::string sourceRoot = make_posix_absolute(config_->sourceRoot); - std::vector> search_dirs; - Preprocessor& PP = sema_.getPreprocessor(); HeaderSearch& HS = PP.getHeaderSearchInfo(); + std::vector> search_dirs; search_dirs.reserve(HS.search_dir_size()); // first, convert all the include search directories into POSIX style - for(const DirectoryLookup& DL : HS.search_dir_range()) + for (const DirectoryLookup& DL : HS.search_dir_range()) { OptionalDirectoryEntryRef DR = DL.getDirRef(); // only consider normal directories @@ -182,6 +179,7 @@ ASTVisitor( FileKind::System : FileKind::Other); } + std::string const sourceRoot = make_posix_absolute(config_->sourceRoot); auto cacheFileInfo = [&](const FileEntry* entry) { // "try" implies this may fail, so fallback to getName @@ -215,10 +213,10 @@ build() // dependencies will be tracked, but not extracted traverseAny(context_.getTranslationUnitDecl()); - // This is to ensure that the global namespace is always present + // Ensure the global namespace is always present upsert(SymbolID::global); - // if dependency extraction is disabled, we are done + // Dependency extraction is disabled: we are done if(config_->referencedDeclarations == ConfigImpl::SettingsImpl::ExtractPolicy::Never) { return; @@ -249,12 +247,21 @@ buildDependencies() } } -template +namespace { +template +concept isRedeclarableTemplate = + std::derived_from; + +template +concept isTemplateSpecialization = + std::derived_from || + std::derived_from; +} // (anon) + + void ASTVisitor:: -traverseAny( - Decl* D, - Args&&... args) +traverseAny(Decl* D) { MRDOCS_ASSERT(D); MRDOCS_CHECK_OR(!D->isInvalidDecl()); @@ -266,152 +273,149 @@ traverseAny( // and call the appropriate traverse function visit(D, [&](DeclTy* DD) { - if constexpr( - std::derived_from) + if constexpr (isRedeclarableTemplate) { - // Only ClassTemplateDecl, FunctionTemplateDecl, - // VarTemplateDecl, and TypeAliasDecl are derived - // from RedeclarableTemplateDecl. - // This doesn't include ConceptDecl. - // Recursively call traverseAny so traverse is called with - // a pointer to the most derived type of the templated Decl + // If the symbol is a template, we traverse the + // templated declaration instead of the template. + // The template is provided as the second argument + // so that the Info object can also be populated with + // this information. traverseAny(DD->getTemplatedDecl(), DD); } - else if constexpr( - std::derived_from || - std::derived_from) + else if constexpr (isTemplateSpecialization) { - // A class template specialization + // If the symbol is a template specialization, + // we traverse the specialized template and provide + // the specialized template as the second argument. traverse(DD, DD->getSpecializedTemplate()); } else { - // Call the appropriate traverse function - // for the most derived type of the Decl - traverse(DD, std::forward(args)...); + // In the general case, we call the appropriate + // traverse function for the most derived type + // of the Decl + traverse(DD); } }); } -template +template TemplateDeclTy> void ASTVisitor:: -traverse(Decl* D, Args&&...) +traverseAny(Decl* D, TemplateDeclTy* TD) { - if (auto* DC = dyn_cast(D)) - { - traverse(DC); - } -} + MRDOCS_ASSERT(D); + MRDOCS_ASSERT(TD); + MRDOCS_CHECK_OR(!D->isInvalidDecl()); + MRDOCS_CHECK_OR(!TD->isInvalidDecl()); -void -ASTVisitor:: -traverse(DeclContext* DC) -{ - for(auto* D : DC->decls()) - { - traverseAny(D); - } -} + // Restore the symbol filter state when leaving the scope + SymbolFilterScope scope(symbolFilter_); -template -requires - std::same_as || - std::same_as || - std::same_as || - std::same_as || - std::same_as || - std::same_as || - std::same_as -void -ASTVisitor:: -traverse(DeclTy* D) -{ - if (auto exp = upsert(D)) + // Convert to the most derived type of the Decl + // and call the appropriate traverse function + visit(D, [&](DeclTy* DD) { - populate(exp->I, exp->created, D); - if constexpr (std::derived_from) + if constexpr ( + isRedeclarableTemplate || + isTemplateSpecialization) { - traverse(dyn_cast(D)); + // If `D` is still a template or a template specialization, + // we traverse the secondary templated declaration instead. + traverseAny(DD); } - } + else + { + // Call the appropriate traverse function + // for the most derived type of the Decl. + // The primary template information provided to + // the corresponding traverse function. + traverse(DD, TD); + } + }); } -template CXXRecordDeclTy> +template < + bool PopulateFromTD, + std::derived_from DeclTy, + std::derived_from TemplateDeclTy> void ASTVisitor:: -traverse( - CXXRecordDeclTy* D, - ClassTemplateDecl* CTD) +defaultTraverseImpl(DeclTy* D, TemplateDeclTy* TD) { - // Upsert the corresponding Info object - auto exp = upsert(D); - if (!exp) + MRDOCS_ASSERT(D); + MRDOCS_ASSERT(!PopulateFromTD || TD); + + // If D is also a template declaration, we extract + // the template information from the declaration itself + if constexpr (!PopulateFromTD && std::derived_from) { + defaultTraverseImpl(D, D); return; } - auto [I, created] = *exp; - // CTD is the specialized template if D is a partial or - // explicit specialization, and the described template otherwise - if (CTD) + using InfoT = MrDocsType_t; + static constexpr bool HasMrDocsInfoType = !std::same_as; + if constexpr (!HasMrDocsInfoType) { - if (!I.Template) - { - I.Template = std::make_unique(); - } - - // If D is a partial/explicit specialization, extract the template arguments - if (auto* CTSD = dyn_cast(D)) - { - generateID(getInstantiatedFrom(CTD), I.Template->Primary); + // Traverse the members of the declaration even if + // the declaration does not have a corresponding Info type + traverseMembers(D); + } + else + { + // If the declaration has a corresponding Info type, + // we build the Info object and populate it with the + // necessary information. + auto exp = upsert(D); + MRDOCS_CHECK_OR(exp); - // Extract the template arguments of the specialization - populate(I.Template->Args, CTSD->getTemplateArgsAsWritten()); + auto& [I, isNew] = *exp; - // Extract the template parameters if this is a partial specialization - if(auto* CTPSD = dyn_cast(D)) + // Populate template information + if constexpr ( + PopulateFromTD && + requires { I.Template; }) + { + if (!I.Template) { - populate(*I.Template, CTPSD->getTemplateParameters()); + I.Template.emplace(); } + populate(*I.Template, D, TD); } - else - { - // Otherwise, extract the template parameter list from CTD - populate(*I.Template, CTD->getTemplateParameters()); - } - } - populate(I, created, D); - traverse(static_cast(D)); + // Populate the Info object with the necessary information + populate(I, isNew, D); + + // Traverse the members of the declaration + traverseMembers(D); + } } -template FunctionDeclTy> +template +requires + std::derived_from && + std::derived_from void ASTVisitor:: -traverse( - FunctionDeclTy* D, - FunctionTemplateDecl* FTD) +traverse(FunctionDeclTy* D) { auto exp = upsert(D); if (!exp) { return; } - auto [I, created] = *exp; + auto [I, isNew] = *exp; // D is the templated declaration if FTD is non-null - if (FTD || D->isFunctionTemplateSpecialization()) + if (D->isFunctionTemplateSpecialization()) { if (!I.Template) { - I.Template = std::make_unique(); + I.Template.emplace(); } - if(auto* FTSI = D->getTemplateSpecializationInfo()) + if (auto* FTSI = D->getTemplateSpecializationInfo()) { generateID(getInstantiatedFrom( FTSI->getTemplate()), I.Template->Primary); @@ -424,7 +428,7 @@ traverse( populate(I.Template->Args, Args->asArray()); } } - else if(auto* DFTSI = D->getDependentSpecializationInfo()) + else if (auto* DFTSI = D->getDependentSpecializationInfo()) { // Only extract the ID of the primary template if there is // a single candidate primary template. @@ -438,113 +442,9 @@ traverse( populate(I.Template->Args, Args); } } - else - { - populate(*I.Template, FTD->getTemplateParameters()); - } - } - - populate(I, created, D); -} - -template TypedefNameDeclTy> -void -ASTVisitor:: -traverse( - TypedefNameDeclTy* D, - TypeAliasTemplateDecl* ATD) -{ - auto exp = upsert(D); - if (!exp) - { - return; - } - auto [I, created] = *exp; - - if (isa(D)) - { - I.IsUsing = true; - } - - if (ATD) - { - if (!I.Template) - { - I.Template = std::make_unique(); - } - populate(*I.Template, ATD->getTemplateParameters()); - } - - populate(I, created, D); -} - -template VarDeclTy> -void -ASTVisitor:: -traverse( - VarDeclTy* D, - VarTemplateDecl* VTD) -{ - auto exp = upsert(D); - if (!exp) - { - return; - } - auto [I, created] = *exp; - - // VTD is the specialized template if D is a partial or - // explicit specialization, and the described template otherwise - if (VTD) - { - if (!I.Template) - { - I.Template = std::make_unique(); - } - - // If D is a partial/explicit specialization, extract the template arguments - if(auto* VTSD = dyn_cast(D)) - { - generateID(getInstantiatedFrom(VTD), I.Template->Primary); - // extract the template arguments of the specialization - populate(I.Template->Args, VTSD->getTemplateArgsAsWritten()); - // extract the template parameters if this is a partial specialization - if(auto* VTPSD = dyn_cast(D)) - populate(*I.Template, VTPSD->getTemplateParameters()); - } - else - { - // otherwise, extract the template parameter list from VTD - populate(*I.Template, VTD->getTemplateParameters()); - } } - populate(I, created, D); -} - -void -ASTVisitor:: -traverse( - CXXDeductionGuideDecl* D, - FunctionTemplateDecl const* FTD) -{ - auto exp = upsert(D); - if (!exp) - { - return; - } - auto [I, created] = *exp; - - // D is the templated declaration if FTD is non-null - if(FTD) - { - if(! I.Template) - { - I.Template = std::make_unique(); - } - populate(*I.Template, FTD->getTemplateParameters()); - } - - populate(I, created, D); + populate(I, isNew, D); } void @@ -558,12 +458,8 @@ traverse(UsingDirectiveDecl* D) } Decl* PD = getParentDecl(D); - bool const isNamespaceScope = cast(PD)->isFileContext(); - if (!isNamespaceScope) - { - return; - } + MRDOCS_CHECK_OR(isNamespaceScope); if (Info* PI = find(generateID(PD))) { @@ -577,27 +473,28 @@ traverse(UsingDirectiveDecl* D) void ASTVisitor:: -traverse(ConceptDecl* D) +traverse(IndirectFieldDecl* D) { - auto exp = upsert(D); - if (!exp) - { - return; - } - auto [I, created] = *exp; - if (!I.Template) - { - I.Template = std::make_unique(); - } - populate(*I.Template, D->getTemplateParameters()); - populate(I, created, D); + traverse(D->getAnonField()); } +template DeclTy> void ASTVisitor:: -traverse(IndirectFieldDecl* D) +traverseMembers(DeclTy* DC) { - traverse(D->getAnonField()); + // When a declaration context is a function, we should + // not traverse its members as function arguments are + // not main Info members. + if constexpr ( + !std::derived_from && + std::derived_from) + { + for (auto* D : DC->decls()) + { + traverseAny(D); + } + } } Expected> @@ -804,10 +701,11 @@ void ASTVisitor:: populate( NamespaceInfo& I, - bool const created, + bool const isNew, NamespaceDecl* D) { - MRDOCS_CHECK_OR(created); + // Only extract Namespace data once + MRDOCS_CHECK_OR(isNew); I.IsAnonymous = D->isAnonymousNamespace(); if (!I.IsAnonymous) { @@ -821,14 +719,14 @@ void ASTVisitor:: populate( RecordInfo& I, - bool const created, + bool const isNew, CXXRecordDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), D->isThisDeclarationADefinition(), documented); - if (!created) + if (!isNew) { return; } @@ -892,7 +790,7 @@ void ASTVisitor:: populate( FunctionInfo& I, - bool const created, + bool const isNew, DeclTy* D) { bool const documented = generateJavadoc(I.javadoc, D); @@ -981,7 +879,7 @@ populate( for (ParmVarDecl const* P : D->parameters()) { - Param& param = created ? + Param& param = isNew ? I.Params.emplace_back() : I.Params[P->getFunctionScopeIndex()]; @@ -1004,7 +902,7 @@ populate( } } - if (!created) + if (!isNew) { return; } @@ -1035,14 +933,14 @@ void ASTVisitor:: populate( EnumInfo& I, - bool const created, + bool const isNew, EnumDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), D->isThisDeclarationADefinition(), documented); - if (!created) + if (!isNew) { return; } @@ -1063,13 +961,13 @@ void ASTVisitor:: populate( EnumConstantInfo& I, - bool const created, + bool const isNew, EnumConstantDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), true, documented); - if (!created) + if (!isNew) { return; } @@ -1084,12 +982,13 @@ populate( populateNamespaces(I, D); } +template TypedefNameDeclTy> void ASTVisitor:: populate( TypedefInfo& I, - bool const created, - TypedefNameDecl* D) + bool const isNew, + TypedefNameDeclTy* D) { bool const documented = generateJavadoc(I.javadoc, D); @@ -1099,11 +998,12 @@ populate( // be redeclared multiple times (even in the same scope) populate(I, D->getBeginLoc(), true, documented); - if (!created) + if (!isNew) { return; } + I.IsUsing = isa(D); I.Name = extractName(D); // When a symbol has a dependency on a typedef, we also @@ -1121,7 +1021,7 @@ void ASTVisitor:: populate( VariableInfo& I, - bool const created, + bool const isNew, VarDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); @@ -1156,7 +1056,7 @@ populate( populate(I.Initializer, E); } - if (!created) + if (!isNew) { return; } @@ -1172,7 +1072,7 @@ void ASTVisitor:: populate( FieldInfo& I, - bool const created, + bool const isNew, FieldDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); @@ -1180,7 +1080,7 @@ populate( // cannot have multiple declarations populate(I, D->getBeginLoc(), true, documented); - if (!created) + if (!isNew) { return; } @@ -1215,10 +1115,10 @@ void ASTVisitor:: populate( SpecializationInfo& I, - bool const created, + bool const isNew, ClassTemplateSpecializationDecl* D) { - if (!created) + if (!isNew) { return; } @@ -1237,13 +1137,13 @@ void ASTVisitor:: populate( FriendInfo& I, - bool const created, + bool const isNew, FriendDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), true, documented); - if (!created) + if (!isNew) { return; } @@ -1283,14 +1183,14 @@ void ASTVisitor:: populate( GuideInfo& I, - bool const created, + bool const isNew, CXXDeductionGuideDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), true, documented); // deduction guides cannot be redeclared, so there is nothing to merge - if (!created) + if (!isNew) { return; } @@ -1317,13 +1217,13 @@ void ASTVisitor:: populate( NamespaceAliasInfo& I, - bool const created, + bool const isNew, NamespaceAliasDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), true, documented); - if (!created) + if (!isNew) { return; } @@ -1347,13 +1247,13 @@ void ASTVisitor:: populate( UsingInfo& I, - bool const created, + bool const isNew, UsingDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), true, documented); - if (!created) + if (!isNew) { return; } @@ -1368,7 +1268,6 @@ populate( UDS->getTargetDecl(), I.UsingSymbols.emplace_back()); } - populateNamespaces(I, D); } @@ -1376,12 +1275,12 @@ void ASTVisitor:: populate( ConceptInfo& I, - bool const created, + bool const isNew, ConceptDecl* D) { bool const documented = generateJavadoc(I.javadoc, D); populate(I, D->getBeginLoc(), true, documented); - if (!created) + if (!isNew) { return; } @@ -1434,6 +1333,78 @@ populate( } } +/* Default function to populate template parameters + */ +template < + std::derived_from DeclTy, + std::derived_from TemplateDeclTy> +void +ASTVisitor:: +populate(TemplateInfo& Template, DeclTy*, TemplateDeclTy* TD) +{ + MRDOCS_ASSERT(TD); + populate(Template, TD->getTemplateParameters()); +} + +template CXXRecordDeclTy> +void +ASTVisitor:: +populate( + TemplateInfo& Template, + CXXRecordDeclTy* D, + ClassTemplateDecl* CTD) +{ + MRDOCS_ASSERT(CTD); + + // If D is a partial/explicit specialization, extract the template arguments + if (auto* CTSD = dyn_cast(D)) + { + generateID(getInstantiatedFrom(CTD), Template.Primary); + + // Extract the template arguments of the specialization + populate(Template.Args, CTSD->getTemplateArgsAsWritten()); + + // Extract the template parameters if this is a partial specialization + if (auto* CTPSD = dyn_cast(D)) + { + populate(Template, CTPSD->getTemplateParameters()); + } + } + else + { + // Otherwise, extract the template parameter list from CTD + populate(Template, CTD->getTemplateParameters()); + } +} + +template VarDeclTy> +void +ASTVisitor:: +populate( + TemplateInfo& Template, + VarDeclTy* D, + VarTemplateDecl* VTD) +{ + MRDOCS_ASSERT(VTD); + + // If D is a partial/explicit specialization, extract the template arguments + if(auto* VTSD = dyn_cast(D)) + { + generateID(getInstantiatedFrom(VTD), Template.Primary); + // extract the template arguments of the specialization + populate(Template.Args, VTSD->getTemplateArgsAsWritten()); + // extract the template parameters if this is a partial specialization + if(auto* VTPSD = dyn_cast(D)) + populate(Template, VTPSD->getTemplateParameters()); + } + else + { + // otherwise, extract the template parameter list from VTD + populate(Template, VTD->getTemplateParameters()); + } +} + + void ASTVisitor:: populate( @@ -1611,56 +1582,22 @@ void ASTVisitor:: populate( TemplateInfo& TI, - const TemplateParameterList* TPL) + TemplateParameterList const* TPL) { - for(std::size_t I = 0; I < TPL->size(); ++I) + if (TPL->size() > TI.Params.size()) { - auto& PI = I < TI.Params.size() ? - TI.Params[I] : TI.Params.emplace_back(); - populate(PI, TPL->getParam(I)); + TI.Params.resize(TPL->size()); } - if (auto* RC = TPL->getRequiresClause()) + for (std::size_t I = 0; I < TPL->size(); ++I) { - populate(TI.Requires, RC); + populate(TI.Params[I], TPL->getParam(I)); } -} - -template -void -ASTVisitor:: -populate( - std::vector>& result, - Range&& args) -{ - for(const TemplateArgument& arg : args) + if (auto* RC = TPL->getRequiresClause()) { - // KRYSTIAN NOTE: is this correct? should we have a - // separate TArgKind for packs instead of "unlaminating" - // them as we are doing here? - if (arg.getKind() == TemplateArgument::Pack) - { - populate(result, arg.pack_elements()); - } else - { - result.emplace_back(toTArg(arg)); - } + populate(TI.Requires, RC); } } -template -void -ASTVisitor:: -populate const&>( - std::vector>& result, - llvm::ArrayRef const& args); - -template -void -ASTVisitor:: -populate&>( - std::vector>& result, - llvm::ArrayRef& args); - void ASTVisitor:: populate( @@ -1675,7 +1612,6 @@ populate( })); } - std::string ASTVisitor:: extractName(NamedDecl const* D) @@ -1760,16 +1696,16 @@ populateNamespaces( case Decl::TranslationUnit: { MRDOCS_ASSERT(ParentID == SymbolID::global); - auto [P, created] = upsert< + auto [P, isNew] = upsert< NamespaceInfo>(ParentID); addMember(P, I); break; } case Decl::Namespace: { - auto [P, created] = upsert< + auto [P, isNew] = upsert< NamespaceInfo>(ParentID); - populate(P, created, cast(PD)); + populate(P, isNew, cast(PD)); addMember(P, I); break; } @@ -1788,9 +1724,9 @@ populateNamespaces( MRDOCS_ASSERT(PD->getKind() != Decl::ClassTemplatePartialSpecialization); - auto [P, created] = upsert< + auto [P, isNew] = upsert< SpecializationInfo>(ParentID); - populate(P, created, S); + populate(P, isNew, S); addMember(P, I); break; } @@ -1801,17 +1737,17 @@ populateNamespaces( // that is not a CXXRecord case Decl::CXXRecord: { - auto [P, created] = upsert< + auto [P, isNew] = upsert< RecordInfo>(ParentID); - populate(P, created, cast(PD)); + populate(P, isNew, cast(PD)); addMember(P, I); break; } case Decl::Enum: { - auto [P, created] = upsert< + auto [P, isNew] = upsert< EnumInfo>(ParentID); - populate(P, created, cast(PD)); + populate(P, isNew, cast(PD)); addMember(P, I); break; } @@ -2703,6 +2639,9 @@ isInSpecialNamespace( const Decl* D, std::span const Patterns) { + // Check if a Decl is in a special namespace + // A Decl is in a special namespace if any of its + // parent namespaces match a special namespace pattern if (!D || Patterns.empty()) { return false; @@ -2733,6 +2672,9 @@ isInSpecialNamespace( const NestedNameSpecifier* NNS, std::span Patterns) { + // Check if a NestedNameSpecifier is in a special namespace + // It's in a special namespace if any of its prefixes are + // in a special namespace const NamedDecl* ND = nullptr; while(NNS) { @@ -2756,6 +2698,8 @@ checkSpecialNamespace( const NestedNameSpecifier* NNS, const Decl* D) const { + // Check if a NestedNameSpecifier or a Decl is in a special namespace + // If so, update the NameInfo's Name to reflect this if (isInSpecialNamespace(NNS, config_->seeBelowFilter) || isInSpecialNamespace(D, config_->seeBelowFilter)) { @@ -2782,6 +2726,8 @@ checkSpecialNamespace( const NestedNameSpecifier* NNS, const Decl* D) const { + // Check if a NestedNameSpecifier or a Decl is in a special namespace + // If so, update the TypeInfo's Name to reflect this if (std::unique_ptr Name; checkSpecialNamespace(Name, NNS, D)) { @@ -2847,7 +2793,7 @@ upsert(SymbolID const& id) // Creating symbol with invalid SymbolID MRDOCS_ASSERT(id != SymbolID::invalid); Info* info = find(id); - bool const created = !info; + bool const isNew = !info; if (!info) { info = info_.emplace(std::make_unique< @@ -2855,7 +2801,7 @@ upsert(SymbolID const& id) info->Implicit = currentMode() != ExtractMode::Normal; } MRDOCS_ASSERT(info->Kind == InfoTy::kind_id); - return {static_cast(*info), created}; + return {static_cast(*info), isNew}; } template DeclType> @@ -2868,14 +2814,14 @@ upsert(DeclType* D) shouldExtract(D, access), "Symbol should not be extracted"); - SymbolID id = generateID(D); + SymbolID const id = generateID(D); MRDOCS_CHECK_MSG(id, "Failed to extract symbol ID"); - auto [I, created] = upsert>(id); + auto [I, isNew] = upsert>(id); I.Access = convertToAccessKind(access); using R = upsertResult>; - return R{std::ref(I), created}; + return R{std::ref(I), isNew}; } void diff --git a/src/lib/AST/ASTVisitor.hpp b/src/lib/AST/ASTVisitor.hpp index 495a159e76..bce3575d7d 100644 --- a/src/lib/AST/ASTVisitor.hpp +++ b/src/lib/AST/ASTVisitor.hpp @@ -58,7 +58,7 @@ class ASTVisitor friend class TerminalTypeVisitor; // MrDocs configuration - const ConfigImpl& config_; + ConfigImpl const& config_; // MrDocs diagnostics Diagnostics diags_; @@ -195,7 +195,7 @@ class ASTVisitor template struct upsertResult { InfoTy& I; - bool created; + bool isNew; }; public: @@ -280,44 +280,45 @@ class ASTVisitor // AST Traversal // ================================================= - /* Traverse a declaration context + /* Traverse a declaration This function is called to traverse any declaration. The Decl element is converted to its derived type, and the appropriate `traverse` overload is called. - The build() function will call this function with - context_.getTranslationUnitDecl() to initiate + The `build()` function will call this function with + `context_.getTranslationUnitDecl()` to initiate the traversal of the entire AST, while `buildDependencies()` will call it for each dependency. - @param DC The declaration context to traverse. - @param args The arguments to forward to the `traverse` function. + @param D The declaration to traverse. */ - template void - traverseAny(Decl* D, Args&&... args); + traverseAny(Decl* D); - /* Traverse an unspecified declaration + /* Traverse a declaration and template declaration - Catch-all function to traverse any declaration. - The function will attempt to convert the declaration - to a DeclContext and call traverse it if successful. - */ - template - void - traverse(Decl* D, Args&&...); + This function is called to traverse any declaration + with the corresponding template declaration. - /* Traverse declaration contexts + The Decl element is converted to its derived type, + and the appropriate `traverse` overload is called + with the template declaration as the second argument. - This function is called to traverse the members of a declaration - that is also a context with other members. + Both the information about the type and the + template parameters are extracted into the + `Info` object. - The function will call traverseAny for each member of the - declaration context. - */ + The `traverseAny()` function will call this function + for each declaration with a corresponding template + declaration. + + @param D The declaration context to traverse. + @param TD The corresponding template declaration. + */ + template TemplateDeclTy> void - traverse(DeclContext* DC); + traverseAny(Decl* D, TemplateDeclTy* TD); /* The default implementation for the traverse function @@ -328,118 +329,87 @@ class ASTVisitor declaration, populates it with the necessary information, and optionally traverses the members of the declaration. - The Traverse template parameter is used to determine - whether the function should traverse the members of - the declaration context. - @param D The declaration to traverse */ template - requires - std::same_as || - std::same_as || - std::same_as || - std::same_as || - std::same_as || - std::same_as || - std::same_as - void - traverse(DeclTy* D); - - /* Traverse a C++ struct, union, or class - - This function is called by traverseAny to traverse a - C++ struct, union, or class. `D` can be a CXXRecordDecl - or a templated CXXRecordDecl. - - If `CTD` is not null, the function will populate - the template parameters of the Record object. - `CTD` might represent a partial specialization, - an explicit specialization, or the primary template. - */ - template CXXRecordDeclTy> + requires std::derived_from void - traverse(CXXRecordDeclTy*, ClassTemplateDecl* CTD = nullptr); - - /* Traverse a C++ function - - This function is called by traverseAny to traverse a - C++ function. `D` can be a FunctionDecl - or a templated FunctionDecl. + traverse(DeclTy* D) + { + defaultTraverseImpl(D); + } - If `CTD` is not null, the function will populate - the template parameters of the function. - `CTD` might represent a partial specialization, - an explicit specialization, or the primary template. - */ - template FunctionDeclTy> - void - traverse(FunctionDeclTy* D, FunctionTemplateDecl* CTD = nullptr); + /* The default implementation for the traverse function with a + template parameter - /* Traverse a typedef declaration + This function defines the usual behavior for the + traverse function for a concrete declaration type + when associated with a template declaration. - This function is called by traverseAny to traverse a - typedef declaration. `D` can be a TypedefNameDecl - or a templated TypedefNameDecl. + It creates a new corresponding Info object for the + declaration, populates it with the necessary information, + populates the Template information, and optionally + traverses the members of the declaration. - If `ATD` is not null, the function will populate - the template parameters of the Typedef object. - `ATD` might represent a partial specialization, - an explicit specialization, or the primary template. - */ - template TypedefNameDeclTy> + @param D The declaration to traverse + @param TD The template declaration associated with `D` + */ + template < + std::derived_from DeclTy, + std::derived_from TemplateDeclTy> void - traverse(TypedefNameDeclTy * D, TypeAliasTemplateDecl * ATD = nullptr); - - /* Traverse a variable declaration or definition + traverse(DeclTy* D, TemplateDeclTy* TD) + { + defaultTraverseImpl(D, TD); + } - This function is called by traverseAny to traverse a - variable declaration or definition. `D` can be a VarDecl - or a templated VarDecl. + /* Default implementation for the traverse function - If `VTD` is not null, the function will populate - the template parameters of the Variable object. - `VTD` might represent a partial specialization, - an explicit specialization, or the primary template. - */ - template VarDeclTy> + This function defines the common logic for + `traverse(DeclTy*)` and `traverse(DeclTy*, TemplateDeclTy*)`, + where the `PopulateFromTD` parameter determines whether + the template information should be populated from the + template declaration. + */ + template < + bool PopulateFromTD, + std::derived_from DeclTy, + std::derived_from TemplateDeclTy = TemplateDecl> void - traverse(VarDeclTy* D, VarTemplateDecl* VTD = nullptr); + defaultTraverseImpl(DeclTy* D, TemplateDeclTy* TD = nullptr); - /* Traverse a deduction guide + /* Traverse a C++ function or function specialization - This function is called by traverseAny to traverse a - C++ deduction guide. `D` can be a CXXDeductionGuideDecl - or a templated CXXDeductionGuideDecl. + This handles `FunctionDecl` and `CXXMethodDecl`. - If `FTD` is not null, the function will populate - the template parameters of the Guide object. - */ + Both these classes can return `true` for + `D->isFunctionTemplateSpecialization()`, + in which case the function will also populate the + template parameters of the function. + + */ + template + requires + std::derived_from && + std::derived_from void - traverse( - CXXDeductionGuideDecl* D, - FunctionTemplateDecl const* FTD = nullptr); + traverse(FunctionDeclTy* D); /* Traverse a using directive This function is called to traverse a using directive such as `using namespace std;`. - The parent declaration is extracted and included - in the dependencies. - */ - void - traverse(UsingDirectiveDecl*); - - /* Traverse a concept definition - - This function is called by traverseAny to traverse a - C++ concept definition. + If the parent declaration is a Namespace, we + update its `UsingDirectives` field. */ void - traverse(ConceptDecl*); + traverse(UsingDirectiveDecl* D); /* Traverse a member of an anonymous union. + + We get the anonymous union field and traverse it + as a regular `FieldDecl`. */ void traverse(IndirectFieldDecl*); @@ -448,6 +418,18 @@ class ASTVisitor // AST Traversal Helpers // ================================================= + /* Traverse the members of a declaration + + This function is called to traverse the members of + a Decl that is a DeclContext with other members. + + The function will call traverseAny for all members of the + declaration context. + */ + template DeclTy> + void + traverseMembers(DeclTy* DC); + /* Generates a Unified Symbol Resolution value for a declaration. USRs are strings that provide an unambiguous reference to a symbol. @@ -457,7 +439,7 @@ class ASTVisitor @returns true if USR generation succeeded. */ - Expected> + Expected> generateUSR(const Decl* D) const; /* Generate the symbol ID for a declaration. @@ -497,51 +479,82 @@ class ASTVisitor // Populate functions // ================================================= void - populate(NamespaceInfo& I, bool created, NamespaceDecl* D); + populate(NamespaceInfo& I, bool isNew, NamespaceDecl* D); void - populate(RecordInfo& I, bool created, CXXRecordDecl* D); + populate(RecordInfo& I, bool isNew, CXXRecordDecl* D); template DeclTy> void - populate(FunctionInfo& I, bool created, DeclTy* D); + populate(FunctionInfo& I, bool isNew, DeclTy* D); void - populate(EnumInfo& I, bool created, EnumDecl* D); + populate(EnumInfo& I, bool isNew, EnumDecl* D); void - populate(EnumConstantInfo& I, bool created, EnumConstantDecl* D); + populate(EnumConstantInfo& I, bool isNew, EnumConstantDecl* D); + template TypedefNameDeclTy> void - populate(TypedefInfo& I, bool created, TypedefNameDecl* D); + populate(TypedefInfo& I, bool isNew, TypedefNameDeclTy* D); void - populate(VariableInfo& I, bool created, VarDecl* D); + populate(VariableInfo& I, bool isNew, VarDecl* D); void - populate(FieldInfo& I, bool created, FieldDecl* D); + populate(FieldInfo& I, bool isNew, FieldDecl* D); void - populate(SpecializationInfo& I, bool created, ClassTemplateSpecializationDecl* D); + populate(SpecializationInfo& I, bool isNew, ClassTemplateSpecializationDecl* D); void - populate(FriendInfo& I, bool created, FriendDecl* D); + populate(FriendInfo& I, bool isNew, FriendDecl* D); void - populate(GuideInfo& I, bool created, CXXDeductionGuideDecl* D); + populate(GuideInfo& I, bool isNew, CXXDeductionGuideDecl* D); void - populate(NamespaceAliasInfo& I, bool created, NamespaceAliasDecl* D); + populate(NamespaceAliasInfo& I, bool isNew, NamespaceAliasDecl* D); void - populate(UsingInfo& I, bool created, UsingDecl* D); + populate(UsingInfo& I, bool isNew, UsingDecl* D); void - populate(ConceptInfo& I, bool created, ConceptDecl* D); + populate(ConceptInfo& I, bool isNew, ConceptDecl* D); void populate(SourceInfo& I, clang::SourceLocation loc, bool definition, bool documented); + /* Default function to populate the template information + + This overload ignores the declaration and populates + the template information with the template parameters + of the template declaration. + */ + template < + std::derived_from DeclTy, + std::derived_from TemplateDeclTy> + void + populate(TemplateInfo& Template, DeclTy* D, TemplateDeclTy* TD); + + /* Populate the template information for a class template + + The function will populate the template parameters + depending on whether the record is a specialization. + */ + template CXXRecordDeclTy> + void + populate(TemplateInfo& Template, CXXRecordDeclTy*, ClassTemplateDecl* CTD); + + /* Populate the template information for a variable template + + The function will populate the template parameters + depending on whether the variable is a specialization. + */ + template VarDeclTy> + void + populate(TemplateInfo& Template, VarDeclTy* D, VarTemplateDecl* VTD); + void populate(NoexceptInfo& I, const FunctionProtoType* FPT); @@ -565,11 +578,26 @@ class ASTVisitor void populate(TemplateInfo& TI, const TemplateParameterList* TPL); - template + template void populate( std::vector>& result, - Range&& args); + Range&& args) + { + for (TemplateArgument const& arg : args) + { + // KRYSTIAN NOTE: is this correct? should we have a + // separate TArgKind for packs instead of "unlaminating" + // them as we are doing here? + if (arg.getKind() == TemplateArgument::Pack) + { + populate(result, arg.pack_elements()); + } else + { + result.emplace_back(toTArg(arg)); + } + } + } void populate( diff --git a/src/lib/Gen/xml/XMLWriter.cpp b/src/lib/Gen/xml/XMLWriter.cpp index 5e2caddfcd..702749a8b4 100644 --- a/src/lib/Gen/xml/XMLWriter.cpp +++ b/src/lib/Gen/xml/XMLWriter.cpp @@ -637,7 +637,7 @@ writeLocation( void XMLWriter:: openTemplate( - const std::unique_ptr& I) + const std::optional& I) { if(! I) return; @@ -659,7 +659,7 @@ openTemplate( void XMLWriter:: closeTemplate( - const std::unique_ptr& I) + const std::optional& I) { if(! I) return; diff --git a/src/lib/Gen/xml/XMLWriter.hpp b/src/lib/Gen/xml/XMLWriter.hpp index db46df65d0..f113da6549 100644 --- a/src/lib/Gen/xml/XMLWriter.hpp +++ b/src/lib/Gen/xml/XMLWriter.hpp @@ -66,8 +66,8 @@ class XMLWriter void writeSourceInfo(SourceInfo const& I); void writeLocation(Location const& loc, bool def = false); void writeJavadoc(std::unique_ptr const& javadoc); - void openTemplate(const std::unique_ptr& I); - void closeTemplate(const std::unique_ptr& I); + void openTemplate(const std::optional& I); + void closeTemplate(const std::optional& I); // void writeType(std::unique_ptr const& type); diff --git a/src/lib/Metadata/Finalize.cpp b/src/lib/Metadata/Finalize.cpp index e183769396..c536726cc8 100644 --- a/src/lib/Metadata/Finalize.cpp +++ b/src/lib/Metadata/Finalize.cpp @@ -236,6 +236,14 @@ class Finalizer finalize(*ptr); } + template + void finalize(std::optional& ptr) requires + requires { this->finalize(*ptr); } + { + if(ptr) + finalize(*ptr); + } + template requires std::ranges::input_range void finalize(Range&& range)