Index: clang-tools-extra/clang-doc/BitcodeReader.cpp =================================================================== --- clang-tools-extra/clang-doc/BitcodeReader.cpp +++ clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -83,7 +83,7 @@ if (R[0] > INT_MAX) return llvm::make_error("Integer too large to parse.\n", llvm::inconvertibleErrorCode()); - Field.emplace((int)R[0], Blob); + Field.emplace((int)R[0], Blob, (bool)R[1]); return llvm::Error::success(); } @@ -129,7 +129,7 @@ if (R[0] > INT_MAX) return llvm::make_error("Integer too large to parse.\n", llvm::inconvertibleErrorCode()); - Field.emplace_back((int)R[0], Blob); + Field.emplace_back((int)R[0], Blob, (bool)R[1]); return llvm::Error::success(); } Index: clang-tools-extra/clang-doc/BitcodeWriter.cpp =================================================================== --- clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -77,10 +77,13 @@ {// 0. Fixed-size integer (line number) llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, BitCodeConstants::LineNumberSize), - // 1. Fixed-size integer (length of the following string (filename)) + // 1. Boolean (IsFileInRootDir) + llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, + BitCodeConstants::BoolSize), + // 2. Fixed-size integer (length of the following string (filename)) llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, BitCodeConstants::StringLengthSize), - // 2. The string blob + // 3. The string blob llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)}); } @@ -316,6 +319,7 @@ // FIXME: Assert that the line number is of the appropriate size. Record.push_back(Loc.LineNumber); assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize)); + Record.push_back(Loc.IsFileInRootDir); Record.push_back(Loc.Filename.size()); Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename); } Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp =================================================================== --- clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -294,12 +294,15 @@ return Out; } -static std::vector> genHTML(const EnumInfo &I); -static std::vector> genHTML(const FunctionInfo &I, - StringRef ParentInfoDir); +static std::vector> +genHTML(const EnumInfo &I, const ClangDocContext &CDCtx); +static std::vector> +genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx, + StringRef ParentInfoDir); static std::vector> -genEnumsBlock(const std::vector &Enums) { +genEnumsBlock(const std::vector &Enums, + const ClangDocContext &CDCtx) { if (Enums.empty()) return {}; @@ -308,7 +311,7 @@ Out.emplace_back(llvm::make_unique(HTMLTag::TAG_DIV)); auto &DivBody = Out.back(); for (const auto &E : Enums) { - std::vector> Nodes = genHTML(E); + std::vector> Nodes = genHTML(E, CDCtx); AppendVector(std::move(Nodes), DivBody->Children); } return Out; @@ -327,7 +330,7 @@ static std::vector> genFunctionsBlock(const std::vector &Functions, - StringRef ParentInfoDir) { + const ClangDocContext &CDCtx, StringRef ParentInfoDir) { if (Functions.empty()) return {}; @@ -336,7 +339,8 @@ Out.emplace_back(llvm::make_unique(HTMLTag::TAG_DIV)); auto &DivBody = Out.back(); for (const auto &F : Functions) { - std::vector> Nodes = genHTML(F, ParentInfoDir); + std::vector> Nodes = + genHTML(F, CDCtx, ParentInfoDir); AppendVector(std::move(Nodes), DivBody->Children); } return Out; @@ -381,10 +385,30 @@ return Out; } -static std::unique_ptr writeFileDefinition(const Location &L) { - return llvm::make_unique( - HTMLTag::TAG_P, - "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename); +static std::unique_ptr +writeFileDefinition(const Location &L, + llvm::Optional RepositoryUrl = None) { + if (!L.IsFileInRootDir || !RepositoryUrl) + return llvm::make_unique( + HTMLTag::TAG_P, "Defined at line " + std::to_string(L.LineNumber) + + " of file " + L.Filename); + SmallString<128> FileURL(RepositoryUrl.getValue()); + llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename); + auto Node = llvm::make_unique(HTMLTag::TAG_P); + Node->Children.emplace_back(llvm::make_unique("Defined at line ")); + auto LocNumberNode = + llvm::make_unique(HTMLTag::TAG_A, std::to_string(L.LineNumber)); + // The links to a specific line in the source code use the github / + // googlesource notation so it won't work for all hosting pages. + LocNumberNode->Attributes.try_emplace( + "href", (FileURL + "#" + std::to_string(L.LineNumber)).str()); + Node->Children.emplace_back(std::move(LocNumberNode)); + Node->Children.emplace_back(llvm::make_unique(" of file ")); + auto LocFileNode = llvm::make_unique( + HTMLTag::TAG_A, llvm::sys::path::filename(FileURL)); + LocFileNode->Attributes.try_emplace("href", FileURL); + Node->Children.emplace_back(std::move(LocFileNode)); + return Node; } static std::vector> @@ -445,7 +469,8 @@ return CommentBlock; } -static std::vector> genHTML(const EnumInfo &I) { +static std::vector> +genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) { std::vector> Out; std::string EnumType; if (I.Scoped) @@ -460,8 +485,13 @@ if (Node) Out.emplace_back(std::move(Node)); - if (I.DefLoc) - Out.emplace_back(writeFileDefinition(I.DefLoc.getValue())); + if (I.DefLoc) { + if (!CDCtx.RepositoryUrl) + Out.emplace_back(writeFileDefinition(I.DefLoc.getValue())); + else + Out.emplace_back(writeFileDefinition( + I.DefLoc.getValue(), StringRef{CDCtx.RepositoryUrl.getValue()})); + } std::string Description; if (!I.Description.empty()) @@ -470,8 +500,9 @@ return Out; } -static std::vector> genHTML(const FunctionInfo &I, - StringRef ParentInfoDir) { +static std::vector> +genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx, + StringRef ParentInfoDir) { std::vector> Out; Out.emplace_back(llvm::make_unique(HTMLTag::TAG_H3, I.Name)); @@ -500,8 +531,13 @@ } FunctionHeader->Children.emplace_back(llvm::make_unique(")")); - if (I.DefLoc) - Out.emplace_back(writeFileDefinition(I.DefLoc.getValue())); + if (I.DefLoc) { + if (!CDCtx.RepositoryUrl) + Out.emplace_back(writeFileDefinition(I.DefLoc.getValue())); + else + Out.emplace_back(writeFileDefinition( + I.DefLoc.getValue(), StringRef{CDCtx.RepositoryUrl.getValue()})); + } std::string Description; if (!I.Description.empty()) @@ -510,8 +546,9 @@ return Out; } -static std::vector> genHTML(const NamespaceInfo &I, - std::string &InfoTitle) { +static std::vector> +genHTML(const NamespaceInfo &I, const ClangDocContext &CDCtx, + std::string &InfoTitle) { std::vector> Out; if (I.Name.str() == "") InfoTitle = "Global Namespace"; @@ -532,23 +569,29 @@ AppendVector(std::move(ChildRecords), Out); std::vector> ChildFunctions = - genFunctionsBlock(I.ChildFunctions, I.Path); + genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path); AppendVector(std::move(ChildFunctions), Out); std::vector> ChildEnums = - genEnumsBlock(I.ChildEnums); + genEnumsBlock(I.ChildEnums, CDCtx); AppendVector(std::move(ChildEnums), Out); return Out; } -static std::vector> genHTML(const RecordInfo &I, - std::string &InfoTitle) { +static std::vector> +genHTML(const RecordInfo &I, const ClangDocContext &CDCtx, + std::string &InfoTitle) { std::vector> Out; InfoTitle = (getTagType(I.TagType) + " " + I.Name).str(); Out.emplace_back(llvm::make_unique(HTMLTag::TAG_H1, InfoTitle)); - if (I.DefLoc) - Out.emplace_back(writeFileDefinition(I.DefLoc.getValue())); + if (I.DefLoc) { + if (!CDCtx.RepositoryUrl) + Out.emplace_back(writeFileDefinition(I.DefLoc.getValue())); + else + Out.emplace_back(writeFileDefinition( + I.DefLoc.getValue(), StringRef{CDCtx.RepositoryUrl.getValue()})); + } std::string Description; if (!I.Description.empty()) @@ -581,10 +624,10 @@ AppendVector(std::move(ChildRecords), Out); std::vector> ChildFunctions = - genFunctionsBlock(I.ChildFunctions, I.Path); + genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path); AppendVector(std::move(ChildFunctions), Out); std::vector> ChildEnums = - genEnumsBlock(I.ChildEnums); + genEnumsBlock(I.ChildEnums, CDCtx); AppendVector(std::move(ChildEnums), Out); return Out; @@ -610,25 +653,25 @@ switch (I->IT) { case InfoType::IT_namespace: { std::vector> Nodes = - genHTML(*static_cast(I), InfoTitle); + genHTML(*static_cast(I), CDCtx, InfoTitle); AppendVector(std::move(Nodes), MainContentNode->Children); break; } case InfoType::IT_record: { std::vector> Nodes = - genHTML(*static_cast(I), InfoTitle); + genHTML(*static_cast(I), CDCtx, InfoTitle); AppendVector(std::move(Nodes), MainContentNode->Children); break; } case InfoType::IT_enum: { std::vector> Nodes = - genHTML(*static_cast(I)); + genHTML(*static_cast(I), CDCtx); AppendVector(std::move(Nodes), MainContentNode->Children); break; } case InfoType::IT_function: { std::vector> Nodes = - genHTML(*static_cast(I), ""); + genHTML(*static_cast(I), CDCtx, ""); AppendVector(std::move(Nodes), MainContentNode->Children); break; } Index: clang-tools-extra/clang-doc/Mapper.h =================================================================== --- clang-tools-extra/clang-doc/Mapper.h +++ clang-tools-extra/clang-doc/Mapper.h @@ -44,7 +44,9 @@ template bool mapDecl(const T *D); int getLine(const NamedDecl *D, const ASTContext &Context) const; - StringRef getFile(const NamedDecl *D, const ASTContext &Context) const; + llvm::SmallString<128> getFile(const NamedDecl *D, const ASTContext &Context, + StringRef RootDir, + bool &IsFileInRootDir) const; comments::FullComment *getComment(const NamedDecl *D, const ASTContext &Context) const; Index: clang-tools-extra/clang-doc/Mapper.cpp =================================================================== --- clang-tools-extra/clang-doc/Mapper.cpp +++ clang-tools-extra/clang-doc/Mapper.cpp @@ -36,10 +36,12 @@ // If there is an error generating a USR for the decl, skip this decl. if (index::generateUSRForDecl(D, USR)) return true; - - auto I = serialize::emitInfo( - D, getComment(D, D->getASTContext()), getLine(D, D->getASTContext()), - getFile(D, D->getASTContext()), CDCtx.PublicOnly); + bool IsFileInRootDir; + llvm::SmallString<128> File = + getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir); + auto I = serialize::emitInfo(D, getComment(D, D->getASTContext()), + getLine(D, D->getASTContext()), File, + IsFileInRootDir, CDCtx.PublicOnly); // A null in place of I indicates that the serializer is skipping this decl // for some reason (e.g. we're only reporting public decls). @@ -87,11 +89,26 @@ return Context.getSourceManager().getPresumedLoc(D->getBeginLoc()).getLine(); } -llvm::StringRef MapASTVisitor::getFile(const NamedDecl *D, - const ASTContext &Context) const { - return Context.getSourceManager() - .getPresumedLoc(D->getBeginLoc()) - .getFilename(); +llvm::SmallString<128> MapASTVisitor::getFile(const NamedDecl *D, + const ASTContext &Context, + llvm::StringRef RootDir, + bool &IsFileInRootDir) const { + llvm::SmallString<128> File(Context.getSourceManager() + .getPresumedLoc(D->getBeginLoc()) + .getFilename()); + IsFileInRootDir = false; + if (RootDir.empty() || !File.startswith(RootDir)) + return File; + IsFileInRootDir = true; + llvm::SmallString<128> Prefix(RootDir); + // replace_path_prefix removes the exact prefix provided. The result of + // calling that function on ("A/B/C.c", "A/B", "") would be "/C.c", which + // starts with a / that is not needed. This is why we fix Prefix so it always + // ends with a / and the result has the desired format. + if (!llvm::sys::path::is_separator(Prefix.back())) + Prefix += llvm::sys::path::get_separator(); + llvm::sys::path::replace_path_prefix(File, Prefix, ""); + return File; } } // namespace doc Index: clang-tools-extra/clang-doc/Representation.h =================================================================== --- clang-tools-extra/clang-doc/Representation.h +++ clang-tools-extra/clang-doc/Representation.h @@ -205,6 +205,9 @@ Location() = default; Location(int LineNumber, SmallString<16> Filename) : LineNumber(LineNumber), Filename(std::move(Filename)) {} + Location(int LineNumber, SmallString<16> Filename, bool IsFileInRootDir) + : LineNumber(LineNumber), Filename(std::move(Filename)), + IsFileInRootDir(IsFileInRootDir) {} bool operator==(const Location &Other) const { return std::tie(LineNumber, Filename) == @@ -220,8 +223,9 @@ std::tie(Other.LineNumber, Other.Filename); } - int LineNumber; // Line number of this Location. - SmallString<32> Filename; // File for this Location. + int LineNumber; // Line number of this Location. + SmallString<32> Filename; // File for this Location. + bool IsFileInRootDir = false; // Indicates if file is inside root directory }; /// A base struct for Infos. @@ -372,14 +376,18 @@ struct ClangDocContext { ClangDocContext() = default; ClangDocContext(tooling::ExecutionContext *ECtx, bool PublicOnly, - StringRef OutDirectory, + StringRef OutDirectory, StringRef SourceRoot, + StringRef RepositoryUrl, std::vector UserStylesheets, - std::vector JsScripts) - : ECtx(ECtx), PublicOnly(PublicOnly), OutDirectory(OutDirectory), - UserStylesheets(UserStylesheets), JsScripts(JsScripts) {} + std::vector JsScripts); tooling::ExecutionContext *ECtx; - bool PublicOnly; - std::string OutDirectory; + bool PublicOnly; // Indicates if only public declarations are documented. + std::string OutDirectory; // Directory for outputting generated files. + std::string SourceRoot; // Directory where processed files are stored. Links + // to definition locations will only be generated if + // the file is in this dir. + // URL of repository that hosts code used for links to definition locations. + llvm::Optional RepositoryUrl; // Path of CSS stylesheets that will be copied to OutDirectory and used to // style all HTML files. std::vector UserStylesheets; Index: clang-tools-extra/clang-doc/Representation.cpp =================================================================== --- clang-tools-extra/clang-doc/Representation.cpp +++ clang-tools-extra/clang-doc/Representation.cpp @@ -235,5 +235,21 @@ C.sort(); } +ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx, + bool PublicOnly, StringRef OutDirectory, + StringRef SourceRoot, StringRef RepositoryUrl, + std::vector UserStylesheets, + std::vector JsScripts) + : ECtx(ECtx), PublicOnly(PublicOnly), OutDirectory(OutDirectory), + SourceRoot(SourceRoot), UserStylesheets(UserStylesheets), + JsScripts(JsScripts) { + if (!RepositoryUrl.empty()) { + this->RepositoryUrl = RepositoryUrl; + if (!RepositoryUrl.empty() && RepositoryUrl.find("http://") != 0 && + RepositoryUrl.find("https://") != 0) + this->RepositoryUrl->insert(0, "https://"); + } +} + } // namespace doc } // namespace clang Index: clang-tools-extra/clang-doc/Serialize.h =================================================================== --- clang-tools-extra/clang-doc/Serialize.h +++ clang-tools-extra/clang-doc/Serialize.h @@ -38,19 +38,19 @@ // nullptr. std::pair, std::unique_ptr> emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool PublicOnly); + StringRef File, bool IsFileInRootDir, bool PublicOnly); std::pair, std::unique_ptr> emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool PublicOnly); + StringRef File, bool IsFileInRootDir, bool PublicOnly); std::pair, std::unique_ptr> emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool PublicOnly); + StringRef File, bool IsFileInRootDir, bool PublicOnly); std::pair, std::unique_ptr> emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool PublicOnly); + StringRef File, bool IsFileInRootDir, bool PublicOnly); std::pair, std::unique_ptr> emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, - StringRef File, bool PublicOnly); + StringRef File, bool IsFileInRootDir, bool PublicOnly); // Function to hash a given USR value for storage. // As USRs (Unified Symbol Resolution) could be large, especially for functions Index: clang-tools-extra/clang-doc/Serialize.cpp =================================================================== --- clang-tools-extra/clang-doc/Serialize.cpp +++ clang-tools-extra/clang-doc/Serialize.cpp @@ -348,19 +348,21 @@ template static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, int LineNumber, StringRef Filename, + bool IsFileInRootDir, bool &IsInAnonymousNamespace) { populateInfo(I, D, C, IsInAnonymousNamespace); if (D->isThisDeclarationADefinition()) - I.DefLoc.emplace(LineNumber, Filename); + I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir); else - I.Loc.emplace_back(LineNumber, Filename); + I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir); } static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, int LineNumber, - StringRef Filename, + StringRef Filename, bool IsFileInRootDir, bool &IsInAnonymousNamespace) { - populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace); + populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir, + IsInAnonymousNamespace); if (const auto *T = getDeclForType(D->getReturnType())) { if (dyn_cast(T)) I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(), @@ -376,7 +378,7 @@ std::pair, std::unique_ptr> emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, - llvm::StringRef File, bool PublicOnly) { + llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { auto I = llvm::make_unique(); bool IsInAnonymousNamespace = false; populateInfo(*I, D, FC, IsInAnonymousNamespace); @@ -402,10 +404,11 @@ std::pair, std::unique_ptr> emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, - llvm::StringRef File, bool PublicOnly) { + llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { auto I = llvm::make_unique(); bool IsInAnonymousNamespace = false; - populateSymbolInfo(*I, D, FC, LineNumber, File, IsInAnonymousNamespace); + populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir, + IsInAnonymousNamespace); if (PublicOnly && ((IsInAnonymousNamespace || !isPublic(D->getAccess(), D->getLinkageInternal())))) return {}; @@ -452,10 +455,11 @@ std::pair, std::unique_ptr> emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber, - llvm::StringRef File, bool PublicOnly) { + llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { FunctionInfo Func; bool IsInAnonymousNamespace = false; - populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace); + populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, + IsInAnonymousNamespace); if (PublicOnly && ((IsInAnonymousNamespace || !isPublic(D->getAccess(), D->getLinkageInternal())))) return {}; @@ -477,10 +481,11 @@ std::pair, std::unique_ptr> emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, - llvm::StringRef File, bool PublicOnly) { + llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { FunctionInfo Func; bool IsInAnonymousNamespace = false; - populateFunctionInfo(Func, D, FC, LineNumber, File, IsInAnonymousNamespace); + populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, + IsInAnonymousNamespace); if (PublicOnly && ((IsInAnonymousNamespace || !isPublic(D->getAccess(), D->getLinkageInternal())))) return {}; @@ -511,10 +516,11 @@ std::pair, std::unique_ptr> emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber, - llvm::StringRef File, bool PublicOnly) { + llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { EnumInfo Enum; bool IsInAnonymousNamespace = false; - populateSymbolInfo(Enum, D, FC, LineNumber, File, IsInAnonymousNamespace); + populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir, + IsInAnonymousNamespace); if (PublicOnly && ((IsInAnonymousNamespace || !isPublic(D->getAccess(), D->getLinkageInternal())))) return {}; Index: clang-tools-extra/clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -72,6 +72,18 @@ llvm::cl::desc("CSS stylesheets to extend the default styles."), llvm::cl::cat(ClangDocCategory)); +static llvm::cl::opt SourceRoot("source-root", llvm::cl::desc(R"( +Directory where processed files are stored. +Links to definition locations will only be +generated if the file is in this dir.)"), + llvm::cl::cat(ClangDocCategory)); + +static llvm::cl::opt + RepositoryUrl("repository", llvm::cl::desc(R"( +URL of repository that hosts code. +Used for links to definition locations.)"), + llvm::cl::cat(ClangDocCategory)); + enum OutputFormatTy { md, yaml, @@ -138,7 +150,7 @@ // /A/B/C. // // namespace A { -// namesapce B { +// namespace B { // // class C {}; // @@ -211,10 +223,18 @@ tooling::ArgumentInsertPosition::END), ArgAdjuster); + llvm::SmallString<128> SourceRootDir; + // Check if the --source-root flag has a value + if (SourceRoot.empty()) + // If it's empty the current path is used as the default + llvm::sys::fs::current_path(SourceRootDir); + clang::doc::ClangDocContext CDCtx = { Exec->get()->getExecutionContext(), PublicOnly, OutDirectory, + SourceRootDir.str(), + RepositoryUrl, {UserStylesheets.begin(), UserStylesheets.end()}, {"index.js", "index_json.js"}}; Index: clang-tools-extra/docs/clang-doc.rst =================================================================== --- clang-tools-extra/docs/clang-doc.rst +++ clang-tools-extra/docs/clang-doc.rst @@ -66,7 +66,7 @@ .. code-block:: console - $ clang-doc --help + $ clang-doc --help USAGE: clang-doc [options] [... ] OPTIONS: @@ -79,17 +79,27 @@ clang-doc options: - -doxygen - Use only doxygen-style comments to generate docs. - -dump - Dump intermediate results to bitcode file. - -extra-arg= - Additional argument to append to the compiler command line - -extra-arg-before= - Additional argument to prepend to the compiler command line - --format= - Format for outputted docs. - =yaml - Documentation in YAML format. - =md - Documentation in MD format. - =html - Documentation in HTML format. - -output= - Directory for outputting generated files. - -p= - Build path - --public - Document only public declarations. - --stylesheets= - CSS stylesheets to extend the default styles. - -``stylesheets`` should only be used if ``format`` is set to ``html``. + --doxygen - Use only doxygen-style comments to generate docs. + --extra-arg= - Additional argument to append to the compiler command line + --extra-arg-before= - Additional argument to prepend to the compiler command line + --format= - Format for outputted docs. + =yaml - Documentation in YAML format. + =md - Documentation in MD format. + =html - Documentation in HTML format. + --ignore-map-errors - Continue if files are not mapped correctly. + --output= - Directory for outputting generated files. + -p= - Build path + --public - Document only public declarations. + --repository= - + URL of repository that hosts code. + Used for links to definition locations. + --source-root= - + Directory where processed files are stored. + Links to definition locations will only be + generated if the file is in this dir. + --stylesheets= - CSS stylesheets to extend the default styles. + +The following flags shoud only be used if ``format`` is set to ``html``: +- ``repository`` +- ``source-root`` +- ``stylesheets`` Index: clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp +++ clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp @@ -22,9 +22,9 @@ } ClangDocContext -getClangDocContext(std::vector UserStylesheets = {}) { - ClangDocContext CDCtx; - CDCtx.UserStylesheets = {UserStylesheets.begin(), UserStylesheets.end()}; +getClangDocContext(std::vector UserStylesheets = {}, + StringRef RepositoryUrl = "") { + ClangDocContext CDCtx{{}, {}, {}, {}, RepositoryUrl, UserStylesheets, {}}; CDCtx.UserStylesheets.insert( CDCtx.UserStylesheets.begin(), "../share/clang/clang-doc-default-stylesheet.css"); @@ -90,7 +90,7 @@ I.Path = "X/Y/Z"; I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); - I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}); + I.DefLoc = Location(10, llvm::SmallString<16>{"dir/test.cpp"}, true); I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"}); SmallString<16> PathTo; @@ -110,7 +110,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - ClangDocContext CDCtx = getClangDocContext(); + ClangDocContext CDCtx = getClangDocContext({}, "http://www.repository.com"); auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); std::string Expected = R"raw( @@ -121,7 +121,12 @@

class r

-

Defined at line 10 of test.cpp

+

+ Defined at line + 10 + of file + test.cpp +

Inherits from F @@ -159,7 +164,7 @@ I.Name = "f"; I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); - I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}); + I.DefLoc = Location(10, llvm::SmallString<16>{"dir/test.cpp"}, false); I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"}); SmallString<16> PathTo; @@ -173,7 +178,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - ClangDocContext CDCtx = getClangDocContext(); + ClangDocContext CDCtx = getClangDocContext({}, "https://www.repository.com"); auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); std::string Expected = R"raw( @@ -190,7 +195,7 @@ int P)

-

Defined at line 10 of test.cpp

+

Defined at line 10 of file dir/test.cpp

)raw"; @@ -202,7 +207,7 @@ I.Name = "e"; I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); - I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}); + I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}, true); I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"}); I.Members.emplace_back("X"); @@ -212,7 +217,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - ClangDocContext CDCtx = getClangDocContext(); + ClangDocContext CDCtx = getClangDocContext({}, "www.repository.com"); auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); std::string Expected = R"raw( @@ -226,7 +231,12 @@
  • X
-

Defined at line 10 of test.cpp

+

+ Defined at line + 10 + of file + test.cpp +

)raw"; @@ -295,7 +305,7 @@

f

void f(int I, int J)

-

Defined at line 10 of test.cpp

+

Defined at line 10 of file test.cpp

Brief description.

Index: clang-tools-extra/unittests/clang-doc/SerializeTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/SerializeTest.cpp +++ clang-tools-extra/unittests/clang-doc/SerializeTest.cpp @@ -37,7 +37,7 @@ template bool mapDecl(const T *D) { auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0, - /*File=*/"test.cpp", Public); + /*File=*/"test.cpp", true, Public); if (I.first) EmittedInfos.emplace_back(std::move(I.first)); if (I.second)