This revision was automatically updated to reflect the committed changes.
Closed by commit rL368602: [clang-doc] Generate HTML links for children 
namespaces/records (authored by DiegoAstiazaran, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D65987?vs=214444&id=214677#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D65987

Files:
  clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
  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/unittests/clang-doc/HTMLGeneratorTest.cpp
  clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp
  clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
  clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp

Index: clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -39,8 +39,9 @@
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
-                                 InfoType::IT_namespace);
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+                                 InfoType::IT_namespace, "Namespace");
+  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                              "Namespace");
   I.ChildFunctions.emplace_back();
   I.ChildFunctions.back().Name = "OneFunction";
   I.ChildEnums.emplace_back();
@@ -100,11 +101,15 @@
   <h1>namespace Namespace</h1>
   <h2 id="Namespaces">Namespaces</h2>
   <ul>
-    <li>ChildNamespace</li>
+    <li>
+      <a href="Namespace/ChildNamespace.html">ChildNamespace</a>
+    </li>
   </ul>
   <h2 id="Records">Records</h2>
   <ul>
-    <li>ChildStruct</li>
+    <li>
+      <a href="Namespace/ChildStruct.html">ChildStruct</a>
+    </li>
   </ul>
   <h2 id="Functions">Functions</h2>
   <div>
@@ -137,7 +142,8 @@
   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, PathTo);
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                              "X/Y/Z/r");
   I.ChildFunctions.emplace_back();
   I.ChildFunctions.back().Name = "OneFunction";
   I.ChildEnums.emplace_back();
@@ -215,7 +221,9 @@
   </ul>
   <h2 id="Records">Records</h2>
   <ul>
-    <li>ChildStruct</li>
+    <li>
+      <a href="r/ChildStruct.html">ChildStruct</a>
+    </li>
   </ul>
   <h2 id="Functions">Functions</h2>
   <div>
Index: clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -29,8 +29,9 @@
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
-                                 InfoType::IT_namespace);
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+                                 InfoType::IT_namespace, "path/to/A/Namespace");
+  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                              "path/to/A/Namespace");
   I.ChildFunctions.emplace_back();
   I.ChildFunctions.back().Name = "OneFunction";
   I.ChildEnums.emplace_back();
@@ -53,9 +54,11 @@
 ChildNamespaces:
   - Type:            Namespace
     Name:            'ChildNamespace'
+    Path:            'path/to/A/Namespace'
 ChildRecords:
   - Type:            Record
     Name:            'ChildStruct'
+    Path:            'path/to/A/Namespace'
 ChildFunctions:
   - USR:             '0000000000000000000000000000000000000000'
     Name:            'OneFunction'
@@ -71,7 +74,7 @@
 TEST(YAMLGeneratorTest, emitRecordYAML) {
   RecordInfo I;
   I.Name = "r";
-  I.Path = "path/to/r";
+  I.Path = "path/to/A";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
@@ -85,7 +88,8 @@
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
                                 "path/to/G");
 
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                              "path/to/A/r");
   I.ChildFunctions.emplace_back();
   I.ChildFunctions.back().Name = "OneFunction";
   I.ChildEnums.emplace_back();
@@ -101,7 +105,7 @@
       R"raw(---
 USR:             '0000000000000000000000000000000000000000'
 Name:            'r'
-Path:            'path/to/r'
+Path:            'path/to/A'
 Namespace:
   - Type:            Namespace
     Name:            'A'
@@ -129,6 +133,7 @@
 ChildRecords:
   - Type:            Record
     Name:            'ChildStruct'
+    Path:            'path/to/A/r'
 ChildFunctions:
   - USR:             '0000000000000000000000000000000000000000'
     Name:            'OneFunction'
Index: clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
===================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
+++ clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp
@@ -407,12 +407,14 @@
 
   RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
   RecordInfo ExpectedParentB(EmptySID);
-  ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record);
+  ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record,
+                                            "A");
   CheckRecordInfo(&ExpectedParentB, ParentB);
 
   NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
   NamespaceInfo ExpectedParentC(EmptySID);
