[clang-tools-extra] r368460 - [clang-format] Add link to source code in file definitions

Diego Astiazaran via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 9 10:49:41 PDT 2019


Author: diegoastiazaran
Date: Fri Aug  9 10:49:41 2019
New Revision: 368460

URL: http://llvm.org/viewvc/llvm-project?rev=368460&view=rev
Log:
[clang-format] Add link to source code in file definitions

Two command line options have been added to clang-doc.
  --repository=<string>       - URL of repository that hosts code; used for links to definition locations.
  --source-root=<string>      - Directory where processed files are stored. Links to definition locations will only be generated if the file is in this dir.

If the file is in the source-root and a repository options is passed;
a link to the source code will be rendered by the HTML generator.

Differential Revision: https://reviews.llvm.org/D65483

Modified:
    clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
    clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
    clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
    clang-tools-extra/trunk/clang-doc/Mapper.cpp
    clang-tools-extra/trunk/clang-doc/Mapper.h
    clang-tools-extra/trunk/clang-doc/Representation.cpp
    clang-tools-extra/trunk/clang-doc/Representation.h
    clang-tools-extra/trunk/clang-doc/Serialize.cpp
    clang-tools-extra/trunk/clang-doc/Serialize.h
    clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
    clang-tools-extra/trunk/docs/clang-doc.rst
    clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
    clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp

Modified: clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp Fri Aug  9 10:49:41 2019
@@ -83,7 +83,7 @@ llvm::Error decodeRecord(Record R, llvm:
   if (R[0] > INT_MAX)
     return llvm::make_error<llvm::StringError>("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 @@ llvm::Error decodeRecord(Record R, llvm:
   if (R[0] > INT_MAX)
     return llvm::make_error<llvm::StringError>("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();
 }
 

Modified: clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp Fri Aug  9 10:49:41 2019
@@ -77,10 +77,13 @@ static void LocationAbbrev(std::shared_p
       {// 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 @@ void ClangDocBitcodeWriter::emitRecord(c
   // 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);
 }

Modified: clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp Fri Aug  9 10:49:41 2019
@@ -301,12 +301,15 @@ genReferenceList(const llvm::SmallVector
   return Out;
 }
 
-static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);
-static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
-                                                     StringRef ParentInfoDir);
+static std::vector<std::unique_ptr<TagNode>>
+genHTML(const EnumInfo &I, const ClangDocContext &CDCtx);
+static std::vector<std::unique_ptr<TagNode>>
+genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
+        StringRef ParentInfoDir);
 
 static std::vector<std::unique_ptr<TagNode>>
-genEnumsBlock(const std::vector<EnumInfo> &Enums) {
+genEnumsBlock(const std::vector<EnumInfo> &Enums,
+              const ClangDocContext &CDCtx) {
   if (Enums.empty())
     return {};
 
@@ -316,7 +319,7 @@ genEnumsBlock(const std::vector<EnumInfo
   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
   auto &DivBody = Out.back();
   for (const auto &E : Enums) {
-    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E);
+    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E, CDCtx);
     AppendVector(std::move(Nodes), DivBody->Children);
   }
   return Out;
@@ -335,7 +338,7 @@ genEnumMembersBlock(const llvm::SmallVec
 
 static std::vector<std::unique_ptr<TagNode>>
 genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
-                  StringRef ParentInfoDir) {
+                  const ClangDocContext &CDCtx, StringRef ParentInfoDir) {
   if (Functions.empty())
     return {};
 
@@ -345,7 +348,8 @@ genFunctionsBlock(const std::vector<Func
   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
   auto &DivBody = Out.back();
   for (const auto &F : Functions) {
-    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F, ParentInfoDir);
+    std::vector<std::unique_ptr<TagNode>> Nodes =
+        genHTML(F, CDCtx, ParentInfoDir);
     AppendVector(std::move(Nodes), DivBody->Children);
   }
   return Out;
@@ -392,10 +396,30 @@ genReferencesBlock(const std::vector<Ref
   return Out;
 }
 
-static std::unique_ptr<TagNode> writeFileDefinition(const Location &L) {
-  return llvm::make_unique<TagNode>(
-      HTMLTag::TAG_P,
-      "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename);
+static std::unique_ptr<TagNode>
+writeFileDefinition(const Location &L,
+                    llvm::Optional<StringRef> RepositoryUrl = None) {
+  if (!L.IsFileInRootDir || !RepositoryUrl)
+    return llvm::make_unique<TagNode>(
+        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<TagNode>(HTMLTag::TAG_P);
+  Node->Children.emplace_back(llvm::make_unique<TextNode>("Defined at line "));
+  auto LocNumberNode =
+      llvm::make_unique<TagNode>(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<TextNode>(" of file "));
+  auto LocFileNode = llvm::make_unique<TagNode>(
+      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<std::unique_ptr<TagNode>>
@@ -491,7 +515,8 @@ static std::unique_ptr<TagNode> genHTML(
   return CommentBlock;
 }
 
-static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) {
+static std::vector<std::unique_ptr<TagNode>>
+genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
   std::vector<std::unique_ptr<TagNode>> Out;
   std::string EnumType;
   if (I.Scoped)
@@ -508,8 +533,13 @@ static std::vector<std::unique_ptr<TagNo
   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())
@@ -518,8 +548,9 @@ static std::vector<std::unique_ptr<TagNo
   return Out;
 }
 
-static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
-                                                     StringRef ParentInfoDir) {
+static std::vector<std::unique_ptr<TagNode>>
+genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
+        StringRef ParentInfoDir) {
   std::vector<std::unique_ptr<TagNode>> Out;
   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
   // USR is used as id for functions instead of name to disambiguate function
@@ -552,8 +583,13 @@ static std::vector<std::unique_ptr<TagNo
   }
   FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")"));
 
-  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())
@@ -563,7 +599,8 @@ static std::vector<std::unique_ptr<TagNo
 }
 
 static std::vector<std::unique_ptr<TagNode>>
