DiegoAstiazaran updated this revision to Diff 207611.
DiegoAstiazaran edited the summary of this revision.
DiegoAstiazaran added a parent revision: D63857: [clang-doc] Add a structured 
HTML generator.
DiegoAstiazaran added a comment.

The links are now generated using the nodes structure introduced by D63857 
<https://reviews.llvm.org/D63857>.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63663/new/

https://reviews.llvm.org/D63663

Files:
  clang-tools-extra/clang-doc/BitcodeReader.cpp
  clang-tools-extra/clang-doc/BitcodeWriter.cpp
  clang-tools-extra/clang-doc/BitcodeWriter.h
  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/Mapper.cpp
  clang-tools-extra/clang-doc/Representation.cpp
  clang-tools-extra/clang-doc/Representation.h
  clang-tools-extra/clang-doc/Serialize.cpp
  clang-tools-extra/clang-doc/Serialize.h
  clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
  clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
  clang-tools-extra/unittests/clang-doc/SerializeTest.cpp

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 @@
 
   bool VisitNamespaceDecl(const NamespaceDecl *D) {
     auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
+                                 /*File=*/"test.cpp", Public, "");
     if (I)
       EmittedInfos.emplace_back(std::move(I));
     return true;
@@ -48,7 +48,7 @@
     if (dyn_cast<CXXMethodDecl>(D))
       return true;
     auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
+                                 /*File=*/"test.cpp", Public, "");
     if (I)
       EmittedInfos.emplace_back(std::move(I));
     return true;
@@ -56,7 +56,7 @@
 
   bool VisitCXXMethodDecl(const CXXMethodDecl *D) {
     auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
+                                 /*File=*/"test.cpp", Public, "");
     if (I)
       EmittedInfos.emplace_back(std::move(I));
     return true;
@@ -64,7 +64,7 @@
 
   bool VisitRecordDecl(const RecordDecl *D) {
     auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
+                                 /*File=*/"test.cpp", Public, "");
     if (I)
       EmittedInfos.emplace_back(std::move(I));
     return true;
@@ -72,7 +72,7 @@
 
   bool VisitEnumDecl(const EnumDecl *D) {
     auto I = serialize::emitInfo(D, getComment(D), /*Line=*/0,
-                                 /*File=*/"test.cpp", Public);
+                                 /*File=*/"test.cpp", Public, "");
     if (I)
       EmittedInfos.emplace_back(std::move(I));
     return true;
@@ -142,7 +142,8 @@
   E() {}
 protected:
   void ProtectedMethod();
-};)raw", 3, /*Public=*/false, Infos);
+};)raw",
+                       3, /*Public=*/false, Infos);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, "E");
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
@@ -57,7 +57,8 @@
   <div>
     <h3>OneFunction</h3>
     <p>
-       OneFunction()
+      OneFunction(
+      )
     </p>
   </div>
   <h2>Enums</h2>
@@ -78,9 +79,10 @@
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
 
-  I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
+  I.Members.emplace_back("int", "/path/to", "X", AccessSpecifier::AS_private);
   I.TagType = TagTypeKind::TTK_Class;
-  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record,
+                         llvm::SmallString<128>("/path/to"));
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
@@ -104,11 +106,14 @@
     Defined at line 10 of test.cpp
   </p>
   <p>
-    Inherits from F, G
+    Inherits from 
+    <a href="/path/to/F.html">F</a>
+    , 
+    G
   </p>
   <h2>Members</h2>
   <ul>
-    <li>private int X</li>
+    <li>private <a href="/path/to/int.html">int</a> X</li>
   </ul>
   <h2>Records</h2>
   <ul>
@@ -118,7 +123,8 @@
   <div>
     <h3>OneFunction</h3>
     <p>
-       OneFunction()
+      OneFunction(
+      )
     </p>
   </div>
   <h2>Enums</h2>
@@ -139,8 +145,8 @@
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
 
-  I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
-  I.Params.emplace_back("int", "P");
+  I.ReturnType = TypeInfo(EmptySID, "float", InfoType::IT_default, "/path/to");
+  I.Params.emplace_back("int", "/path/to", "P");
   I.IsMethod = true;
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
 
@@ -156,7 +162,12 @@
 <div>
   <h3>f</h3>
   <p>