-  ExpectedParentC.ChildRecords.emplace_back(EmptySID, "C", InfoType::IT_record);
+  ExpectedParentC.ChildRecords.emplace_back(EmptySID, "C", InfoType::IT_record,
+                                            "@nonymous_namespace");
   CheckNamespaceInfo(&ExpectedParentC, ParentC);
 }
 
@@ -431,7 +433,7 @@
   NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
   NamespaceInfo ExpectedParentB(EmptySID);
   ExpectedParentB.ChildNamespaces.emplace_back(EmptySID, "B",
-                                               InfoType::IT_namespace);
+                                               InfoType::IT_namespace, "A");
   CheckNamespaceInfo(&ExpectedParentB, ParentB);
 }
 
Index: clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp
===================================================================
--- clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp
+++ clang-tools-extra/trunk/unittests/clang-doc/MergeTest.cpp
@@ -87,7 +87,7 @@
   One.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
   One.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
-  One.ChildRecords.emplace_back(NonEmptySID, "ChildStruct",
+  One.ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
                                 InfoType::IT_record);
   One.ChildFunctions.emplace_back();
   One.ChildFunctions.back().Name = "OneFunction";
@@ -104,8 +104,8 @@
 
   Two.TagType = TagTypeKind::TTK_Class;
 
-  Two.ChildRecords.emplace_back(EmptySID, "OtherChildStruct",
-                                InfoType::IT_record);
+  Two.ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
+                                InfoType::IT_record, "path");
   Two.ChildFunctions.emplace_back();
   Two.ChildFunctions.back().Name = "TwoFunction";
   Two.ChildEnums.emplace_back();
@@ -127,10 +127,8 @@
   Expected->Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
   Expected->VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
-  Expected->ChildRecords.emplace_back(NonEmptySID, "ChildStruct",
-                                      InfoType::IT_record);
-  Expected->ChildRecords.emplace_back(EmptySID, "OtherChildStruct",
-                                      InfoType::IT_record);
+  Expected->ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
+                                      InfoType::IT_record, "path");
   Expected->ChildFunctions.emplace_back();
   Expected->ChildFunctions.back().Name = "OneFunction";
   Expected->ChildFunctions.back().USR = NonEmptySID;
Index: clang-tools-extra/trunk/clang-doc/Serialize.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/Serialize.cpp
+++ clang-tools-extra/trunk/clang-doc/Serialize.cpp
@@ -394,8 +394,8 @@
 
   auto ParentI = llvm::make_unique<NamespaceInfo>();
   ParentI->USR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
-  ParentI->ChildNamespaces.emplace_back(I->USR, I->Name,
-                                        InfoType::IT_namespace);
+  ParentI->ChildNamespaces.emplace_back(I->USR, I->Name, InfoType::IT_namespace,
+                                        getInfoRelativePath(I->Namespace));
   if (I->Namespace.empty())
     ParentI->Path = getInfoRelativePath(ParentI->Namespace);
   return {std::unique_ptr<Info>{std::move(I)},
@@ -427,7 +427,8 @@
   if (I->Namespace.empty()) {
     auto ParentI = llvm::make_unique<NamespaceInfo>();
     ParentI->USR = SymbolID();
-    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record,
+                                       getInfoRelativePath(I->Namespace));
     ParentI->Path = getInfoRelativePath(ParentI->Namespace);
     return {std::unique_ptr<Info>{std::move(I)},
             std::unique_ptr<Info>{std::move(ParentI)}};
@@ -437,14 +438,16 @@
   case InfoType::IT_namespace: {
     auto ParentI = llvm::make_unique<NamespaceInfo>();
     ParentI->USR = I->Namespace[0].USR;
-    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record,
+                                       getInfoRelativePath(I->Namespace));
     return {std::unique_ptr<Info>{std::move(I)},
             std::unique_ptr<Info>{std::move(ParentI)}};
   }
   case InfoType::IT_record: {
     auto ParentI = llvm::make_unique<RecordInfo>();
     ParentI->USR = I->Namespace[0].USR;
-    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);
+    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record,
+                                       getInfoRelativePath(I->Namespace));
     return {std::unique_ptr<Info>{std::move(I)},
             std::unique_ptr<Info>{std::move(ParentI)}};
   }
Index: clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
+++ clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp
@@ -207,26 +207,44 @@
   std::move(New.begin(), New.end(), std::back_inserter(Original));
 }
 