-genHTML(const NamespaceInfo &I, Index &InfoIndex, std::string &InfoTitle) {
+genHTML(const NamespaceInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
+        std::string &InfoTitle) {
   std::vector<std::unique_ptr<TagNode>> Out;
   if (I.Name.str() == "")
     InfoTitle = "Global Namespace";
@@ -584,10 +621,10 @@ genHTML(const NamespaceInfo &I, Index &I
   AppendVector(std::move(ChildRecords), Out);
 
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
-      genFunctionsBlock(I.ChildFunctions, I.Path);
+      genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path);
   AppendVector(std::move(ChildFunctions), Out);
   std::vector<std::unique_ptr<TagNode>> ChildEnums =
-      genEnumsBlock(I.ChildEnums);
+      genEnumsBlock(I.ChildEnums, CDCtx);
   AppendVector(std::move(ChildEnums), Out);
 
   if (!I.ChildNamespaces.empty())
@@ -604,13 +641,19 @@ genHTML(const NamespaceInfo &I, Index &I
 }
 
 static std::vector<std::unique_ptr<TagNode>>
-genHTML(const RecordInfo &I, Index &InfoIndex, std::string &InfoTitle) {
+genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
+        std::string &InfoTitle) {
   std::vector<std::unique_ptr<TagNode>> Out;
   InfoTitle = (getTagType(I.TagType) + " " + I.Name).str();
   Out.emplace_back(llvm::make_unique<TagNode>(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())
@@ -643,10 +686,10 @@ genHTML(const RecordInfo &I, Index &Info
   AppendVector(std::move(ChildRecords), Out);
 
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
-      genFunctionsBlock(I.ChildFunctions, I.Path);
+      genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path);
   AppendVector(std::move(ChildFunctions), Out);
   std::vector<std::unique_ptr<TagNode>> ChildEnums =
-      genEnumsBlock(I.ChildEnums);
+      genEnumsBlock(I.ChildEnums, CDCtx);
   AppendVector(std::move(ChildEnums), Out);
 
   if (!I.Members.empty())
@@ -682,26 +725,27 @@ llvm::Error HTMLGenerator::generateDocFo
   Index InfoIndex;
   switch (I->IT) {
   case InfoType::IT_namespace: {
-    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(
-        *static_cast<clang::doc::NamespaceInfo *>(I), InfoIndex, InfoTitle);
+    std::vector<std::unique_ptr<TagNode>> Nodes =
+        genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), InfoIndex, CDCtx,
+                InfoTitle);
     AppendVector(std::move(Nodes), MainContentNode->Children);
     break;
   }
   case InfoType::IT_record: {
     std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(
-        *static_cast<clang::doc::RecordInfo *>(I), InfoIndex, InfoTitle);
+        *static_cast<clang::doc::RecordInfo *>(I), InfoIndex, CDCtx, InfoTitle);
     AppendVector(std::move(Nodes), MainContentNode->Children);
     break;
   }
   case InfoType::IT_enum: {
     std::vector<std::unique_ptr<TagNode>> Nodes =
-        genHTML(*static_cast<clang::doc::EnumInfo *>(I));
+        genHTML(*static_cast<clang::doc::EnumInfo *>(I), CDCtx);
     AppendVector(std::move(Nodes), MainContentNode->Children);
     break;
   }
   case InfoType::IT_function: {
     std::vector<std::unique_ptr<TagNode>> Nodes =
-        genHTML(*static_cast<clang::doc::FunctionInfo *>(I), "");
+        genHTML(*static_cast<clang::doc::FunctionInfo *>(I), CDCtx, "");
     AppendVector(std::move(Nodes), MainContentNode->Children);
     break;
   }

Modified: clang-tools-extra/trunk/clang-doc/Mapper.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Mapper.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Mapper.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Mapper.cpp Fri Aug  9 10:49:41 2019
@@ -36,10 +36,12 @@ template <typename T> bool MapASTVisitor
   // 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 @@ int MapASTVisitor::getLine(const NamedDe
   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

Modified: clang-tools-extra/trunk/clang-doc/Mapper.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Mapper.h?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Mapper.h (original)
+++ clang-tools-extra/trunk/clang-doc/Mapper.h Fri Aug  9 10:49:41 2019
@@ -44,7 +44,9 @@ private:
   template <typename T> 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;
 

Modified: clang-tools-extra/trunk/clang-doc/Representation.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.cpp Fri Aug  9 10:49:41 2019
@@ -235,5 +235,21 @@ void Index::sort() {
     C.sort();
 }
 
+ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
+                                 bool PublicOnly, StringRef OutDirectory,
+                                 StringRef SourceRoot, StringRef RepositoryUrl,
+                                 std::vector<std::string> UserStylesheets,
+                                 std::vector<std::string> 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

Modified: clang-tools-extra/trunk/clang-doc/Representation.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.h (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.h Fri Aug  9 10:49:41 2019
@@ -205,6 +205,9 @@ struct Location {
   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 @@ struct Location {
            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.
@@ -375,14 +379,18 @@ mergeInfos(std::vector<std::unique_ptr<I
 struct ClangDocContext {
   ClangDocContext() = default;
   ClangDocContext(tooling::ExecutionContext *ECtx, bool PublicOnly,
-                  StringRef OutDirectory,
+                  StringRef OutDirectory, StringRef SourceRoot,
+                  StringRef RepositoryUrl,
                   std::vector<std::string> UserStylesheets,
-                  std::vector<std::string> JsScripts)
-      : ECtx(ECtx), PublicOnly(PublicOnly), OutDirectory(OutDirectory),
-        UserStylesheets(UserStylesheets), JsScripts(JsScripts) {}
+                  std::vector<std::string> 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<std::string> RepositoryUrl;
   // Path of CSS stylesheets that will be copied to OutDirectory and used to
   // style all HTML files.
   std::vector<std::string> UserStylesheets;

Modified: clang-tools-extra/trunk/clang-doc/Serialize.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Serialize.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/Serialize.cpp Fri Aug  9 10:49:41 2019
@@ -348,19 +348,21 @@ static void populateInfo(Info &I, const
 template <typename T>
 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<EnumDecl>(T))
       I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),
@@ -376,7 +378,7 @@ static void populateFunctionInfo(Functio
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 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<NamespaceInfo>();
   bool IsInAnonymousNamespace = false;
   populateInfo(*I, D, FC, IsInAnonymousNamespace);
@@ -402,10 +404,11 @@ emitInfo(const NamespaceDecl *D, const F
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 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<RecordInfo>();
   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 @@ emitInfo(const RecordDecl *D, const Full
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 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 @@ emitInfo(const FunctionDecl *D, const Fu
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 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 @@ emitInfo(const CXXMethodDecl *D, const F
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 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 {};

Modified: clang-tools-extra/trunk/clang-doc/Serialize.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.h?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Serialize.h (original)
+++ clang-tools-extra/trunk/clang-doc/Serialize.h Fri Aug  9 10:49:41 2019
@@ -38,19 +38,19 @@ namespace serialize {
 // nullptr.
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
-         StringRef File, bool PublicOnly);
+         StringRef File, bool IsFileInRootDir, bool PublicOnly);
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
-         StringRef File, bool PublicOnly);
+         StringRef File, bool IsFileInRootDir, bool PublicOnly);
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
-         StringRef File, bool PublicOnly);
+         StringRef File, bool IsFileInRootDir, bool PublicOnly);
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
-         StringRef File, bool PublicOnly);
+         StringRef File, bool IsFileInRootDir, bool PublicOnly);
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 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

Modified: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp Fri Aug  9 10:49:41 2019
@@ -76,6 +76,18 @@ static llvm::cl::list<std::string> UserS
     llvm::cl::desc("CSS stylesheets to extend the default styles."),
     llvm::cl::cat(ClangDocCategory));
 
+static llvm::cl::opt<std::string> 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<std::string>
+    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,
@@ -142,7 +154,7 @@ bool CreateDirectory(const Twine &DirNam
 // <root>/A/B/C.<ext>
 //
 // namespace A {
-// namesapce B {
+// namespace B {
 //
 // class C {};
 //
@@ -191,10 +203,18 @@ int main(int argc, const char **argv) {
                                   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"}};
 

Modified: clang-tools-extra/trunk/docs/clang-doc.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-doc.rst?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-doc.rst (original)
+++ clang-tools-extra/trunk/docs/clang-doc.rst Fri Aug  9 10:49:41 2019
@@ -66,7 +66,7 @@ Options
 
 .. code-block:: console
 
-	$ clang-doc --help
+  $ clang-doc --help
   USAGE: clang-doc [options] <source0> [... <sourceN>]
 
   OPTIONS:
@@ -79,17 +79,27 @@ Options
 
   clang-doc options:
 
-    -doxygen                   - Use only doxygen-style comments to generate docs.
-    -dump                      - Dump intermediate results to bitcode file.
-    -extra-arg=<string>        - Additional argument to append to the compiler command line
-    -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
-    --format=<value>           - Format for outputted docs.
-      =yaml                    -   Documentation in YAML format.
-      =md                      -   Documentation in MD format.
-      =html                    -   Documentation in HTML format.
-    -output=<string>           - Directory for outputting generated files.
-    -p=<string>                - Build path
-    --public                   - Document only public declarations.
-    --stylesheets=<string>     - 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=<string>        - Additional argument to append to the compiler command line
+    --extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+    --format=<value>            - 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=<string>           - Directory for outputting generated files.
+    -p=<string>                 - Build path
+    --public                    - Document only public declarations.
+    --repository=<string>       -
+                                  URL of repository that hosts code.
+                                  Used for links to definition locations.
+    --source-root=<string>      -
+                                  Directory where processed files are stored.
+                                  Links to definition locations will only be
+                                  generated if the file is in this dir.
+    --stylesheets=<string>      - CSS stylesheets to extend the default styles.
+
+The following flags shoud only be used if ``format`` is set to ``html``:
+- ``repository``
+- ``source-root``
+- ``stylesheets``

Modified: clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp Fri Aug  9 10:49:41 2019
@@ -23,9 +23,9 @@ std::unique_ptr<Generator> getHTMLGenera
 }
 
 ClangDocContext
-getClangDocContext(std::vector<std::string> UserStylesheets = {}) {
-  ClangDocContext CDCtx;
-  CDCtx.UserStylesheets = {UserStylesheets.begin(), UserStylesheets.end()};
+getClangDocContext(std::vector<std::string> UserStylesheets = {},
+                   StringRef RepositoryUrl = "") {
+  ClangDocContext CDCtx{{}, {}, {}, {}, RepositoryUrl, UserStylesheets, {}};
   CDCtx.UserStylesheets.insert(
       CDCtx.UserStylesheets.begin(),
       "../share/clang/clang-doc-default-stylesheet.css");
@@ -127,7 +127,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML)
   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;
@@ -147,7 +147,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML)
   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(<!DOCTYPE html>
@@ -194,7 +194,12 @@ TEST(HTMLGeneratorTest, emitRecordHTML)
 </ul>
 <div>
   <h1>class r</h1>
-  <p>Defined at line 10 of test.cpp</p>
+  <p>
+    Defined at line 
+    <a href="http://www.repository.com/dir/test.cpp#10">10</a>
+     of file 
+    <a href="http://www.repository.com/dir/test.cpp">test.cpp</a>
+  </p>
   <p>
     Inherits from 
     <a href="../../../path/to/F.html">F</a>
@@ -232,7 +237,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML
   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;
@@ -246,7 +251,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML
   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(<!DOCTYPE html>
@@ -263,7 +268,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML
     <a href="path/to/int.html">int</a>
      P)
   </p>
-  <p>Defined at line 10 of test.cpp</p>
+  <p>Defined at line 10 of file dir/test.cpp</p>
 </div>
 )raw";
 
@@ -275,7 +280,7 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
   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");
@@ -285,7 +290,7 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
   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(<!DOCTYPE html>
@@ -299,7 +304,12 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
   <ul>
     <li>X</li>
   </ul>
-  <p>Defined at line 10 of test.cpp</p>
+  <p>
+    Defined at line 
+    <a href="https://www.repository.com/test.cpp#10">10</a>
+     of file 
+    <a href="https://www.repository.com/test.cpp">test.cpp</a>
+  </p>
 </div>
 )raw";
 
@@ -368,7 +378,7 @@ TEST(HTMLGeneratorTest, emitCommentHTML)
 <div>
   <h3 id="0000000000000000000000000000000000000000">f</h3>
   <p>void f(int I, int J)</p>
-  <p>Defined at line 10 of test.cpp</p>
+  <p>Defined at line 10 of file test.cpp</p>
   <div>
     <div>
       <p> Brief description.</p>

Modified: clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp?rev=368460&r1=368459&r2=368460&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp Fri Aug  9 10:49:41 2019
@@ -37,7 +37,7 @@ public:
 
   template <typename T> 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)




More information about the cfe-commits mailing list