-    void f(int P)
+    <a href="/path/to/float.html">float</a>
+     
+    f(
+    <a href="/path/to/int.html">int</a>
+     P
+    )
   </p>
   <p>
     Defined at line 10 of test.cpp
@@ -250,7 +261,15 @@
 <div>
   <h3>f</h3>
   <p>
-    void f(int I, int J)
+    void
+     
+    f(
+    int
+     I
+    , 
+    int
+     J
+    )
   </p>
   <p>
     Defined at line 10 of test.cpp
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
@@ -110,12 +110,13 @@
   return false;
 }
 
-// A function to extract the appropriate path name for a given info's
-// documentation. The path returned is a composite of the parent namespaces as
-// directories plus the decl name as the filename.
+// A function to extract the appropriate file name for a given info's
+// documentation. The path returned is a composite of the direcory and the
+// info's name. The directory should have been constructed in the serialization
+// phase.
 //
-// Example: Given the below, the <ext> path for class C will be <
-// root>/A/B/C.<ext>
+// Example: Given the below, the <ext> path for class C will be
+// <root>/A/B/C.<ext>
 //
 // namespace A {
 // namesapce B {
@@ -125,15 +126,7 @@
 // }
 // }
 llvm::Expected<llvm::SmallString<128>>
-getInfoOutputFile(StringRef Root,
-                  llvm::SmallVectorImpl<doc::Reference> &Namespaces,
-                  StringRef Name, StringRef Ext) {
-  std::error_code OK;
-  llvm::SmallString<128> Path;
-  llvm::sys::path::native(Root, Path);
-  for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
-    llvm::sys::path::append(Path, R->Name);
-
+getInfoOutputFile(llvm::SmallString<128> Path, StringRef Name, StringRef Ext) {
   if (CreateDirectory(Path))
     return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
                                                llvm::inconvertibleErrorCode());
@@ -200,7 +193,7 @@
   // Mapping phase
   llvm::outs() << "Mapping decls...\n";
   clang::doc::ClangDocContext CDCtx = {Exec->get()->getExecutionContext(),
-                                       PublicOnly};
+                                       PublicOnly, OutDirectory};
   auto Err =
       Exec->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster);
   if (Err) {
@@ -227,11 +220,10 @@
 
     doc::Info *I = Reduced.get().get();
 
-    auto InfoPath =
-        getInfoOutputFile(OutDirectory, I->Namespace, I->Name, "." + Format);
+    auto InfoPath = getInfoOutputFile(I->Path, I->Name, "." + Format);
     if (!InfoPath) {
       llvm::errs() << toString(InfoPath.takeError()) << "\n";
-      continue;
+      return 1;
     }
     std::error_code FileErr;
     llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
Index: clang-tools-extra/clang-doc/Serialize.h
===================================================================
--- clang-tools-extra/clang-doc/Serialize.h
+++ clang-tools-extra/clang-doc/Serialize.h
@@ -28,15 +28,20 @@
 namespace serialize {
 
 std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
+                               int LineNumber, StringRef File, bool PublicOnly,
+                               StringRef OutDirectory);
 std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
+                               int LineNumber, StringRef File, bool PublicOnly,
+                               StringRef OutDirectory);
 std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
+                               int LineNumber, StringRef File, bool PublicOnly,
+                               StringRef OutDirectory);
 std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
+                               int LineNumber, StringRef File, bool PublicOnly,
+                               StringRef OutDirectory);
 std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
-                               int LineNumber, StringRef File, bool PublicOnly);
+                               int LineNumber, StringRef File, bool PublicOnly,
+                               StringRef OutDirectory);
 
 // 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
@@ -24,6 +24,41 @@
   return llvm::SHA1::hash(arrayRefFromStringRef(USR));
 }
 
+template <typename T>
+static void
+populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
+                         const T *D);
+
+// A function to extract the appropriate directory name for a given info's
+// documentation. The path returned is a composite of the parent namespaces.
+//
+// Example: Given the below, the diretory path for class C info will be
+// <root>/A/B
+//
+// namespace A {
+// namesapce B {
+//
+// class C {};
+//
+// }
+// }
+llvm::SmallString<128>
+getInfoOutputFile(StringRef Root,
+                  const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
+  std::error_code OK;
+  llvm::SmallString<128> Path;
+  llvm::sys::path::native(Root, Path);
+  for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
+    llvm::sys::path::append(Path, R->Name);
+  return Path;
+}
+
+llvm::SmallString<128> getInfoOutputFile(StringRef Root, const Decl *D) {
+  llvm::SmallVector<Reference, 4> Namespaces;
+  populateParentNamespaces(Namespaces, D);
+  return getInfoOutputFile(Root, Namespaces);
+}
+
 class ClangDocCommentVisitor
     : public ConstCommentVisitor<ClangDocCommentVisitor> {
 public:
@@ -195,7 +230,8 @@
   return false; // otherwise, linkage is some form of internal linkage
 }
 
