DiegoAstiazaran created this revision.
DiegoAstiazaran added reviewers: juliehockett, jakehehrlich, lebedev.ri.
DiegoAstiazaran added a project: clang-tools-extra.
Herald added subscribers: kadircet, arphaman.

<a> tags are added for the parents of records.
The link redirects to the parent's info file.

Depends on D63180 <https://reviews.llvm.org/D63180>.


https://reviews.llvm.org/D63663

Files:
  clang-tools-extra/clang-doc/Generators.cpp
  clang-tools-extra/clang-doc/Generators.h
  clang-tools-extra/clang-doc/HTMLGenerator.cpp
  clang-tools-extra/clang-doc/MDGenerator.cpp
  clang-tools-extra/clang-doc/Representation.h
  clang-tools-extra/clang-doc/YAMLGenerator.cpp
  clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
  clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
  clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
  clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp

Index: clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -39,7 +39,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -89,7 +90,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -148,7 +150,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -194,7 +197,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -331,7 +335,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected =
       R"raw(---
Index: clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -38,7 +38,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(# namespace Namespace
 
@@ -101,7 +102,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(# class r
 
@@ -162,7 +164,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(### f
 
@@ -190,7 +193,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(| enum class e |
 
@@ -320,7 +324,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected =
       R"raw(### f
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
@@ -9,6 +9,7 @@
 #include "ClangDocTest.h"
 #include "Generators.h"
 #include "Representation.h"
+#include "Serialize.h"
 #include "gtest/gtest.h"
 
 namespace clang {
@@ -38,7 +39,9 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(<h1>namespace Namespace</h1>
 <br>
@@ -72,7 +75,7 @@
 
   I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
   I.TagType = TagTypeKind::TTK_Class;
-  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
+  I.Parents.emplace_back(serialize::hashUSR("1"), "F", InfoType::IT_record);
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
@@ -81,15 +84,20 @@
   I.ChildEnums.emplace_back();
   I.ChildEnums.back().Name = "OneEnum";
 
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto A = llvm::make_unique<Info>();
+  A->Path = "path/to/A.html";
+  Infos.emplace(toHex(llvm::toStringRef(I.Parents[0].USR)), std::move(A));
+
   auto G = getHTMLGenerator();
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(<h1>class r</h1>
 <p><em>Defined at line 10 of test.cpp</em></p>
-<p>Inherits from F, G</p>
+<p>Inherits from <a href="path/to/A.html">F</a>, G</p>
 <br>
 <h2>Members</h2>
 <p>private int X</p>
@@ -128,7 +136,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(<h3>f</h3>
 <p><em>void f(int P)</em></p>
@@ -153,7 +162,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(<p>| enum class e |</p>
 <p>--</p>
@@ -279,7 +289,8 @@
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual);
+  std::map<std::string, std::unique_ptr<doc::Info>> Infos;
+  auto Err = G->generateDocForInfo(&I, Actual, Infos);
   assert(!Err);
   std::string Expected = R"raw(<h3>f</h3>
 <p><em>void f(int I, int J)</em></p>
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
@@ -217,6 +217,7 @@
     return 1;
 
   // First reducing phase (reduce all decls into one info per decl).
+  std::map<std::string, std::unique_ptr<doc::Info>> ReducedInfos;
   llvm::outs() << "Reducing " << USRToInfos.size() << " infos...\n";
   for (auto &Group : USRToInfos) {
     auto Reduced = doc::mergeInfos(Group.getValue());
@@ -233,14 +234,23 @@
       llvm::errs() << toString(InfoPath.takeError()) << "\n";
       continue;
     }
+
+    I->Path = InfoPath.get();
+    ReducedInfos.emplace(Group.getKey(), std::move(Reduced.get()));
+  }
+
+  llvm::outs() << "Generating docs...\n";
+  for (auto &Reduced : ReducedInfos) {
+    doc::Info *I = Reduced.second.get();
+
     std::error_code FileErr;
-    llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
+    llvm::raw_fd_ostream InfoOS(I->Path, FileErr, llvm::sys::fs::F_None);
     if (FileErr != OK) {
       llvm::errs() << "Error opening info file: " << FileErr.message() << "\n";
       continue;
     }
 
-    if (auto Err = G->get()->generateDocForInfo(I, InfoOS))
+    if (auto Err = G->get()->generateDocForInfo(I, InfoOS, ReducedInfos))
       llvm::errs() << toString(std::move(Err)) << "\n";
   }
 
Index: clang-tools-extra/clang-doc/YAMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -241,12 +241,16 @@
 public:
   static const char *Format;
 
-  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
-};
-
-const char *YAMLGenerator::Format = "yaml";
-
-llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+  llvm::Error generateDocForInfo(
+      Info *I, llvm::raw_ostream &OS,
+      const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) override;
+ };
+ 
+ const char *YAMLGenerator::Format = "yaml";
+ 
+llvm::Error YAMLGenerator::generateDocForInfo(
+    Info *I, llvm::raw_ostream &OS,
+    const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) {
   llvm::yaml::Output InfoYAML(OS);
   switch (I->IT) {
   case InfoType::IT_namespace:
Index: clang-tools-extra/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/clang-doc/Representation.h
+++ clang-tools-extra/clang-doc/Representation.h
@@ -171,6 +171,7 @@
   llvm::SmallVector<Reference, 4>
       Namespace; // List of parent namespaces for this decl.
   std::vector<CommentInfo> Description; // Comment description of this decl.
+  llvm::SmallString<128> Path;          // Path of generated file by clang-doc
 
   void mergeBase(Info &&I);
   bool mergeable(const Info &Other);
Index: clang-tools-extra/clang-doc/MDGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/MDGenerator.cpp
+++ clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -30,6 +30,19 @@
   return "[" + Text.str() + "](" + Link.str() + ")";
 }
 
+std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
+  std::string Buffer;
+  llvm::raw_string_ostream Stream(Buffer);
+  bool First = true;
+  for (const auto &R : Refs) {
+    if (!First)
+      Stream << ", ";
+    Stream << R.Name;
+    First = false;
+  }
+  return Stream.str();
+}
+
 void writeLine(const Twine &Text, raw_ostream &OS) { OS << Text << "\n\n"; }
 
 void writeNewLine(raw_ostream &OS) { OS << "\n\n"; }
@@ -240,12 +253,16 @@
 public:
   static const char *Format;
 
-  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
-};
-
-const char *MDGenerator::Format = "md";
-
-llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+  llvm::Error generateDocForInfo(
+      Info *I, llvm::raw_ostream &OS,
+      const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) override;
+ };
+ 
+ const char *MDGenerator::Format = "md";
+ 
+llvm::Error MDGenerator::generateDocForInfo(
+    Info *I, llvm::raw_ostream &OS,
+    const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) {
   switch (I->IT) {
   case InfoType::IT_namespace:
     genMarkdown(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -26,10 +26,47 @@
   return "<" + Tag.str() + ">" + Text.str() + "</" + Tag.str() + ">";
 }
 
+std::string genTag(const Twine &Text, const Twine &Tag,
+                   const llvm::StringMap<std::string> &Options) {
+  std::string OptionsText = "";
+  for (auto &Option : Options) {
+    OptionsText = OptionsText + " " + Option.getKey().str() + "=\"" +
+                  Option.getValue() + "\"";
+  }
+  return "<" + Tag.str() + OptionsText + ">" + Text.str() + "</" + Tag.str() +
+         ">";
+}
+
 std::string genItalic(const Twine &Text) { return genTag(Text, "em"); }
 
 std::string genEmphasis(const Twine &Text) { return genTag(Text, "strong"); }
 
+std::string genLink(const Twine &Text, const Twine &Link) {
+  llvm::StringMap<std::string> Options;
+  Options.try_emplace("href", Link.str());
+  return genTag(Text.str(), "a", Options);
+}
+
+std::string genReferenceList(
+    const llvm::SmallVectorImpl<Reference> &Refs,
+    const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) {
+  std::string Buffer;
+  llvm::raw_string_ostream Stream(Buffer);
+  bool First = true;
+  for (const auto &R : Refs) {
+    if (!First)
+      Stream << ", ";
+    const auto &It = Infos.find(toHex(llvm::toStringRef(R.USR)));
+    if (It != Infos.end()) {
+      Stream << genLink(R.Name, It->second->Path);
+    } else {
+      Stream << R.Name;
+    }
+    First = false;
+  }
+  return Stream.str();
+}
+
 void writeLine(const Twine &Text, raw_ostream &OS) {
   OS << genTag(Text, "p") << "\n";
 }
@@ -182,7 +219,8 @@
   }
 }
 
-void genHTML(const RecordInfo &I, llvm::raw_ostream &OS) {
+void genHTML(const RecordInfo &I, llvm::raw_ostream &OS,
+             const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) {
   writeHeader(getTagType(I.TagType) + " " + I.Name, "1", OS);
   if (I.DefLoc)
     writeFileDefinition(I.DefLoc.getValue(), OS);
@@ -193,8 +231,8 @@
     writeNewLine(OS);
   }
 
-  std::string Parents = genReferenceList(I.Parents);
-  std::string VParents = genReferenceList(I.VirtualParents);
+  std::string Parents = genReferenceList(I.Parents, Infos);
+  std::string VParents = genReferenceList(I.VirtualParents, Infos);
   if (!Parents.empty() || !VParents.empty()) {
     if (Parents.empty())
       writeLine("Inherits from " + VParents, OS);
@@ -242,18 +280,22 @@
 public:
   static const char *Format;
 
-  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
+  llvm::Error generateDocForInfo(
+      Info *I, llvm::raw_ostream &OS,
+      const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) override;
 };
 
 const char *HTMLGenerator::Format = "html";
 
-llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+llvm::Error HTMLGenerator::generateDocForInfo(
+    Info *I, llvm::raw_ostream &OS,
+    const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) {
   switch (I->IT) {
   case InfoType::IT_namespace:
     genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
     break;
   case InfoType::IT_record:
-    genHTML(*static_cast<clang::doc::RecordInfo *>(I), OS);
+    genHTML(*static_cast<clang::doc::RecordInfo *>(I), OS, Infos);
     break;
   case InfoType::IT_enum:
     genHTML(*static_cast<clang::doc::EnumInfo *>(I), OS);
Index: clang-tools-extra/clang-doc/Generators.h
===================================================================
--- clang-tools-extra/clang-doc/Generators.h
+++ clang-tools-extra/clang-doc/Generators.h
@@ -26,7 +26,9 @@
   virtual ~Generator() = default;
 
   // Write out the decl info in the specified format.
-  virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0;
+  virtual llvm::Error generateDocForInfo(
+      Info *I, llvm::raw_ostream &OS,
+      const std::map<std::string, std::unique_ptr<doc::Info>> &Infos) = 0;
 };
 
 typedef llvm::Registry<Generator> GeneratorRegistry;
@@ -38,8 +40,6 @@
 
 std::string getTagType(TagTypeKind AS);
 
-std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs);
-
 } // namespace doc
 } // namespace clang
 
Index: clang-tools-extra/clang-doc/Generators.cpp
===================================================================
--- clang-tools-extra/clang-doc/Generators.cpp
+++ clang-tools-extra/clang-doc/Generators.cpp
@@ -57,19 +57,6 @@
   llvm_unreachable("Unknown TagTypeKind");
 }
 
-std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
-  std::string Buffer;
-  llvm::raw_string_ostream Stream(Buffer);
-  bool First = true;
-  for (const auto &R : Refs) {
-    if (!First)
-      Stream << ", ";
-    Stream << R.Name;
-    First = false;
-  }
-  return Stream.str();
-}
-
 // This anchor is used to force the linker to link in the generated object file
 // and thus register the generators.
 extern volatile int YAMLGeneratorAnchorSource;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to