diff --git a/include/mrdocs/Metadata/Template.hpp b/include/mrdocs/Metadata/Template.hpp index ec802884d5..4126ba558a 100644 --- a/include/mrdocs/Metadata/Template.hpp +++ b/include/mrdocs/Metadata/Template.hpp @@ -175,7 +175,7 @@ enum class TParamKind : int Type = 1, // for bitstream // template non-type parameter, e.g. "int N" or "auto N" NonType, - // template template parameter, e.g. "template typename T" + // Template-template parameter, e.g. "template typename T" Template }; @@ -235,7 +235,7 @@ tag_invoke( template -struct IsTParam : TParam +struct TParamCommonBase : TParam { static constexpr TParamKind kind_id = K; @@ -245,7 +245,7 @@ struct IsTParam : TParam protected: constexpr - IsTParam() noexcept + TParamCommonBase() noexcept : TParam(K) { } @@ -271,7 +271,7 @@ tag_invoke( } struct TypeTParam - : IsTParam + : TParamCommonBase { /** Keyword (class/typename) the parameter uses */ TParamKeyKind KeyKind = TParamKeyKind::Class; @@ -281,14 +281,14 @@ struct TypeTParam }; struct NonTypeTParam - : IsTParam + : TParamCommonBase { /** Type of the non-type template parameter */ std::unique_ptr Type; }; struct TemplateTParam - : IsTParam + : TParamCommonBase { /** Template parameters for the template template parameter */ std::vector> Params; diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 8aecf5e4ac..5eb54512b8 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -950,6 +950,8 @@ populate( FunctionInfo& I, DeclTy* D) { + MRDOCS_SYMBOL_TRACE(D, context_); + // D is the templated declaration if FTD is non-null if (D->isFunctionTemplateSpecialization()) { @@ -987,11 +989,12 @@ populate( } } - // KRYSTIAN TODO: move other extraction that requires - // a valid function type here - if (auto FT = getDeclaratorType(D); ! FT.isNull()) + // Get the function type and extract information that comes from the type + if (auto FT = getDeclaratorType(D); !FT.isNull()) { + MRDOCS_SYMBOL_TRACE(FT, context_); const auto* FPT = FT->template getAs(); + MRDOCS_SYMBOL_TRACE(FPT, context_); populate(I.Noexcept, FPT); I.HasTrailingReturn |= FPT->hasTrailingReturn(); } @@ -999,79 +1002,78 @@ populate( // // FunctionDecl // - I.OverloadedOperator = toOperatorKind( - D->getOverloadedOperator()); - I.IsVariadic |= D->isVariadic(); - I.IsDefaulted |= D->isDefaulted(); - I.IsExplicitlyDefaulted |= D->isExplicitlyDefaulted(); - I.IsDeleted |= D->isDeleted(); - I.IsDeletedAsWritten |= D->isDeletedAsWritten(); - I.IsNoReturn |= D->isNoReturn(); - // subsumes D->hasAttr() - // subsumes D->hasAttr() - // subsumes D->hasAttr() - // subsumes D->getType()->getAs()->getNoReturnAttr() - I.HasOverrideAttr |= D->template hasAttr(); - - if (ConstexprSpecKind const CSK = D->getConstexprKind(); + FunctionDecl const* FD = D; + I.OverloadedOperator = toOperatorKind(FD->getOverloadedOperator()); + I.IsVariadic |= FD->isVariadic(); + I.IsDefaulted |= FD->isDefaulted(); + I.IsExplicitlyDefaulted |= FD->isExplicitlyDefaulted(); + I.IsDeleted |= FD->isDeleted(); + I.IsDeletedAsWritten |= FD->isDeletedAsWritten(); + I.IsNoReturn |= FD->isNoReturn(); + I.HasOverrideAttr |= FD->template hasAttr(); + + if (ConstexprSpecKind const CSK = FD->getConstexprKind(); CSK != ConstexprSpecKind::Unspecified) { I.Constexpr = toConstexprKind(CSK); } - if (StorageClass const SC = D->getStorageClass()) + if (StorageClass const SC = FD->getStorageClass()) { I.StorageClass = toStorageClassKind(SC); } - I.IsNodiscard |= D->template hasAttr(); - I.IsExplicitObjectMemberFunction |= D->hasCXXExplicitFunctionObjectParameter(); + I.IsNodiscard |= FD->template hasAttr(); + I.IsExplicitObjectMemberFunction |= FD->hasCXXExplicitFunctionObjectParameter(); + // // CXXMethodDecl // if constexpr(std::derived_from) { - I.IsVirtual |= D->isVirtual(); - I.IsVirtualAsWritten |= D->isVirtualAsWritten(); - I.IsPure |= D->isPureVirtual(); - I.IsConst |= D->isConst(); - I.IsVolatile |= D->isVolatile(); - I.RefQualifier = toReferenceKind(D->getRefQualifier()); - I.IsFinal |= D->template hasAttr(); - //D->isCopyAssignmentOperator() - //D->isMoveAssignmentOperator() - //D->isOverloadedOperator(); - //D->isStaticOverloadedOperator(); - } + CXXMethodDecl const* MD = D; + I.IsVirtual |= MD->isVirtual(); + I.IsVirtualAsWritten |= MD->isVirtualAsWritten(); + I.IsPure |= MD->isPureVirtual(); + I.IsConst |= MD->isConst(); + I.IsVolatile |= MD->isVolatile(); + I.RefQualifier = toReferenceKind(MD->getRefQualifier()); + I.IsFinal |= MD->template hasAttr(); + //MD->isCopyAssignmentOperator() + //MD->isMoveAssignmentOperator() + //MD->isOverloadedOperator(); + //MD->isStaticOverloadedOperator(); - // - // CXXDestructorDecl - // - // if constexpr(std::derived_from) - // { - // } + // + // CXXDestructorDecl + // + // if constexpr(std::derived_from) + // { + // } - // - // CXXConstructorDecl - // - if constexpr(std::derived_from) - { - populate(I.Explicit, D->getExplicitSpecifier()); - } + // + // CXXConstructorDecl + // + if constexpr(std::derived_from) + { + populate(I.Explicit, D->getExplicitSpecifier()); + } - // - // CXXConversionDecl - // - if constexpr(std::derived_from) - { - populate(I.Explicit, D->getExplicitSpecifier()); + // + // CXXConversionDecl + // + if constexpr(std::derived_from) + { + populate(I.Explicit, D->getExplicitSpecifier()); + } } - ArrayRef const params = D->parameters(); + ArrayRef const params = FD->parameters(); I.Params.resize(params.size()); for (std::size_t i = 0; i < params.size(); ++i) { ParmVarDecl const* P = params[i]; + MRDOCS_SYMBOL_TRACE(P, context_); Param& param = I.Params[i]; if (param.Name.empty()) @@ -1099,16 +1101,16 @@ populate( } } - I.Class = toFunctionClass(D->getDeclKind()); + I.Class = toFunctionClass(FD->getDeclKind()); // extract the return type in direct dependency mode // if it contains a placeholder type which is // deduceded as a local class type - QualType const RT = D->getReturnType(); + QualType const RT = FD->getReturnType(); MRDOCS_SYMBOL_TRACE(RT, context_); I.ReturnType = toTypeInfo(RT); - if (auto* TRC = D->getTrailingRequiresClause()) + if (auto* TRC = FD->getTrailingRequiresClause()) { populate(I.Requires, TRC); } @@ -1120,8 +1122,9 @@ void ASTVisitor:: populate(FunctionInfo& I, FunctionTemplateDecl* D) { - populate(I.Template, D->getTemplatedDecl(), D); - populate(I, D->getTemplatedDecl()); + FunctionDecl* TD = D->getTemplatedDecl(); + populate(I.Template, TD, D); + populate(I, TD); } void @@ -1375,7 +1378,8 @@ ASTVisitor:: populate(TemplateInfo& Template, DeclTy*, TemplateDeclTy* TD) { MRDOCS_ASSERT(TD); - populate(Template, TD->getTemplateParameters()); + TemplateParameterList const* TPL = TD->getTemplateParameters(); + populate(Template, TPL); } template CXXRecordDeclTy> @@ -1592,18 +1596,25 @@ populate( { I = std::make_unique(); } - auto* R = dynamic_cast(I.get()); - if(R->Params.empty()) + TemplateTemplateParmDecl const* TTPD = cast(P); + MRDOCS_CHECK_OR(TTPD); + TemplateParameterList const* TPL = TTPD->getTemplateParameters(); + MRDOCS_CHECK_OR(TPL); + auto* Result = dynamic_cast(I.get()); + if (Result->Params.size() < TPL->size()) { - for (NamedDecl const* NP: *P->getTemplateParameters()) - { - populate(R->Params.emplace_back(), NP); - } + Result->Params.resize(TPL->size()); } - if (P->hasDefaultArgument() && !R->Default) + for (std::size_t i = 0; i < TPL->size(); ++i) { - R->Default = toTArg( - P->getDefaultArgument().getArgument()); + NamedDecl const* TP = TPL->getParam(i); + populate(Result->Params[i], TP); + } + if (TTPD->hasDefaultArgument() && !Result->Default) + { + TemplateArgumentLoc const& TAL = TTPD->getDefaultArgument(); + TemplateArgument const& TA = TAL.getArgument(); + Result->Default = toTArg(TA); } return; } @@ -1634,9 +1645,10 @@ populate( { TI.Params.resize(TPL->size()); } - for (std::size_t I = 0; I < TPL->size(); ++I) + for (std::size_t i = 0; i < TPL->size(); ++i) { - populate(TI.Params[I], TPL->getParam(I)); + NamedDecl const* P = TPL->getParam(i); + populate(TI.Params[i], P); } if (auto* RC = TPL->getRequiresClause()) { diff --git a/src/lib/AST/ASTVisitor.hpp b/src/lib/AST/ASTVisitor.hpp index 18810c99cd..18da626a67 100644 --- a/src/lib/AST/ASTVisitor.hpp +++ b/src/lib/AST/ASTVisitor.hpp @@ -482,7 +482,8 @@ class ASTVisitor { Template.emplace(); } - populate(*Template, D, VTD); + TemplateInfo &TI = *Template; + populate(TI, D, VTD); } void diff --git a/src/lib/AST/ClangHelpers.hpp b/src/lib/AST/ClangHelpers.hpp index a180545940..835245c439 100644 --- a/src/lib/AST/ClangHelpers.hpp +++ b/src/lib/AST/ClangHelpers.hpp @@ -914,6 +914,20 @@ namespace detail { { printTraceName(&D, C, symbol_name); } + + template + void + printTraceName(std::optional const& D, ASTContext const& C, SmallString<256>& symbol_name) + { + if (D) + { + printTraceName(*D, C, symbol_name); + } + else + { + symbol_name += ""; + } + } } // namespace detail # define MRDOCS_SYMBOL_TRACE_MERGE_(a, b) a##b diff --git a/src/lib/AST/NameInfoBuilder.cpp b/src/lib/AST/NameInfoBuilder.cpp index bad6d37d8c..ea83f94511 100644 --- a/src/lib/AST/NameInfoBuilder.cpp +++ b/src/lib/AST/NameInfoBuilder.cpp @@ -89,11 +89,6 @@ buildTerminal( // Look for the Info type. If this is a template specialization, // we look for the Info of the specialized record. Decl const* ID = decayToPrimaryTemplate(D); - Info const* I = getASTVisitor().findOrTraverse(const_cast(ID)); - if (!I) - { - return; - } auto TI = std::make_unique(); @@ -103,7 +98,10 @@ buildTerminal( { Name->Name = II->getName(); } - Name->id = I->id; + if (Info const* I = getASTVisitor().findOrTraverse(const_cast(ID))) + { + Name->id = I->id; + } if(NNS) { Name->Prefix = getASTVisitor().toNameInfo(NNS); diff --git a/src/lib/AST/TerminalTypeVisitor.hpp b/src/lib/AST/TerminalTypeVisitor.hpp index d131ef05d6..9e52ea576c 100644 --- a/src/lib/AST/TerminalTypeVisitor.hpp +++ b/src/lib/AST/TerminalTypeVisitor.hpp @@ -615,22 +615,27 @@ class TerminalTypeVisitor // Template names can also refer to function templates, // C++0x template aliases, etc... TemplateName const TN = T->getTemplateName(); + MRDOCS_SYMBOL_TRACE(TN, Visitor_.context_); MRDOCS_ASSERT(! TN.isNull()); // The list of template parameters and a reference to // the templated scoped declaration NamedDecl* D = TN.getAsTemplateDecl(); + MRDOCS_SYMBOL_TRACE(TN, Visitor_.context_); if (!T->isTypeAlias()) { auto* CT = T->getCanonicalTypeInternal().getTypePtrOrNull(); + MRDOCS_SYMBOL_TRACE(CT, Visitor_.context_); if (auto* ICT = dyn_cast_or_null(CT)) { D = ICT->getDecl(); + MRDOCS_SYMBOL_TRACE(D, Visitor_.context_); } else if (auto* RT = dyn_cast_or_null(CT)) { D = RT->getDecl(); + MRDOCS_SYMBOL_TRACE(D, Visitor_.context_); } } diff --git a/src/lib/AST/TypeInfoBuilder.cpp b/src/lib/AST/TypeInfoBuilder.cpp index 6341c53428..459b88eef7 100644 --- a/src/lib/AST/TypeInfoBuilder.cpp +++ b/src/lib/AST/TypeInfoBuilder.cpp @@ -200,20 +200,15 @@ buildTerminal( unsigned quals, bool pack) { - MRDOCS_SYMBOL_TRACE(D, getASTVisitor().context_); MRDOCS_SYMBOL_TRACE(NNS, getASTVisitor().context_); + MRDOCS_SYMBOL_TRACE(D, getASTVisitor().context_); + MRDOCS_SYMBOL_TRACE(TArgs, getASTVisitor().context_); // Look for the Info type. If this is a template specialization, // we look for the Info of the specialized record. Decl const* ID = decayToPrimaryTemplate(D); MRDOCS_SYMBOL_TRACE(ID, getASTVisitor().context_); - Info const* I = getASTVisitor().findOrTraverse(const_cast(ID)); - if (!I) - { - return; - } - auto TI = std::make_unique(); TI->CVQualifiers = toQualifierKind(quals); @@ -223,7 +218,10 @@ buildTerminal( { Name->Name = II->getName(); } - Name->id = I->id; + if (Info const* I = getASTVisitor().findOrTraverse(const_cast(ID))) + { + Name->id = I->id; + } if(NNS) { Name->Prefix = getASTVisitor().toNameInfo(NNS); diff --git a/src/lib/Gen/adoc/AdocGenerator.cpp b/src/lib/Gen/adoc/AdocGenerator.cpp index 639d3ff724..58d837d39a 100644 --- a/src/lib/Gen/adoc/AdocGenerator.cpp +++ b/src/lib/Gen/adoc/AdocGenerator.cpp @@ -17,11 +17,6 @@ namespace clang::mrdocs { namespace adoc { -AdocGenerator:: -AdocGenerator() - : hbs::HandlebarsGenerator("Asciidoc", "adoc") -{} - std::string AdocGenerator:: toString(hbs::HandlebarsCorpus const& c, doc::Node const& I) const diff --git a/src/lib/Gen/adoc/AdocGenerator.hpp b/src/lib/Gen/adoc/AdocGenerator.hpp index dd65e91d4f..c4bd42818a 100644 --- a/src/lib/Gen/adoc/AdocGenerator.hpp +++ b/src/lib/Gen/adoc/AdocGenerator.hpp @@ -25,7 +25,24 @@ class AdocGenerator : public hbs::HandlebarsGenerator { public: - AdocGenerator(); + std::string_view + id() const noexcept override + { + return "adoc"; + } + + std::string_view + fileExtension() const noexcept override + { + return "adoc"; + } + + + std::string_view + displayName() const noexcept override + { + return "Asciidoc"; + } std::string toString( diff --git a/src/lib/Gen/hbs/HandlebarsGenerator.cpp b/src/lib/Gen/hbs/HandlebarsGenerator.cpp index 093f169fc6..22c841947e 100644 --- a/src/lib/Gen/hbs/HandlebarsGenerator.cpp +++ b/src/lib/Gen/hbs/HandlebarsGenerator.cpp @@ -28,10 +28,9 @@ #include #include -namespace clang { -namespace mrdocs { -namespace hbs { +namespace clang::mrdocs::hbs { +namespace { std::function createEscapeFn(HandlebarsGenerator const& gen) { @@ -65,8 +64,7 @@ createExecutors( HandlebarsCorpus createDomCorpus( HandlebarsGenerator const& gen, - Corpus const& corpus) -{ + Corpus const& corpus) { return { corpus, gen.fileExtension(), @@ -74,6 +72,7 @@ createDomCorpus( return gen.toString(c, n); }}; } +} // (anon) //------------------------------------------------ // @@ -89,21 +88,10 @@ build( { if (!corpus.config->multipage) { - auto e = Generator::build(outputPath, corpus); - if (e.has_value() && !corpus.config->tagfile.empty()) - { - // Generate tagfile if specified - auto const singlePagePath = getSinglePageFullPath(outputPath, fileExtension()); - MRDOCS_CHECK_OR(singlePagePath, Unexpected(singlePagePath.error())); - HandlebarsCorpus hbsCorpus = createDomCorpus(*this, corpus); - MRDOCS_TRY(auto tagFileWriter, TagfileWriter::create( - hbsCorpus, - corpus.config->tagfile, - files::getFileName(*singlePagePath))); - tagFileWriter.build(); - } - - return e; + MRDOCS_TRY(Generator::build(outputPath, corpus)); + MRDOCS_CHECK_OR(!corpus.config->tagfile.empty(), {}); + MRDOCS_TRY(buildTagfile(corpus.config->tagfile, corpus)); + return {}; } // Create corpus and executors @@ -117,21 +105,74 @@ build( // Wait for all executors to finish and check errors auto errors = ex.wait(); MRDOCS_CHECK_OR(errors.empty(), Unexpected(errors)); - report::info("Generated {} pages", visitor.count()); - if (! corpus.config->tagfile.empty()) + MRDOCS_CHECK_OR(!corpus.config->tagfile.empty(), {}); + MRDOCS_TRY(buildTagfile(corpus.config->tagfile, corpus)); + return {}; +} + +Expected +HandlebarsGenerator:: +buildTagfile( + std::ostream& os, + Corpus const& corpus) const +{ + HandlebarsCorpus domCorpus = createDomCorpus(*this, corpus); + RawOstream raw_os(os); + if (corpus.config->multipage) { MRDOCS_TRY(auto tagFileWriter, TagfileWriter::create( - domCorpus, - corpus.config->tagfile, - outputPath)); + domCorpus, + raw_os)); + tagFileWriter.build(); + } + else + { + // Get the name of the single page output file + auto const singlePagePath = getSinglePageFullPath(corpus.config->output, fileExtension()); + MRDOCS_CHECK_OR(singlePagePath, Unexpected(singlePagePath.error())); + auto const singlePathFilename = files::getFileName(*singlePagePath); + MRDOCS_TRY(auto tagFileWriter, TagfileWriter::create( + domCorpus, + raw_os, + singlePathFilename)); tagFileWriter.build(); } - return {}; } +Expected +HandlebarsGenerator:: +buildTagfile( + std::string_view const fileName, + Corpus const& corpus) const +{ + std::string const dir = files::getParentDir(fileName); + MRDOCS_TRY(files::createDirectory(dir)); + std::ofstream os; + try + { + os.open(std::string(fileName), + std::ios_base::binary | + std::ios_base::out | + std::ios_base::trunc // | std::ios_base::noreplace + ); + } + catch(std::exception const& ex) + { + return Unexpected(formatError("std::ofstream threw \"{}\"", ex.what())); + } + try + { + return buildTagfile(os, corpus); + } + catch(std::exception const& ex) + { + return Unexpected(formatError("buildOne threw \"{}\"", ex.what())); + } +} + Expected HandlebarsGenerator:: buildOne( @@ -178,6 +219,4 @@ escape(OutputRef& out, std::string_view str) const out << str; } -} // hbs -} // mrdocs -} // clang +} // clang::mrdocs::hbs \ No newline at end of file diff --git a/src/lib/Gen/hbs/HandlebarsGenerator.hpp b/src/lib/Gen/hbs/HandlebarsGenerator.hpp index 79afd4a669..175c73bba0 100644 --- a/src/lib/Gen/hbs/HandlebarsGenerator.hpp +++ b/src/lib/Gen/hbs/HandlebarsGenerator.hpp @@ -28,35 +28,7 @@ namespace hbs { class HandlebarsGenerator : public Generator { - std::string displayName_; - std::string fileExtension_; - public: - HandlebarsGenerator( - std::string_view displayName, - std::string_view fileExtension) - : displayName_(displayName) - , fileExtension_(fileExtension) - {} - - std::string_view - id() const noexcept override - { - return fileExtension_; - } - - std::string_view - displayName() const noexcept override - { - return displayName_; - } - - std::string_view - fileExtension() const noexcept override - { - return fileExtension_; - } - Expected build( std::string_view outputPath, @@ -67,6 +39,20 @@ class HandlebarsGenerator std::ostream& os, Corpus const& corpus) const override; + /** Build a tagfile for the corpus. + */ + Expected + buildTagfile( + std::ostream& os, + Corpus const& corpus) const; + + /** Build a tagfile for the corpus and store the result in a file. + */ + Expected + buildTagfile( + std::string_view fileName, + Corpus const& corpus) const; + /** Convert a Javadoc node to a string. */ virtual @@ -76,7 +62,7 @@ class HandlebarsGenerator return {}; } - /** Output a escaped string to the output stream. + /** Output an escaped string to the output stream. */ virtual void diff --git a/src/lib/Gen/html/HTMLGenerator.cpp b/src/lib/Gen/html/HTMLGenerator.cpp index cae66d87b6..5341ebadc9 100644 --- a/src/lib/Gen/html/HTMLGenerator.cpp +++ b/src/lib/Gen/html/HTMLGenerator.cpp @@ -17,11 +17,6 @@ namespace clang { namespace mrdocs { namespace html { -HTMLGenerator:: -HTMLGenerator() - : hbs::HandlebarsGenerator("HTML", "html") -{} - std::string HTMLGenerator:: toString(hbs::HandlebarsCorpus const& c, doc::Node const& I) const diff --git a/src/lib/Gen/html/HTMLGenerator.hpp b/src/lib/Gen/html/HTMLGenerator.hpp index d142b6f36d..0492b6992a 100644 --- a/src/lib/Gen/html/HTMLGenerator.hpp +++ b/src/lib/Gen/html/HTMLGenerator.hpp @@ -25,7 +25,23 @@ class HTMLGenerator : public hbs::HandlebarsGenerator { public: - HTMLGenerator(); + std::string_view + id() const noexcept override + { + return "html"; + } + + std::string_view + fileExtension() const noexcept override + { + return "html"; + } + + std::string_view + displayName() const noexcept override + { + return "HTML"; + } std::string toString( diff --git a/src/lib/Lib/TagfileWriter.cpp b/src/lib/Lib/TagfileWriter.cpp index 6cdde33180..bb89685cff 100644 --- a/src/lib/Lib/TagfileWriter.cpp +++ b/src/lib/Lib/TagfileWriter.cpp @@ -31,36 +31,23 @@ namespace mrdocs { TagfileWriter:: TagfileWriter( hbs::HandlebarsCorpus const& corpus, - os_ptr os, + llvm::raw_ostream& os, std::string_view const defaultFilename ) noexcept : corpus_(corpus) - , os_(std::move(os)) - , tags_(*os_) + , os_(os) + , tags_(os) , defaultFilename_(defaultFilename) -{ - tags_.nesting(false); -} +{} Expected TagfileWriter:: create( hbs::HandlebarsCorpus const& corpus, - std::string_view tagfile, - std::string_view defaultFilename) + llvm::raw_ostream& os, + std::string_view defaultFilename) { - std::error_code ec; - - auto os = std::make_unique( - tagfile.data(), - ec, - llvm::sys::fs::OF_None); - - if (ec) - { - return Unexpected(formatError("llvm::raw_fd_ostream(\"{}\") failed with error: {}", tagfile, ec.message())); - } - return TagfileWriter(corpus, std::move(os), defaultFilename); + return TagfileWriter(corpus, os, defaultFilename); } void @@ -76,15 +63,15 @@ void TagfileWriter:: initialize() { - (*os_) << "\n"; - (*os_) << "\n"; + os_ << "\n"; + os_ << "\n"; } void TagfileWriter:: finalize() { - (*os_) << "\n"; + os_ << "\n"; } diff --git a/src/lib/Lib/TagfileWriter.hpp b/src/lib/Lib/TagfileWriter.hpp index 0cb678a87f..b76f90451e 100644 --- a/src/lib/Lib/TagfileWriter.hpp +++ b/src/lib/Lib/TagfileWriter.hpp @@ -34,13 +34,13 @@ class TagfileWriter using os_ptr = std::unique_ptr; hbs::HandlebarsCorpus const& corpus_; - os_ptr os_; + llvm::raw_ostream& os_; xml::XMLTags tags_; std::string defaultFilename_; TagfileWriter( hbs::HandlebarsCorpus const& corpus, - os_ptr os, + llvm::raw_ostream& os, std::string_view defaultFilename) noexcept; public: @@ -49,8 +49,13 @@ class TagfileWriter This static function creates a TagfileWriter instance using the provided HandlebarsCorpus, tagfile, and default filename. + This overload provides a default filename for symbols. This is useful + when generating a tagfile for single page output, as there's a single + page to reference before the anchors. All symbols are references to + the same file with different anchors. + @param corpus The HandlebarsCorpus to use for the writer. - @param tagfile The name of the tagfile to write to. + @param os The output stream to write the tagfile to. @param defaultFilename The default filename to use for a symbol if none is provided. Typically, the relative path to a single page output file. This parameter is ignored in multipage mode. @@ -60,9 +65,31 @@ class TagfileWriter Expected create( hbs::HandlebarsCorpus const& corpus, - std::string_view tagfile, + llvm::raw_ostream& os, std::string_view defaultFilename); + /** Create a TagfileWriter instance without a reference to a default filename. + + This static function creates a TagfileWriter instance using the provided + HandlebarsCorpus and tagfile. + + This overload provides no default filename for symbols. This is useful + when generating a tagfile for multipage output, as there's no single + page to reference. All symbols are references to other files. + + @param corpus The HandlebarsCorpus to use for the writer. + @param os The output stream to write the tagfile to. + @return An Expected object containing the TagfileWriter instance or an error. + */ + static + Expected + create( + hbs::HandlebarsCorpus const& corpus, + llvm::raw_ostream& os) + { + return create(corpus, os, {}); + } + /** Build the tagfile. This function builds the tagfile by initializing the output, diff --git a/src/test/TestRunner.cpp b/src/test/TestRunner.cpp index 2e88acc5a6..42a9c42c07 100644 --- a/src/test/TestRunner.cpp +++ b/src/test/TestRunner.cpp @@ -16,6 +16,7 @@ #include "lib/Lib/CorpusImpl.hpp" #include "lib/Lib/MrDocsCompilationDatabase.hpp" #include "lib/Lib/SingleFileDB.hpp" +#include "lib/Gen/hbs/HandlebarsGenerator.hpp" #include "test_suite/diff.hpp" #include #include @@ -130,6 +131,16 @@ handleFile( } replaceCRLFWithLF(generatedDocs); + // Generate tagfile + if (auto hbsGen = dynamic_cast(gen_)) + { + std::stringstream ss; + if (auto exp = hbsGen->buildTagfile(ss, **corpus); !exp) + { + return report::error("{}: \"{}\"", exp.error(), filePath); + } + } + // Get expected documentation if it exists std::unique_ptr expectedDocsBuf; { diff --git a/test-files/golden-tests/metadata/class-private-alias.adoc b/test-files/golden-tests/metadata/class-private-alias.adoc new file mode 100644 index 0000000000..dd662d67af --- /dev/null +++ b/test-files/golden-tests/metadata/class-private-alias.adoc @@ -0,0 +1,59 @@ += Reference +:mrdocs: + +[#index] +== Global namespace + + +=== Types + +[cols=1] +|=== +| Name + +| <> +|=== + +[#S] +== S + + +=== Synopsis + + +Declared in `<class‐private‐alias.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +class S; +---- + +=== Member Functions + +[cols=1] +|=== +| Name + +| <> +|=== + + + +[#S-f] +== <>::f + + +=== Synopsis + + +Declared in `<class‐private‐alias.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +void +f(type); +---- + + + +[.small]#Created with https://www.mrdocs.com[MrDocs]# diff --git a/test-files/golden-tests/metadata/class-private-alias.cpp b/test-files/golden-tests/metadata/class-private-alias.cpp new file mode 100644 index 0000000000..f2e5d9eb08 --- /dev/null +++ b/test-files/golden-tests/metadata/class-private-alias.cpp @@ -0,0 +1,6 @@ +class S +{ + using type = int; +public: + void f(type) {} +}; diff --git a/test-files/golden-tests/metadata/class-private-alias.html b/test-files/golden-tests/metadata/class-private-alias.html new file mode 100644 index 0000000000..ca7a760f5e --- /dev/null +++ b/test-files/golden-tests/metadata/class-private-alias.html @@ -0,0 +1,76 @@ + + +Reference + + +
+