-static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) {
+static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
+                        StringRef OutDirectory) {
   for (const FieldDecl *F : D->fields()) {
     if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal()))
       continue;
@@ -204,13 +240,15 @@
       // valid, as opposed to an assert.
       if (const auto *N = dyn_cast<EnumDecl>(T)) {
         I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
-                               InfoType::IT_enum, F->getNameAsString(),
-                               N->getAccessUnsafe());
+                               InfoType::IT_enum,
+                               getInfoOutputFile(OutDirectory, N),
+                               F->getNameAsString(), N->getAccessUnsafe());
         continue;
       } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
         I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),
-                               InfoType::IT_record, F->getNameAsString(),
-                               N->getAccessUnsafe());
+                               InfoType::IT_record,
+                               getInfoOutputFile(OutDirectory, N),
+                               F->getNameAsString(), N->getAccessUnsafe());
         continue;
       }
     }
@@ -224,16 +262,20 @@
     I.Members.emplace_back(E->getNameAsString());
 }
 
-static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
+static void parseParameters(FunctionInfo &I, const FunctionDecl *D,
+                            StringRef OutDirectory) {
   for (const ParmVarDecl *P : D->parameters()) {
     if (const auto *T = getDeclForType(P->getOriginalType())) {
       if (const auto *N = dyn_cast<EnumDecl>(T)) {
-        I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_enum, P->getNameAsString());
+
+        I.Params.emplace_back(
+            getUSRForDecl(N), N->getNameAsString(), InfoType::IT_enum,
+            getInfoOutputFile(OutDirectory, N), P->getNameAsString());
         continue;
       } else if (const auto *N = dyn_cast<RecordDecl>(T)) {
-        I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_record, P->getNameAsString());
+        I.Params.emplace_back(
+            getUSRForDecl(N), N->getNameAsString(), InfoType::IT_record,
+            getInfoOutputFile(OutDirectory, N), P->getNameAsString());
         continue;
       }
     }
@@ -242,24 +284,27 @@
   }
 }
 
-static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
+static void parseBases(RecordInfo &I, const CXXRecordDecl *D,
+                       StringRef OutDirectory) {
   // Don't parse bases if this isn't a definition.
   if (!D->isThisDeclarationADefinition())
     return;
   for (const CXXBaseSpecifier &B : D->bases()) {
     if (B.isVirtual())
       continue;
-    if (const auto *P = getDeclForType(B.getType()))
+    if (const auto *P = getDeclForType(B.getType())) {
       I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
-                             InfoType::IT_record);
-    else
+                             InfoType::IT_record,
+                             getInfoOutputFile(OutDirectory, P));
+    } else
       I.Parents.emplace_back(B.getType().getAsString());
   }
   for (const CXXBaseSpecifier &B : D->vbases()) {
-    if (const auto *P = getDeclForType(B.getType()))
+    if (const auto *P = getDeclForType(B.getType())) {
       I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
-                                    InfoType::IT_record);
-    else
+                                    InfoType::IT_record,
+                                    getInfoOutputFile(OutDirectory, P));
+    } else
       I.VirtualParents.emplace_back(B.getType().getAsString());
   }
 }
@@ -308,53 +353,57 @@
 
 static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
                                  const FullComment *FC, int LineNumber,
-                                 StringRef Filename) {
+                                 StringRef Filename, StringRef OutDirectory) {
   populateSymbolInfo(I, D, FC, LineNumber, Filename);
   if (const auto *T = getDeclForType(D->getReturnType())) {
     if (dyn_cast<EnumDecl>(T))
       I.ReturnType =
-          TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);
+          TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum,
+                   getInfoOutputFile(OutDirectory, T));
     else if (dyn_cast<RecordDecl>(T))
       I.ReturnType =
-          TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);
+          TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record,
+                   getInfoOutputFile(OutDirectory, T));
   } else {
     I.ReturnType = TypeInfo(D->getReturnType().getAsString());
   }