-// Compute the relative path that names the file path relative to the given
-// directory.
-static SmallString<128> computeRelativePath(StringRef FilePath,
-                                            StringRef Directory) {
-  StringRef Path = FilePath;
-  while (!Path.empty()) {
-    if (Directory == Path)
-      return FilePath.substr(Path.size());
-    Path = llvm::sys::path::parent_path(Path);
-  }
+// Compute the relative path from an Origin directory to a Destination directory
+static SmallString<128> computeRelativePath(StringRef Destination,
+                                            StringRef Origin) {
+  // If Origin is empty, the relative path to the Destination is its complete
+  // path.
+  if (Origin.empty())
+    return Destination;
 
-  StringRef Dir = Directory;
-  SmallString<128> Result;
-  while (!Dir.empty()) {
-    if (Dir == FilePath)
-      break;
-    Dir = llvm::sys::path::parent_path(Dir);
+  // The relative path is an empty path if both directories are the same.
+  if (Destination == Origin)
+    return {};
+
+  // These iterators iterate through each of their parent directories
+  llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
+  llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
+  llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
+  llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
+  // Advance both iterators until the paths differ. Example:
+  //    Destination = A/B/C/D
+  //    Origin      = A/B/E/F
+  // FileI will point to C and DirI to E. The directories behind them is the
+  // directory they share (A/B).
+  while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
+    ++FileI;
+    ++DirI;
+  }
+  SmallString<128> Result; // This will hold the resulting path.
+  // Result has to go up one directory for each of the remaining directories in
+  // Origin
+  while (DirI != DirE) {
     llvm::sys::path::append(Result, "..");
+    ++DirI;
+  }
+  // Result has to append each of the remaining directories in Destination
+  while (FileI != FileE) {
+    llvm::sys::path::append(Result, *FileI);
+    ++FileI;
   }
-  llvm::sys::path::append(Result, FilePath.substr(Dir.size()));
   return Result;
 }
 
@@ -271,8 +289,8 @@
 }
 
 static std::unique_ptr<HTMLNode>
-genTypeReference(const Reference &Type, StringRef CurrentDirectory,
-                 llvm::Optional<StringRef> JumpToSection = None) {
+genReference(const Reference &Type, StringRef CurrentDirectory,
+             llvm::Optional<StringRef> JumpToSection = None) {
   if (Type.Path.empty() && !Type.IsInGlobalNamespace) {
     if (!JumpToSection)
       return llvm::make_unique<TextNode>(Type.Name);
@@ -296,7 +314,7 @@
   for (const auto &R : Refs) {
     if (&R != Refs.begin())
       Out.emplace_back(llvm::make_unique<TextNode>(", "));
-    Out.emplace_back(genTypeReference(R, CurrentDirectory));
+    Out.emplace_back(genReference(R, CurrentDirectory));
   }
   return Out;
 }
@@ -372,7 +390,7 @@
       Access = Access + " ";
     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, ParentInfoDir));
+    LIBody->Children.emplace_back(genReference(M.Type, ParentInfoDir));
     LIBody->Children.emplace_back(llvm::make_unique<TextNode>(" " + M.Name));
     ULBody->Children.emplace_back(std::move(LIBody));
   }
@@ -381,7 +399,7 @@
 
 static std::vector<std::unique_ptr<TagNode>>
 genReferencesBlock(const std::vector<Reference> &References,
-                   llvm::StringRef Title) {
+                   llvm::StringRef Title, StringRef ParentPath) {
   if (References.empty())
     return {};
 
@@ -390,9 +408,11 @@
   Out.back()->Attributes.try_emplace("id", Title);
   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL));
   auto &ULBody = Out.back();
-  for (const auto &R : References)
-    ULBody->Children.emplace_back(
-        llvm::make_unique<TagNode>(HTMLTag::TAG_LI, R.Name));
+  for (const auto &R : References) {
+    auto LiNode = llvm::make_unique<TagNode>(HTMLTag::TAG_LI);
+    LiNode->Children.emplace_back(genReference(R, ParentPath));
+    ULBody->Children.emplace_back(std::move(LiNode));
+  }
   return Out;
 }
 