Reference

+
+
+

Global namespace

+
+

Types

+ + + + + + + + + + +
Name
S
+
+
+
+

S

+
+
+

Synopsis

+
+Declared in <class-private-alias.cpp>
+
+
+class S;
+
+
+
+

Member Functions

+ + + + + + + + + + +
Name
f
+ + +
+
+
+

S::f

+
+
+

Synopsis

+
+Declared in <class-private-alias.cpp>
+
+
+void
+f(type);
+
+
+
+
+ +
+
+

Created with MrDocs

+
+ + \ No newline at end of file diff --git a/test-files/golden-tests/metadata/class-private-alias.xml b/test-files/golden-tests/metadata/class-private-alias.xml new file mode 100644 index 0000000000..983b772afe --- /dev/null +++ b/test-files/golden-tests/metadata/class-private-alias.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/test-files/golden-tests/metadata/function-template-template.adoc b/test-files/golden-tests/metadata/function-template-template.adoc new file mode 100644 index 0000000000..5c2e4fb854 --- /dev/null +++ b/test-files/golden-tests/metadata/function-template-template.adoc @@ -0,0 +1,36 @@ += Reference +:mrdocs: + +[#index] +== Global namespace + + +=== Functions + +[cols=1] +|=== +| Name + +| <> +|=== + +[#f] +== f + + +=== Synopsis + + +Declared in `<function‐template‐template.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +template<template<class...> typename ListType> +constexpr +void +f(ListType<int> param); +---- + + + +[.small]#Created with https://www.mrdocs.com[MrDocs]# diff --git a/test-files/golden-tests/metadata/function-template-template.cpp b/test-files/golden-tests/metadata/function-template-template.cpp new file mode 100644 index 0000000000..8411ea759a --- /dev/null +++ b/test-files/golden-tests/metadata/function-template-template.cpp @@ -0,0 +1,4 @@ +template