-  parseParameters(I, D);
+  parseParameters(I, D, OutDirectory);
 }
 
 std::unique_ptr<Info> emitInfo(const NamespaceDecl *D, const FullComment *FC,
                                int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+                               bool PublicOnly, StringRef OutDirectory) {
   if (PublicOnly && ((D->isAnonymousNamespace()) ||
                      !isPublic(D->getAccess(), D->getLinkageInternal())))
     return nullptr;
   auto I = llvm::make_unique<NamespaceInfo>();
   populateInfo(*I, D, FC);
+  I->Path = getInfoOutputFile(OutDirectory, I->Namespace);
   return std::unique_ptr<Info>{std::move(I)};
 }
 
 std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
                                int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+                               bool PublicOnly, StringRef OutDirectory) {
   if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
     return nullptr;
   auto I = llvm::make_unique<RecordInfo>();
   populateSymbolInfo(*I, D, FC, LineNumber, File);
   I->TagType = D->getTagKind();
-  parseFields(*I, D, PublicOnly);
+  parseFields(*I, D, PublicOnly, OutDirectory);
   if (const auto *C = dyn_cast<CXXRecordDecl>(D))
-    parseBases(*I, C);
+    parseBases(*I, C, OutDirectory);
+  I->Path = getInfoOutputFile(OutDirectory, I->Namespace);
   return std::unique_ptr<Info>{std::move(I)};
 }
 
 std::unique_ptr<Info> emitInfo(const FunctionDecl *D, const FullComment *FC,
                                int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+                               bool PublicOnly, StringRef OutDirectory) {
   if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
     return nullptr;
   FunctionInfo Func;
-  populateFunctionInfo(Func, D, FC, LineNumber, File);
+  populateFunctionInfo(Func, D, FC, LineNumber, File, OutDirectory);
   Func.Access = clang::AccessSpecifier::AS_none;
 
   // Wrap in enclosing scope
@@ -364,16 +413,17 @@
   else
     I->USR = SymbolID();
   I->ChildFunctions.emplace_back(std::move(Func));
+  I->Path = getInfoOutputFile(OutDirectory, I->Namespace);
   return std::unique_ptr<Info>{std::move(I)};
 }
 
 std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
                                int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+                               bool PublicOnly, StringRef OutDirectory) {
   if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
     return nullptr;
   FunctionInfo Func;
-  populateFunctionInfo(Func, D, FC, LineNumber, File);
+  populateFunctionInfo(Func, D, FC, LineNumber, File, OutDirectory);
   Func.IsMethod = true;
 
   SymbolID ParentUSR = getUSRForDecl(D->getParent());
@@ -385,12 +435,13 @@
   auto I = llvm::make_unique<RecordInfo>();
   I->USR = ParentUSR;
   I->ChildFunctions.emplace_back(std::move(Func));
+  I->Path = getInfoOutputFile(OutDirectory, I->Namespace);
   return std::unique_ptr<Info>{std::move(I)};
 }
 
 std::unique_ptr<Info> emitInfo(const EnumDecl *D, const FullComment *FC,
                                int LineNumber, llvm::StringRef File,
-                               bool PublicOnly) {
+                               bool PublicOnly, StringRef OutDirectory) {
   if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal()))
     return nullptr;
   EnumInfo Enum;
@@ -422,6 +473,7 @@
   auto I = llvm::make_unique<NamespaceInfo>();
   I->USR = SymbolID();
   I->ChildEnums.emplace_back(std::move(Enum));
+  I->Path = getInfoOutputFile(OutDirectory, I->Namespace);
   return std::unique_ptr<Info>{std::move(I)};
 }
 
Index: clang-tools-extra/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/clang-doc/Representation.h
+++ clang-tools-extra/clang-doc/Representation.h
@@ -74,8 +74,11 @@
 struct Reference {
   Reference() = default;
   Reference(llvm::StringRef Name) : Name(Name) {}
+  Reference(llvm::StringRef Name, StringRef Path) : Name(Name), Path(Path) {}
   Reference(SymbolID USR, StringRef Name, InfoType IT)
       : USR(USR), Name(Name), RefType(IT) {}
+  Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
+      : USR(USR), Name(Name), RefType(IT), Path(Path) {}
 
   bool operator==(const Reference &Other) const {
     return std::tie(USR, Name, RefType) ==
@@ -87,6 +90,8 @@
   InfoType RefType = InfoType::IT_default; // Indicates the type of this
                                            // Reference (namespace, record,
                                            // function, enum, default).
+  llvm::SmallString<128> Path; // Path of directory where the clang-doc
+                               // generated file will be saved
 };
 
 // A base struct for TypeInfos
@@ -94,7 +99,10 @@
   TypeInfo() = default;
   TypeInfo(SymbolID Type, StringRef Field, InfoType IT)
       : Type(Type, Field, IT) {}
+  TypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path)
+      : Type(Type, Field, IT, Path) {}
   TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