@@ -461,9 +481,9 @@
     Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_SPAN));
     auto &SpanBody = Out.back();
     if (!Index.JumpToSection)
-      SpanBody->Children.emplace_back(genTypeReference(Index, InfoPath));
+      SpanBody->Children.emplace_back(genReference(Index, InfoPath));
     else
-      SpanBody->Children.emplace_back(genTypeReference(
+      SpanBody->Children.emplace_back(genReference(
           Index, InfoPath, StringRef{Index.JumpToSection.getValue()}));
   }
   if (Index.Children.empty())
@@ -567,7 +587,7 @@
         llvm::make_unique<TextNode>(Access + " "));
   if (I.ReturnType.Type.Name != "") {
     FunctionHeader->Children.emplace_back(
-        genTypeReference(I.ReturnType.Type, ParentInfoDir));
+        genReference(I.ReturnType.Type, ParentInfoDir));
     FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(" "));
   }
   FunctionHeader->Children.emplace_back(
@@ -576,8 +596,7 @@
   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, ParentInfoDir));
+    FunctionHeader->Children.emplace_back(genReference(P.Type, ParentInfoDir));
     FunctionHeader->Children.emplace_back(
         llvm::make_unique<TextNode>(" " + P.Name));
   }
@@ -614,10 +633,10 @@
     Out.emplace_back(genHTML(I.Description));
 
   std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
-      genReferencesBlock(I.ChildNamespaces, "Namespaces");
+      genReferencesBlock(I.ChildNamespaces, "Namespaces", I.Path);
   AppendVector(std::move(ChildNamespaces), Out);
   std::vector<std::unique_ptr<TagNode>> ChildRecords =
-      genReferencesBlock(I.ChildRecords, "Records");
+      genReferencesBlock(I.ChildRecords, "Records", I.Path);
   AppendVector(std::move(ChildRecords), Out);
 
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
@@ -682,7 +701,7 @@
       genRecordMembersBlock(I.Members, I.Path);
   AppendVector(std::move(Members), Out);
   std::vector<std::unique_ptr<TagNode>> ChildRecords =
-      genReferencesBlock(I.ChildRecords, "Records");
+      genReferencesBlock(I.ChildRecords, "Records", I.Path);
   AppendVector(std::move(ChildRecords), Out);
 
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
Index: clang-tools-extra/trunk/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.h
+++ clang-tools-extra/trunk/clang-doc/Representation.h
@@ -131,6 +131,9 @@
            std::tie(Other.USR, Other.Name, Other.RefType);
   }
 
+  bool mergeable(const Reference &Other);
+  void merge(Reference &&I);
+
   SymbolID USR = SymbolID(); // Unique identifer for referenced decl
   SmallString<16> Name;      // Name of type (possibly unresolved).
   InfoType RefType = InfoType::IT_default; // Indicates the type of this
Index: clang-tools-extra/trunk/clang-doc/Representation.cpp
===================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.cpp
+++ clang-tools-extra/trunk/clang-doc/Representation.cpp
@@ -54,13 +54,15 @@
   return -1;
 }
 
-// For References, we don't need to actually merge them, we just don't want
-// duplicates.
 void reduceChildren(std::vector<Reference> &Children,
                     std::vector<Reference> &&ChildrenToMerge) {
   for (auto &ChildToMerge : ChildrenToMerge) {
-    if (getChildIndexIfExists(Children, ChildToMerge) == -1)
+    int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
+    if (mergeIdx == -1) {
       Children.push_back(std::move(ChildToMerge));
+      continue;
+    }
+    Children[mergeIdx].merge(std::move(ChildToMerge));
   }
 }
 
@@ -112,6 +114,20 @@
   }
 }
 
+bool Reference::mergeable(const Reference &Other) {
+  return RefType == Other.RefType && USR == Other.USR;
+}
+
+void Reference::merge(Reference &&Other) {
+  assert(mergeable(Other));
+  if (Name.empty())
+    Name = Other.Name;
+  if (Path.empty())
+    Path = Other.Path;
+  if (!IsInGlobalNamespace)
+    IsInGlobalNamespace = Other.IsInGlobalNamespace;
+}
+
 void Info::mergeBase(Info &&Other) {
   assert(mergeable(Other));
   if (USR == EmptySID)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to