+  TypeInfo(llvm::StringRef RefName, StringRef Path) : Type(RefName, Path) {}
 
   bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
 
@@ -104,11 +112,13 @@
 // Info for field types.
 struct FieldTypeInfo : public TypeInfo {
   FieldTypeInfo() = default;
-  FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
+  FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
                 llvm::StringRef Name)
-      : TypeInfo(Type, Field, IT), Name(Name) {}
+      : TypeInfo(Type, Field, IT, Path), Name(Name) {}
   FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
       : TypeInfo(RefName), Name(Name) {}
+  FieldTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name)
+      : TypeInfo(RefName, Path), Name(Name) {}
 
   bool operator==(const FieldTypeInfo &Other) const {
     return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);
@@ -120,12 +130,15 @@
 // Info for member types.
 struct MemberTypeInfo : public FieldTypeInfo {
   MemberTypeInfo() = default;
-  MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT,
+  MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,
                  llvm::StringRef Name, AccessSpecifier Access)
-      : FieldTypeInfo(Type, Field, IT, Name), Access(Access) {}
+      : FieldTypeInfo(Type, Field, IT, Path, Name), Access(Access) {}
   MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name,
                  AccessSpecifier Access)
       : FieldTypeInfo(RefName, Name), Access(Access) {}
+  MemberTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name,
+                 AccessSpecifier Access)
+      : FieldTypeInfo(RefName, Path, Name), Access(Access) {}
 
   bool operator==(const MemberTypeInfo &Other) const {
     return std::tie(Type, Name, Access) ==
@@ -171,6 +184,8 @@
   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 directory where the clang-doc
+                                        // generated file will be saved
 
   void mergeBase(Info &&I);
   bool mergeable(const Info &Other);
@@ -282,6 +297,7 @@
 struct ClangDocContext {
   tooling::ExecutionContext *ECtx;
   bool PublicOnly;
+  std::string OutDirectory;
 };
 
 } // namespace doc
Index: clang-tools-extra/clang-doc/Representation.cpp
===================================================================
--- clang-tools-extra/clang-doc/Representation.cpp
+++ clang-tools-extra/clang-doc/Representation.cpp
@@ -117,6 +117,8 @@
     USR = Other.USR;
   if (Name == "")
     Name = Other.Name;
+  if (Path == "")
+    Path = Other.Path;
   if (Namespace.empty())
     Namespace = std::move(Other.Namespace);
   // Unconditionally extend the description, since each decl may have a comment.
Index: clang-tools-extra/clang-doc/Mapper.cpp
===================================================================
--- clang-tools-extra/clang-doc/Mapper.cpp
+++ clang-tools-extra/clang-doc/Mapper.cpp
@@ -39,13 +39,13 @@
 
   auto I = serialize::emitInfo(
       D, getComment(D, D->getASTContext()), getLine(D, D->getASTContext()),
-      getFile(D, D->getASTContext()), CDCtx.PublicOnly);
+      getFile(D, D->getASTContext()), CDCtx.PublicOnly, CDCtx.OutDirectory);
 
   // 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).
   if (I)
     CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(I->USR)),
-                       serialize::serialize(I));
+                             serialize::serialize(I));
   return true;
 }
 
Index: clang-tools-extra/clang-doc/MDGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/MDGenerator.cpp
+++ clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -20,14 +20,30 @@
 
 // Markdown generation
 
-static std::string genItalic(const Twine &Text) { return "*" + Text.str() + "*"; }
+static std::string genItalic(const Twine &Text) {
+  return "*" + Text.str() + "*";
+}
 
-static std::string genEmphasis(const Twine &Text) { return "**" + Text.str() + "**"; }
+static std::string genEmphasis(const Twine &Text) {
+  return "**" + Text.str() + "**";
+}
 
 static std::string genLink(const Twine &Text, const Twine &Link) {
   return "[" + Text.str() + "](" + Link.str() + ")";
 }
 
+static std::string
+genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
+  std::string Buffer;
+  llvm::raw_string_ostream Stream(Buffer);
+  for (const auto &R : Refs) {
+    if (&R != Refs.begin())
+      Stream << ", ";
+    Stream << R.Name;
+  }
+  return Stream.str();
+}
+
 static void writeLine(const Twine &Text, raw_ostream &OS) {
   OS << Text << "\n\n";
 }
Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -33,6 +33,7 @@
     TAG_P,
     TAG_UL,
     TAG_LI,
+    TAG_A,
   };
 
   HTMLTag() = default;
@@ -58,8 +59,8 @@
 };
 
 struct TextNode : public HTMLNode {
-  TextNode(llvm::StringRef Text, bool Indented)
-      : Text(Text), Indented(Indented) {}
+  TextNode(const Twine &Text, bool Indented = true)
+      : Text(Text.str()), Indented(Indented) {}
 
   std::string Text; // Content of node
   bool Indented; // Indicates if an indentation must be rendered before the text
@@ -114,6 +115,7 @@
   case HTMLTag::TAG_P:
   case HTMLTag::TAG_UL:
   case HTMLTag::TAG_LI:
+  case HTMLTag::TAG_A:
     return false;
   }
 }
@@ -126,6 +128,7 @@
   case HTMLTag::TAG_H2:
   case HTMLTag::TAG_H3:
   case HTMLTag::TAG_LI:
+  case HTMLTag::TAG_A:
     return true;
   case HTMLTag::TAG_DIV:
   case HTMLTag::TAG_P:
@@ -154,6 +157,8 @@
     return llvm::SmallString<16>("ul");
   case HTMLTag::TAG_LI:
     return llvm::SmallString<16>("li");
+  case HTMLTag::TAG_A:
+    return llvm::SmallString<16>("a");
   }
 }
 
@@ -188,6 +193,31 @@
 
 // HTML generation
 
+static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) {
+  auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_A, Text);
+  LinkNode->Attributes.try_emplace("href", Link.str());
+  return LinkNode;
+}
+
+static std::unique_ptr<HTMLNode> genTypeReference(const Reference &Type) {
+  if (Type.Path.empty())
+    return llvm::make_unique<TextNode>(Type.Name);
+  llvm::SmallString<128> Path = Type.Path;
+  ::llvm::sys::path::append(Path, Type.Name + ".html");
+  return genLink(Type.Name, Path);
+}
+
+static std::vector<std::unique_ptr<HTMLNode>>
+genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
+  std::vector<std::unique_ptr<HTMLNode>> Out;
+  for (const auto &R : Refs) {
+    if (&R != Refs.begin())
+      Out.emplace_back(llvm::make_unique<TextNode>(", "));
+    Out.emplace_back(genTypeReference(R));
+  }
+  return Out;
+}
+
 static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);
 static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I);
 
@@ -249,8 +279,11 @@
     std::string Access = getAccess(M.Access);
     if (Access != "")
       Access = Access + " ";
-    ULBody->Children.emplace_back(llvm::make_unique<TagNode>(
-        HTMLTag::TAG_LI, Access + M.Type.Name + " " + M.Name));
+    auto LIBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI);
+    LIBody->Children.emplace_back(llvm::make_unique<TextNode>(Access));
+    LIBody->Children.emplace_back(genTypeReference(M.Type));
+    LIBody->Children.emplace_back(llvm::make_unique<TextNode>(" " + M.Name));
+    ULBody->Children.emplace_back(std::move(LIBody));
   }
   return Out;
 }
@@ -343,21 +376,28 @@
   std::vector<std::unique_ptr<TagNode>> Out;
   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
 
-  std::string Buffer;
-  llvm::raw_string_ostream Stream(Buffer);
-  for (const auto &P : I.Params) {
-    if (&P != I.Params.begin())
-      Stream << ", ";
-    Stream << P.Type.Name + " " + P.Name;
-  }
+  Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
+  auto &FunctionHeader = Out.back();
 
   std::string Access = getAccess(I.Access);
   if (Access != "")
-    Access = Access + " ";
+    FunctionHeader->Children.emplace_back(
+        llvm::make_unique<TextNode>(Access + " "));
+  if (I.ReturnType.Type.Name != "") {
+    FunctionHeader->Children.emplace_back(genTypeReference(I.ReturnType.Type));
+    FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(" "));
+  }
+  FunctionHeader->Children.emplace_back(
+      llvm::make_unique<TextNode>(I.Name + "("));
 
-  Out.emplace_back(llvm::make_unique<TagNode>(
-      HTMLTag::TAG_P, Access + I.ReturnType.Type.Name + " " + I.Name + "(" +
-                          Stream.str() + ")"));
+  for (const auto &P : I.Params) {
+    if (&P != I.Params.begin())
+      FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(", "));
+    FunctionHeader->Children.emplace_back(genTypeReference(P.Type));
+    FunctionHeader->Children.emplace_back(
+        llvm::make_unique<TextNode>(" " + P.Name));
+  }
+  FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")"));
 
   if (I.DefLoc)
     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
@@ -415,18 +455,26 @@
   if (!I.Description.empty())
     Out.emplace_back(genHTML(I.Description));
 
-  std::string Parents = genReferenceList(I.Parents);
-  std::string VParents = genReferenceList(I.VirtualParents);
+  Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
+  auto &PBody = Out.back();
+  PBody->Children.emplace_back(llvm::make_unique<TextNode>("Inherits from "));
+  std::vector<std::unique_ptr<HTMLNode>> Parents = genReferenceList(I.Parents);
+  std::vector<std::unique_ptr<HTMLNode>> VParents =
+      genReferenceList(I.VirtualParents);
   if (!Parents.empty() || !VParents.empty()) {
     if (Parents.empty())
-      Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P,
-                                                  "Inherits from " + VParents));
+      std::move(VParents.begin(), VParents.end(),
+                std::back_inserter(PBody->Children));
     else if (VParents.empty())
-      Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P,
-                                                  "Inherits from " + Parents));
-    else
-      Out.emplace_back(llvm::make_unique<TagNode>(
-          HTMLTag::TAG_P, "Inherits from " + Parents + ", " + VParents));
+      std::move(Parents.begin(), Parents.end(),
+                std::back_inserter(PBody->Children));
+    else {
+      std::move(Parents.begin(), Parents.end(),
+                std::back_inserter(PBody->Children));
+      PBody->Children.emplace_back(llvm::make_unique<TextNode>(", "));
+      std::move(VParents.begin(), VParents.end(),
+                std::back_inserter(PBody->Children));
+    }
   }
 
   std::vector<std::unique_ptr<TagNode>> Members =
Index: clang-tools-extra/clang-doc/Generators.h
===================================================================
--- clang-tools-extra/clang-doc/Generators.h
+++ clang-tools-extra/clang-doc/Generators.h
@@ -38,8 +38,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");
 }
 
-// Generates a comma-separated list of Refs
-// Used to display the parents of a record
-std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
-  std::string Buffer;
-  llvm::raw_string_ostream Stream(Buffer);
-  for (const auto &R : Refs) {
-    if (&R != Refs.begin())
-      Stream << ", ";
-    Stream << R.Name;
-  }
-  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;
Index: clang-tools-extra/clang-doc/BitcodeWriter.h
===================================================================
--- clang-tools-extra/clang-doc/BitcodeWriter.h
+++ clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -91,6 +91,7 @@
   MEMBER_TYPE_ACCESS,
   NAMESPACE_USR,
   NAMESPACE_NAME,
+  NAMESPACE_PATH,
   ENUM_USR,
   ENUM_NAME,
   ENUM_DEFLOCATION,
@@ -99,12 +100,14 @@
   ENUM_SCOPED,
   RECORD_USR,
   RECORD_NAME,
+  RECORD_PATH,
   RECORD_DEFLOCATION,
   RECORD_LOCATION,
   RECORD_TAG_TYPE,
   REFERENCE_USR,
   REFERENCE_NAME,
   REFERENCE_TYPE,
+  REFERENCE_PATH,
   REFERENCE_FIELD,
   RI_LAST,
   RI_FIRST = VERSION
Index: clang-tools-extra/clang-doc/BitcodeWriter.cpp
===================================================================
--- clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -148,6 +148,7 @@
           {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
           {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
           {NAMESPACE_NAME, {"Name", &StringAbbrev}},
+          {NAMESPACE_PATH, {"Path", &StringAbbrev}},
           {ENUM_USR, {"USR", &SymbolIDAbbrev}},
           {ENUM_NAME, {"Name", &StringAbbrev}},
           {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
@@ -156,6 +157,7 @@
           {ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
           {RECORD_USR, {"USR", &SymbolIDAbbrev}},
           {RECORD_NAME, {"Name", &StringAbbrev}},
+          {RECORD_PATH, {"Path", &StringAbbrev}},
           {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
           {RECORD_LOCATION, {"Location", &LocationAbbrev}},
           {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
@@ -168,6 +170,7 @@
           {REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
           {REFERENCE_NAME, {"Name", &StringAbbrev}},
           {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
+          {REFERENCE_PATH, {"Path", &StringAbbrev}},
           {REFERENCE_FIELD, {"Field", &IntAbbrev}}};
       assert(Inits.size() == RecordIdCount);
       for (const auto &Init : Inits) {
@@ -198,18 +201,20 @@
          {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER,
           ENUM_SCOPED}},
         // Namespace Block
-        {BI_NAMESPACE_BLOCK_ID, {NAMESPACE_USR, NAMESPACE_NAME}},
+        {BI_NAMESPACE_BLOCK_ID,
+         {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
         // Record Block
         {BI_RECORD_BLOCK_ID,
-         {RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION,
-          RECORD_TAG_TYPE}},
+         {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
+          RECORD_LOCATION, RECORD_TAG_TYPE}},
         // Function Block
         {BI_FUNCTION_BLOCK_ID,
          {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,
           FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
         // Reference Block
         {BI_REFERENCE_BLOCK_ID,
-         {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_FIELD}}};
+         {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH,
+          REFERENCE_FIELD}}};
 
 // AbbreviationMap
 
@@ -380,6 +385,7 @@
   emitRecord(R.USR, REFERENCE_USR);
   emitRecord(R.Name, REFERENCE_NAME);
   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
+  emitRecord(R.Path, REFERENCE_PATH);
   emitRecord((unsigned)Field, REFERENCE_FIELD);
 }
 
@@ -427,6 +433,7 @@
   StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
   emitRecord(I.USR, NAMESPACE_USR);
   emitRecord(I.Name, NAMESPACE_NAME);
+  emitRecord(I.Path, NAMESPACE_PATH);
   for (const auto &N : I.Namespace)
     emitBlock(N, FieldId::F_namespace);
   for (const auto &CI : I.Description)
@@ -462,6 +469,7 @@
   StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
   emitRecord(I.USR, RECORD_USR);
   emitRecord(I.Name, RECORD_NAME);
+  emitRecord(I.Path, RECORD_PATH);
   for (const auto &N : I.Namespace)
     emitBlock(N, FieldId::F_namespace);
   for (const auto &CI : I.Description)
Index: clang-tools-extra/clang-doc/BitcodeReader.cpp
===================================================================
--- clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -148,6 +148,8 @@
     return decodeRecord(R, I->USR, Blob);
   case NAMESPACE_NAME:
     return decodeRecord(R, I->Name, Blob);
+  case NAMESPACE_PATH:
+    return decodeRecord(R, I->Path, Blob);
   default:
     return llvm::make_error<llvm::StringError>(
         "Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode());
@@ -161,6 +163,8 @@
     return decodeRecord(R, I->USR, Blob);
   case RECORD_NAME:
     return decodeRecord(R, I->Name, Blob);
+  case RECORD_PATH:
+    return decodeRecord(R, I->Path, Blob);
   case RECORD_DEFLOCATION:
     return decodeRecord(R, I->DefLoc, Blob);
   case RECORD_LOCATION:
@@ -284,6 +288,8 @@
     return decodeRecord(R, I->Name, Blob);
   case REFERENCE_TYPE:
     return decodeRecord(R, I->RefType, Blob);
+  case REFERENCE_PATH:
+    return decodeRecord(R, I->Path, Blob);
   case REFERENCE_FIELD:
     return decodeRecord(R, F, Blob);
   default:
@@ -656,7 +662,7 @@
   std::unique_ptr<Info> I = llvm::make_unique<T>();
   if (auto Err = readBlock(ID, static_cast<T *>(I.get())))
     return std::move(Err);
-  return std::unique_ptr<Info>{std::move(I)};;
+  return std::unique_ptr<Info>{std::move(I)};
 }
 
 llvm::Expected<std::unique_ptr<Info>>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to