<div dir="ltr">Hi Douglas,<div><br></div><div>This revision (<a href="https://reviews.llvm.org/D64669">https://reviews.llvm.org/D64669</a>) should fix that.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jul 12, 2019 at 1:55 PM <<a href="mailto:douglas.yung@sony.com">douglas.yung@sony.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Diego and Julie,<br>
<br>
The tests you modified, emitFunctionHTML and emitRecordHTML are failing when run on Windows due to path separator differences.<br>
<br>
<a href="http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/26925" rel="noreferrer" target="_blank">http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/26925</a><br>
<br>
FAIL: Extra Tools Unit Tests :: clang-doc/./ClangDocTests.exe/HTMLGeneratorTest.emitFunctionHTML (20152 of 51140)<br>
******************** TEST 'Extra Tools Unit Tests :: clang-doc/./ClangDocTests.exe/HTMLGeneratorTest.emitFunctionHTML' FAILED ********************<br>
Note: Google Test filter = HTMLGeneratorTest.emitFunctionHTML<br>
<br>
[==========] Running 1 test from 1 test case.<br>
<br>
[----------] Global test environment set-up.<br>
<br>
[----------] 1 test from HTMLGeneratorTest<br>
<br>
[ RUN      ] HTMLGeneratorTest.emitFunctionHTML<br>
<br>
C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\tools\clang\tools\extra\unittests\clang-doc\HTMLGeneratorTest.cpp(174): error:       Expected: Expected<br>
<br>
      Which is: "<!DOCTYPE html>\n<meta charset=\"utf-8\"/>\n<title></title>\n<div>\n  <h3>f</h3>\n  <p>\n    <a href=\"path/to/float.html\">float</a>\n     f(\n    <a href=\"path/to/int.html\">int</a>\n     P)\n  </p>\n  <p>\n    Defined at line 10 of test.cpp\n  </p>\n</div>\n"<br>
<br>
To be equal to: Actual.str()<br>
<br>
      Which is: "<!DOCTYPE html>\n<meta charset=\"utf-8\"/>\n<title></title>\n<div>\n  <h3>f</h3>\n  <p>\n    <a href=\"path/to\\float.html\">float</a>\n     f(\n    <a href=\"path/to\\int.html\">int</a>\n     P)\n  </p>\n  <p>\n    Defined at line 10 of test.cpp\n  </p>\n</div>\n"<br>
<br>
With diff:<br>
<br>
@@ -5,7 +5,7 @@<br>
<br>
   <h3>f</h3><br>
<br>
   <p><br>
<br>
-    <a href=\"path/to/float.html\">float</a><br>
<br>
+    <a href=\"path/to\\float.html\">float</a><br>
<br>
      f(<br>
<br>
-    <a href=\"path/to/int.html\">int</a><br>
<br>
+    <a href=\"path/to\\int.html\">int</a><br>
<br>
      P)<br>
<br>
   </p><br>
<br>
<br>
<br>
[  FAILED  ] HTMLGeneratorTest.emitFunctionHTML (1 ms)<br>
<br>
[----------] 1 test from HTMLGeneratorTest (1 ms total)<br>
<br>
<br>
<br>
[----------] Global test environment tear-down<br>
<br>
[==========] 1 test from 1 test case ran. (1 ms total)<br>
<br>
[  PASSED  ] 0 tests.<br>
<br>
[  FAILED  ] 1 test, listed below:<br>
<br>
[  FAILED  ] HTMLGeneratorTest.emitFunctionHTML<br>
<br>
<br>
<br>
 1 FAILED TEST<br>
<br>
<br>
********************<br>
PASS: Clangd Unit Tests :: ./ClangdTests.exe/CompletionTest.CompletionOptions (20153 of 51140)<br>
FAIL: Extra Tools Unit Tests :: clang-doc/./ClangDocTests.exe/HTMLGeneratorTest.emitRecordHTML (20154 of 51140)<br>
******************** TEST 'Extra Tools Unit Tests :: clang-doc/./ClangDocTests.exe/HTMLGeneratorTest.emitRecordHTML' FAILED ********************<br>
Note: Google Test filter = HTMLGeneratorTest.emitRecordHTML<br>
<br>
[==========] Running 1 test from 1 test case.<br>
<br>
[----------] Global test environment set-up.<br>
<br>
[----------] 1 test from HTMLGeneratorTest<br>
<br>
[ RUN      ] HTMLGeneratorTest.emitRecordHTML<br>
<br>
C:\ps4-buildslave2\llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast\llvm.src\tools\clang\tools\extra\unittests\clang-doc\HTMLGeneratorTest.cpp(135): error:       Expected: Expected<br>
<br>
      Which is: "<!DOCTYPE html>\n<meta charset=\"utf-8\"/>\n<title>class r</title>\n<div>\n  <h1>class r</h1>\n  <p>\n    Defined at line 10 of test.cpp\n  </p>\n  <p>\n    Inherits from \n    <a href=\"../../../path/to/F.html\">F</a>\n    , G\n  </p>\n  <h2>Members</h2>\n  <ul>\n    <li>private <a href=\"../int.html\">int</a> X</li>\n  </ul>\n  <h2>Records</h2>\n  <ul>\n    <li>ChildStruct</li>\n  </ul>\n  <h2>Functions</h2>\n  <div>\n    <h3>OneFunction</h3>\n    <p>\n      OneFunction()\n    </p>\n  </div>\n  <h2>Enums</h2>\n  <div>\n    <h3>enum OneEnum</h3>\n  </div>\n</div>\n"<br>
<br>
To be equal to: Actual.str()<br>
<br>
      Which is: "<!DOCTYPE html>\n<meta charset=\"utf-8\"/>\n<title>class r</title>\n<div>\n  <h1>class r</h1>\n  <p>\n    Defined at line 10 of test.cpp\n  </p>\n  <p>\n    Inherits from \n    <a href=\"..\\..\\..\\path/to\\F.html\">F</a>\n    , G\n  </p>\n  <h2>Members</h2>\n  <ul>\n    <li>private <a href=\"..\\int.html\">int</a> X</li>\n  </ul>\n  <h2>Records</h2>\n  <ul>\n    <li>ChildStruct</li>\n  </ul>\n  <h2>Functions</h2>\n  <div>\n    <h3>OneFunction</h3>\n    <p>\n      OneFunction()\n    </p>\n  </div>\n  <h2>Enums</h2>\n  <div>\n    <h3>enum OneEnum</h3>\n  </div>\n</div>\n"<br>
<br>
With diff:<br>
<br>
@@ -9,5 +9,5 @@<br>
<br>
   <p><br>
<br>
     Inherits from <br>
<br>
-    <a href=\"../../../path/to/F.html\">F</a><br>
<br>
+    <a href=\"..\\..\\..\\path/to\\F.html\">F</a><br>
<br>
     , G<br>
<br>
   </p><br>
<br>
@@ -14,5 +14,5 @@<br>
<br>
   <h2>Members</h2><br>
<br>
   <ul><br>
<br>
-    <li>private <a href=\"../int.html\">int</a> X</li><br>
<br>
+    <li>private <a href=\"..\\int.html\">int</a> X</li><br>
<br>
   </ul><br>
<br>
   <h2>Records</h2><br>
<br>
<br>
<br>
[  FAILED  ] HTMLGeneratorTest.emitRecordHTML (1 ms)<br>
<br>
[----------] 1 test from HTMLGeneratorTest (1 ms total)<br>
<br>
<br>
<br>
[----------] Global test environment tear-down<br>
<br>
[==========] 1 test from 1 test case ran. (1 ms total)<br>
<br>
[  PASSED  ] 0 tests.<br>
<br>
[  FAILED  ] 1 test, listed below:<br>
<br>
[  FAILED  ] HTMLGeneratorTest.emitRecordHTML<br>
<br>
<br>
<br>
 1 FAILED TEST<br>
<br>
Can you please take a look?<br>
<br>
Douglas Yung<br>
<br>
-----Original Message-----<br>
From: cfe-commits <<a href="mailto:cfe-commits-bounces@lists.llvm.org" target="_blank">cfe-commits-bounces@lists.llvm.org</a>> On Behalf Of Julie Hockett via cfe-commits<br>
Sent: Friday, July 12, 2019 11:32<br>
To: <a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
Subject: [clang-tools-extra] r365937 - [clang-doc] Add html links to references<br>
<br>
Author: juliehockett<br>
Date: Fri Jul 12 11:32:00 2019<br>
New Revision: 365937<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=365937&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=365937&view=rev</a><br>
Log:<br>
[clang-doc] Add html links to references<br>
<br>
<a> tags are added for the parents and members of records and return type and<br>
params of functions. The link redirects to the reference's info file.<br>
<br>
The directory path where each info file will be saved is now generated in the<br>
serialization phase and stored as an attribute in each Info.<br>
<br>
Bitcode writer and reader were modified to handle the new attributes.<br>
<br>
Committed on behalf of Diego Astiazarán (<a href="mailto:diegoaat97@gmail.com" target="_blank">diegoaat97@gmail.com</a>).<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D63663" rel="noreferrer" target="_blank">https://reviews.llvm.org/D63663</a><br>
<br>
Modified:<br>
    clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp<br>
    clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp<br>
    clang-tools-extra/trunk/clang-doc/BitcodeWriter.h<br>
    clang-tools-extra/trunk/clang-doc/Generators.cpp<br>
    clang-tools-extra/trunk/clang-doc/Generators.h<br>
    clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp<br>
    clang-tools-extra/trunk/clang-doc/MDGenerator.cpp<br>
    clang-tools-extra/trunk/clang-doc/Representation.cpp<br>
    clang-tools-extra/trunk/clang-doc/Representation.h<br>
    clang-tools-extra/trunk/clang-doc/Serialize.cpp<br>
    clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp<br>
    clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp<br>
    clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp<br>
    clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp Fri Jul 12 11:32:00 2019<br>
@@ -148,6 +148,8 @@ llvm::Error parseRecord(Record R, unsign<br>
     return decodeRecord(R, I->USR, Blob);<br>
   case NAMESPACE_NAME:<br>
     return decodeRecord(R, I->Name, Blob);<br>
+  case NAMESPACE_PATH:<br>
+    return decodeRecord(R, I->Path, Blob);<br>
   default:<br>
     return llvm::make_error<llvm::StringError>(<br>
         "Invalid field for NamespaceInfo.\n", llvm::inconvertibleErrorCode());<br>
@@ -161,6 +163,8 @@ llvm::Error parseRecord(Record R, unsign<br>
     return decodeRecord(R, I->USR, Blob);<br>
   case RECORD_NAME:<br>
     return decodeRecord(R, I->Name, Blob);<br>
+  case RECORD_PATH:<br>
+    return decodeRecord(R, I->Path, Blob);<br>
   case RECORD_DEFLOCATION:<br>
     return decodeRecord(R, I->DefLoc, Blob);<br>
   case RECORD_LOCATION:<br>
@@ -286,6 +290,8 @@ llvm::Error parseRecord(Record R, unsign<br>
     return decodeRecord(R, I->Name, Blob);<br>
   case REFERENCE_TYPE:<br>
     return decodeRecord(R, I->RefType, Blob);<br>
+  case REFERENCE_PATH:<br>
+    return decodeRecord(R, I->Path, Blob);<br>
   case REFERENCE_FIELD:<br>
     return decodeRecord(R, F, Blob);<br>
   default:<br>
@@ -685,7 +691,7 @@ ClangDocBitcodeReader::createInfo(unsign<br>
   std::unique_ptr<Info> I = llvm::make_unique<T>();<br>
   if (auto Err = readBlock(ID, static_cast<T *>(I.get())))<br>
     return std::move(Err);<br>
-  return std::unique_ptr<Info>{std::move(I)};;<br>
+  return std::unique_ptr<Info>{std::move(I)};<br>
 }<br>
<br>
 llvm::Expected<std::unique_ptr<Info>><br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp Fri Jul 12 11:32:00 2019<br>
@@ -148,6 +148,7 @@ static const llvm::IndexedMap<RecordIdDs<br>
           {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},<br>
           {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},<br>
           {NAMESPACE_NAME, {"Name", &StringAbbrev}},<br>
+          {NAMESPACE_PATH, {"Path", &StringAbbrev}},<br>
           {ENUM_USR, {"USR", &SymbolIDAbbrev}},<br>
           {ENUM_NAME, {"Name", &StringAbbrev}},<br>
           {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},<br>
@@ -156,6 +157,7 @@ static const llvm::IndexedMap<RecordIdDs<br>
           {ENUM_SCOPED, {"Scoped", &BoolAbbrev}},<br>
           {RECORD_USR, {"USR", &SymbolIDAbbrev}},<br>
           {RECORD_NAME, {"Name", &StringAbbrev}},<br>
+          {RECORD_PATH, {"Path", &StringAbbrev}},<br>
           {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},<br>
           {RECORD_LOCATION, {"Location", &LocationAbbrev}},<br>
           {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},<br>
@@ -169,6 +171,7 @@ static const llvm::IndexedMap<RecordIdDs<br>
           {REFERENCE_USR, {"USR", &SymbolIDAbbrev}},<br>
           {REFERENCE_NAME, {"Name", &StringAbbrev}},<br>
           {REFERENCE_TYPE, {"RefType", &IntAbbrev}},<br>
+          {REFERENCE_PATH, {"Path", &StringAbbrev}},<br>
           {REFERENCE_FIELD, {"Field", &IntAbbrev}}};<br>
       assert(Inits.size() == RecordIdCount);<br>
       for (const auto &Init : Inits) {<br>
@@ -199,18 +202,20 @@ static const std::vector<std::pair<Block<br>
          {ENUM_USR, ENUM_NAME, ENUM_DEFLOCATION, ENUM_LOCATION, ENUM_MEMBER,<br>
           ENUM_SCOPED}},<br>
         // Namespace Block<br>
-        {BI_NAMESPACE_BLOCK_ID, {NAMESPACE_USR, NAMESPACE_NAME}},<br>
+        {BI_NAMESPACE_BLOCK_ID,<br>
+         {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},<br>
         // Record Block<br>
         {BI_RECORD_BLOCK_ID,<br>
-         {RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION,<br>
-          RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},<br>
+         {RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,<br>
+          RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},<br>
         // Function Block<br>
         {BI_FUNCTION_BLOCK_ID,<br>
          {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION,<br>
           FUNCTION_ACCESS, FUNCTION_IS_METHOD}},<br>
         // Reference Block<br>
         {BI_REFERENCE_BLOCK_ID,<br>
-         {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_FIELD}}};<br>
+         {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH,<br>
+          REFERENCE_FIELD}}};<br>
<br>
 // AbbreviationMap<br>
<br>
@@ -381,6 +386,7 @@ void ClangDocBitcodeWriter::emitBlock(co<br>
   emitRecord(R.USR, REFERENCE_USR);<br>
   emitRecord(R.Name, REFERENCE_NAME);<br>
   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);<br>
+  emitRecord(R.Path, REFERENCE_PATH);<br>
   emitRecord((unsigned)Field, REFERENCE_FIELD);<br>
 }<br>
<br>
@@ -428,6 +434,7 @@ void ClangDocBitcodeWriter::emitBlock(co<br>
   StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);<br>
   emitRecord(I.USR, NAMESPACE_USR);<br>
   emitRecord(I.Name, NAMESPACE_NAME);<br>
+  emitRecord(I.Path, NAMESPACE_PATH);<br>
   for (const auto &N : I.Namespace)<br>
     emitBlock(N, FieldId::F_namespace);<br>
   for (const auto &CI : I.Description)<br>
@@ -463,6 +470,7 @@ void ClangDocBitcodeWriter::emitBlock(co<br>
   StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);<br>
   emitRecord(I.USR, RECORD_USR);<br>
   emitRecord(I.Name, RECORD_NAME);<br>
+  emitRecord(I.Path, RECORD_PATH);<br>
   for (const auto &N : I.Namespace)<br>
     emitBlock(N, FieldId::F_namespace);<br>
   for (const auto &CI : I.Description)<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/BitcodeWriter.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.h?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/BitcodeWriter.h?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/BitcodeWriter.h (original)<br>
+++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.h Fri Jul 12 11:32:00 2019<br>
@@ -91,6 +91,7 @@ enum RecordId {<br>
   MEMBER_TYPE_ACCESS,<br>
   NAMESPACE_USR,<br>
   NAMESPACE_NAME,<br>
+  NAMESPACE_PATH,<br>
   ENUM_USR,<br>
   ENUM_NAME,<br>
   ENUM_DEFLOCATION,<br>
@@ -99,6 +100,7 @@ enum RecordId {<br>
   ENUM_SCOPED,<br>
   RECORD_USR,<br>
   RECORD_NAME,<br>
+  RECORD_PATH,<br>
   RECORD_DEFLOCATION,<br>
   RECORD_LOCATION,<br>
   RECORD_TAG_TYPE,<br>
@@ -106,6 +108,7 @@ enum RecordId {<br>
   REFERENCE_USR,<br>
   REFERENCE_NAME,<br>
   REFERENCE_TYPE,<br>
+  REFERENCE_PATH,<br>
   REFERENCE_FIELD,<br>
   RI_LAST,<br>
   RI_FIRST = VERSION<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/Generators.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/Generators.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/Generators.cpp Fri Jul 12 11:32:00 2019<br>
@@ -57,19 +57,6 @@ std::string getTagType(TagTypeKind AS) {<br>
   llvm_unreachable("Unknown TagTypeKind");<br>
 }<br>
<br>
-// Generates a comma-separated list of Refs<br>
-// Used to display the parents of a record<br>
-std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {<br>
-  std::string Buffer;<br>
-  llvm::raw_string_ostream Stream(Buffer);<br>
-  for (const auto &R : Refs) {<br>
-    if (&R != Refs.begin())<br>
-      Stream << ", ";<br>
-    Stream << R.Name;<br>
-  }<br>
-  return Stream.str();<br>
-}<br>
-<br>
 // This anchor is used to force the linker to link in the generated object file<br>
 // and thus register the generators.<br>
 extern volatile int YAMLGeneratorAnchorSource;<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/Generators.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.h?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.h?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/Generators.h (original)<br>
+++ clang-tools-extra/trunk/clang-doc/Generators.h Fri Jul 12 11:32:00 2019<br>
@@ -38,8 +38,6 @@ std::string getAccess(AccessSpecifier AS<br>
<br>
 std::string getTagType(TagTypeKind AS);<br>
<br>
-std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs);<br>
-<br>
 } // namespace doc<br>
 } // namespace clang<br>
<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp Fri Jul 12 11:32:00 2019<br>
@@ -18,13 +18,6 @@ using namespace llvm;<br>
 namespace clang {<br>
 namespace doc {<br>
<br>
-template <typename Derived, typename Base,<br>
-          typename = std::enable_if<std::is_base_of<Derived, Base>::value>><br>
-static void AppendVector(std::vector<Derived> &&New,<br>
-                         std::vector<Base> &Original) {<br>
-  std::move(New.begin(), New.end(), std::back_inserter(Original));<br>
-}<br>
-<br>
 namespace {<br>
<br>
 class HTMLTag {<br>
@@ -40,6 +33,7 @@ public:<br>
     TAG_P,<br>
     TAG_UL,<br>
     TAG_LI,<br>
+    TAG_A,<br>
   };<br>
<br>
   HTMLTag() = default;<br>
@@ -58,15 +52,22 @@ private:<br>
   TagType Value;<br>
 };<br>
<br>
+enum NodeType {<br>
+  NODE_TEXT,<br>
+  NODE_TAG,<br>
+};<br>
+<br>
 struct HTMLNode {<br>
+  HTMLNode(NodeType Type) : Type(Type) {}<br>
   virtual ~HTMLNode() = default;<br>
<br>
   virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;<br>
+  NodeType Type; // Type of node<br>
 };<br>
<br>
 struct TextNode : public HTMLNode {<br>
-  TextNode(llvm::StringRef Text, bool Indented)<br>
-      : Text(Text), Indented(Indented) {}<br>
+  TextNode(const Twine &Text, bool Indented = true)<br>
+      : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()), Indented(Indented) {}<br>
<br>
   std::string Text; // Content of node<br>
   bool Indented; // Indicates if an indentation must be rendered before the text<br>
@@ -75,7 +76,8 @@ struct TextNode : public HTMLNode {<br>
<br>
 struct TagNode : public HTMLNode {<br>
   TagNode(HTMLTag Tag)<br>
-      : Tag(Tag), InlineChildren(Tag.HasInlineChildren()),<br>
+      : HTMLNode(NodeType::NODE_TAG), Tag(Tag),<br>
+        InlineChildren(Tag.HasInlineChildren()),<br>
         SelfClosing(Tag.IsSelfClosing()) {}<br>
   TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {<br>
     Children.emplace_back(<br>
@@ -121,6 +123,7 @@ bool HTMLTag::IsSelfClosing() const {<br>
   case HTMLTag::TAG_P:<br>
   case HTMLTag::TAG_UL:<br>
   case HTMLTag::TAG_LI:<br>
+  case HTMLTag::TAG_A:<br>
     return false;<br>
   }<br>
   llvm_unreachable("Unhandled HTMLTag::TagType");<br>
@@ -134,6 +137,7 @@ bool HTMLTag::HasInlineChildren() const<br>
   case HTMLTag::TAG_H2:<br>
   case HTMLTag::TAG_H3:<br>
   case HTMLTag::TAG_LI:<br>
+  case HTMLTag::TAG_A:<br>
     return true;<br>
   case HTMLTag::TAG_DIV:<br>
   case HTMLTag::TAG_P:<br>
@@ -163,6 +167,8 @@ llvm::SmallString<16> HTMLTag::ToString(<br>
     return llvm::SmallString<16>("ul");<br>
   case HTMLTag::TAG_LI:<br>
     return llvm::SmallString<16>("li");<br>
+  case HTMLTag::TAG_A:<br>
+    return llvm::SmallString<16>("a");<br>
   }<br>
   llvm_unreachable("Unhandled HTMLTag::TagType");<br>
 }<br>
@@ -185,21 +191,87 @@ void TagNode::Render(llvm::raw_ostream &<br>
   OS << ">";<br>
   if (!InlineChildren)<br>
     OS << "\n";<br>
-  int ChildrenIndentation = InlineChildren ? 0 : IndentationLevel + 1;<br>
+  bool NewLineRendered = true;<br>
   for (const auto &C : Children) {<br>
+    int ChildrenIndentation =<br>
+        InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;<br>
     C->Render(OS, ChildrenIndentation);<br>
-    if (!InlineChildren)<br>
+    if (!InlineChildren && (C == Children.back() ||<br>
+                            (C->Type != NodeType::NODE_TEXT ||<br>
+                             (&C + 1)->get()->Type != NodeType::NODE_TEXT))) {<br>
       OS << "\n";<br>
+      NewLineRendered = true;<br>
+    } else<br>
+      NewLineRendered = false;<br>
   }<br>
   if (!InlineChildren)<br>
     OS.indent(IndentationLevel * 2);<br>
   OS << "</" << Tag.ToString() << ">";<br>
 }<br>
<br>
+template <typename Derived, typename Base,<br>
+          typename = std::enable_if<std::is_base_of<Derived, Base>::value>><br>
+static void AppendVector(std::vector<Derived> &&New,<br>
+                         std::vector<Base> &Original) {<br>
+  std::move(New.begin(), New.end(), std::back_inserter(Original));<br>
+}<br>
+<br>
+// Compute the relative path that names the file path relative to the given<br>
+// directory.<br>
+static SmallString<128> computeRelativePath(StringRef FilePath,<br>
+                                            StringRef Directory) {<br>
+  StringRef Path = FilePath;<br>
+  while (!Path.empty()) {<br>
+    if (Directory == Path)<br>
+      return FilePath.substr(Path.size());<br>
+    Path = llvm::sys::path::parent_path(Path);<br>
+  }<br>
+<br>
+  StringRef Dir = Directory;<br>
+  SmallString<128> Result;<br>
+  while (!Dir.empty()) {<br>
+    if (Dir == FilePath)<br>
+      break;<br>
+    Dir = llvm::sys::path::parent_path(Dir);<br>
+    llvm::sys::path::append(Result, "..");<br>
+  }<br>
+  llvm::sys::path::append(Result, FilePath.substr(Dir.size()));<br>
+  return Result;<br>
+}<br>
+<br>
 // HTML generation<br>
<br>
+static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) {<br>
+  auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_A, Text);<br>
+  LinkNode->Attributes.try_emplace("href", Link.str());<br>
+  return LinkNode;<br>
+}<br>
+<br>
+static std::unique_ptr<HTMLNode> genTypeReference(const Reference &Type,<br>
+                                                  StringRef CurrentDirectory) {<br>
+  if (Type.Path.empty())<br>
+    return llvm::make_unique<TextNode>(Type.Name);<br>
+  llvm::SmallString<128> Path =<br>
+      computeRelativePath(Type.Path, CurrentDirectory);<br>
+  llvm::sys::path::append(Path, Type.Name + ".html");<br>
+  return genLink(Type.Name, Path);<br>
+}<br>
+<br>
+static std::vector<std::unique_ptr<HTMLNode>><br>
+genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs,<br>
+                 const StringRef &CurrentDirectory) {<br>
+  std::vector<std::unique_ptr<HTMLNode>> Out;<br>
+  for (const auto &R : Refs) {<br>
+    if (&R != Refs.begin())<br>
+      Out.emplace_back(llvm::make_unique<TextNode>(", "));<br>
+    Out.emplace_back(genTypeReference(R, CurrentDirectory));<br>
+  }<br>
+  return Out;<br>
+}<br>
+<br>
 static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);<br>
-static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I);<br>
+static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,<br>
+                                                     StringRef ParentInfoDir);<br>
<br>
 static std::vector<std::unique_ptr<TagNode>><br>
 genEnumsBlock(const std::vector<EnumInfo> &Enums) {<br>
@@ -229,7 +301,8 @@ genEnumMembersBlock(const llvm::SmallVec<br>
 }<br>
<br>
 static std::vector<std::unique_ptr<TagNode>><br>
-genFunctionsBlock(const std::vector<FunctionInfo> &Functions) {<br>
+genFunctionsBlock(const std::vector<FunctionInfo> &Functions,<br>
+                  StringRef ParentInfoDir) {<br>
   if (Functions.empty())<br>
     return {};<br>
<br>
@@ -238,14 +311,15 @@ genFunctionsBlock(const std::vector<Func<br>
   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));<br>
   auto &DivBody = Out.back();<br>
   for (const auto &F : Functions) {<br>
-    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F);<br>
+    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F, ParentInfoDir);<br>
     AppendVector(std::move(Nodes), DivBody->Children);<br>
   }<br>
   return Out;<br>
 }<br>
<br>
 static std::vector<std::unique_ptr<TagNode>><br>
-genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members) {<br>
+genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,<br>
+                      StringRef ParentInfoDir) {<br>
   if (Members.empty())<br>
     return {};<br>
<br>
@@ -257,8 +331,11 @@ genRecordMembersBlock(const llvm::SmallV<br>
     std::string Access = getAccess(M.Access);<br>
     if (Access != "")<br>
       Access = Access + " ";<br>
-    ULBody->Children.emplace_back(llvm::make_unique<TagNode>(<br>
-        HTMLTag::TAG_LI, Access + <a href="http://M.Type.Name" rel="noreferrer" target="_blank">M.Type.Name</a> + " " + M.Name));<br>
+    auto LIBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI);<br>
+    LIBody->Children.emplace_back(llvm::make_unique<TextNode>(Access));<br>
+    LIBody->Children.emplace_back(genTypeReference(M.Type, ParentInfoDir));<br>
+    LIBody->Children.emplace_back(llvm::make_unique<TextNode>(" " + M.Name));<br>
+    ULBody->Children.emplace_back(std::move(LIBody));<br>
   }<br>
   return Out;<br>
 }<br>
@@ -346,25 +423,35 @@ static std::vector<std::unique_ptr<TagNo<br>
   return Out;<br>
 }<br>
<br>
-static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I) {<br>
+static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,<br>
+                                                     StringRef ParentInfoDir) {<br>
   std::vector<std::unique_ptr<TagNode>> Out;<br>
   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));<br>
<br>
-  std::string Buffer;<br>
-  llvm::raw_string_ostream Stream(Buffer);<br>
-  for (const auto &P : I.Params) {<br>
-    if (&P != I.Params.begin())<br>
-      Stream << ", ";<br>
-    Stream << <a href="http://P.Type.Name" rel="noreferrer" target="_blank">P.Type.Name</a> + " " + P.Name;<br>
-  }<br>
+  Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));<br>
+  auto &FunctionHeader = Out.back();<br>
<br>
   std::string Access = getAccess(I.Access);<br>
   if (Access != "")<br>
-    Access = Access + " ";<br>
+    FunctionHeader->Children.emplace_back(<br>
+        llvm::make_unique<TextNode>(Access + " "));<br>
+  if (<a href="http://I.ReturnType.Type.Name" rel="noreferrer" target="_blank">I.ReturnType.Type.Name</a> != "") {<br>
+    FunctionHeader->Children.emplace_back(<br>
+        genTypeReference(I.ReturnType.Type, ParentInfoDir));<br>
+    FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(" "));<br>
+  }<br>
+  FunctionHeader->Children.emplace_back(<br>
+      llvm::make_unique<TextNode>(I.Name + "("));<br>
<br>
-  Out.emplace_back(llvm::make_unique<TagNode>(<br>
-      HTMLTag::TAG_P, Access + <a href="http://I.ReturnType.Type.Name" rel="noreferrer" target="_blank">I.ReturnType.Type.Name</a> + " " + I.Name + "(" +<br>
-                          Stream.str() + ")"));<br>
+  for (const auto &P : I.Params) {<br>
+    if (&P != I.Params.begin())<br>
+      FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(", "));<br>
+    FunctionHeader->Children.emplace_back(<br>
+        genTypeReference(P.Type, ParentInfoDir));<br>
+    FunctionHeader->Children.emplace_back(<br>
+        llvm::make_unique<TextNode>(" " + P.Name));<br>
+  }<br>
+  FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")"));<br>
<br>
   if (I.DefLoc)<br>
     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));<br>
@@ -398,7 +485,7 @@ static std::vector<std::unique_ptr<TagNo<br>
   AppendVector(std::move(ChildRecords), Out);<br>
<br>
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =<br>
-      genFunctionsBlock(I.ChildFunctions);<br>
+      genFunctionsBlock(I.ChildFunctions, I.Path);<br>
   AppendVector(std::move(ChildFunctions), Out);<br>
   std::vector<std::unique_ptr<TagNode>> ChildEnums =<br>
       genEnumsBlock(I.ChildEnums);<br>
@@ -420,29 +507,34 @@ static std::vector<std::unique_ptr<TagNo<br>
   if (!I.Description.empty())<br>
     Out.emplace_back(genHTML(I.Description));<br>
<br>
-  std::string Parents = genReferenceList(I.Parents);<br>
-  std::string VParents = genReferenceList(I.VirtualParents);<br>
+  std::vector<std::unique_ptr<HTMLNode>> Parents =<br>
+      genReferenceList(I.Parents, I.Path);<br>
+  std::vector<std::unique_ptr<HTMLNode>> VParents =<br>
+      genReferenceList(I.VirtualParents, I.Path);<br>
   if (!Parents.empty() || !VParents.empty()) {<br>
+    Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));<br>
+    auto &PBody = Out.back();<br>
+    PBody->Children.emplace_back(llvm::make_unique<TextNode>("Inherits from "));<br>
     if (Parents.empty())<br>
-      Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P,<br>
-                                                  "Inherits from " + VParents));<br>
+      AppendVector(std::move(VParents), PBody->Children);<br>
     else if (VParents.empty())<br>
-      Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P,<br>
-                                                  "Inherits from " + Parents));<br>
-    else<br>
-      Out.emplace_back(llvm::make_unique<TagNode>(<br>
-          HTMLTag::TAG_P, "Inherits from " + Parents + ", " + VParents));<br>
+      AppendVector(std::move(Parents), PBody->Children);<br>
+    else {<br>
+      AppendVector(std::move(Parents), PBody->Children);<br>
+      PBody->Children.emplace_back(llvm::make_unique<TextNode>(", "));<br>
+      AppendVector(std::move(VParents), PBody->Children);<br>
+    }<br>
   }<br>
<br>
   std::vector<std::unique_ptr<TagNode>> Members =<br>
-      genRecordMembersBlock(I.Members);<br>
+      genRecordMembersBlock(I.Members, I.Path);<br>
   AppendVector(std::move(Members), Out);<br>
   std::vector<std::unique_ptr<TagNode>> ChildRecords =<br>
       genReferencesBlock(I.ChildRecords, "Records");<br>
   AppendVector(std::move(ChildRecords), Out);<br>
<br>
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =<br>
-      genFunctionsBlock(I.ChildFunctions);<br>
+      genFunctionsBlock(I.ChildFunctions, I.Path);<br>
   AppendVector(std::move(ChildFunctions), Out);<br>
   std::vector<std::unique_ptr<TagNode>> ChildEnums =<br>
       genEnumsBlock(I.ChildEnums);<br>
@@ -492,7 +584,7 @@ llvm::Error HTMLGenerator::generateDocFo<br>
   }<br>
   case InfoType::IT_function: {<br>
     std::vector<std::unique_ptr<TagNode>> Nodes =<br>
-        genHTML(*static_cast<clang::doc::FunctionInfo *>(I));<br>
+        genHTML(*static_cast<clang::doc::FunctionInfo *>(I), "");<br>
     AppendVector(std::move(Nodes), MainContentNode->Children);<br>
     break;<br>
   }<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/MDGenerator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/MDGenerator.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/MDGenerator.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/MDGenerator.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/MDGenerator.cpp Fri Jul 12 11:32:00 2019<br>
@@ -28,6 +28,18 @@ static std::string genEmphasis(const Twi<br>
   return "**" + Text.str() + "**";<br>
 }<br>
<br>
+static std::string<br>
+genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {<br>
+  std::string Buffer;<br>
+  llvm::raw_string_ostream Stream(Buffer);<br>
+  for (const auto &R : Refs) {<br>
+    if (&R != Refs.begin())<br>
+      Stream << ", ";<br>
+    Stream << R.Name;<br>
+  }<br>
+  return Stream.str();<br>
+}<br>
+<br>
 static void writeLine(const Twine &Text, raw_ostream &OS) {<br>
   OS << Text << "\n\n";<br>
 }<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/Representation.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/Representation.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/Representation.cpp Fri Jul 12 11:32:00 2019<br>
@@ -118,6 +118,8 @@ void Info::mergeBase(Info &&Other) {<br>
     USR = Other.USR;<br>
   if (Name == "")<br>
     Name = Other.Name;<br>
+  if (Path == "")<br>
+    Path = Other.Path;<br>
   if (Namespace.empty())<br>
     Namespace = std::move(Other.Namespace);<br>
   // Unconditionally extend the description, since each decl may have a comment.<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/Representation.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/Representation.h (original)<br>
+++ clang-tools-extra/trunk/clang-doc/Representation.h Fri Jul 12 11:32:00 2019<br>
@@ -114,8 +114,11 @@ struct CommentInfo {<br>
 struct Reference {<br>
   Reference() = default;<br>
   Reference(llvm::StringRef Name) : Name(Name) {}<br>
+  Reference(llvm::StringRef Name, StringRef Path) : Name(Name), Path(Path) {}<br>
   Reference(SymbolID USR, StringRef Name, InfoType IT)<br>
       : USR(USR), Name(Name), RefType(IT) {}<br>
+  Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)<br>
+      : USR(USR), Name(Name), RefType(IT), Path(Path) {}<br>
<br>
   bool operator==(const Reference &Other) const {<br>
     return std::tie(USR, Name, RefType) ==<br>
@@ -127,6 +130,8 @@ struct Reference {<br>
   InfoType RefType = InfoType::IT_default; // Indicates the type of this<br>
                                            // Reference (namespace, record,<br>
                                            // function, enum, default).<br>
+  llvm::SmallString<128> Path; // Path of directory where the clang-doc<br>
+                               // generated file will be saved<br>
 };<br>
<br>
 // A base struct for TypeInfos<br>
@@ -134,7 +139,10 @@ struct TypeInfo {<br>
   TypeInfo() = default;<br>
   TypeInfo(SymbolID Type, StringRef Field, InfoType IT)<br>
       : Type(Type, Field, IT) {}<br>
+  TypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path)<br>
+      : Type(Type, Field, IT, Path) {}<br>
   TypeInfo(llvm::StringRef RefName) : Type(RefName) {}<br>
+  TypeInfo(llvm::StringRef RefName, StringRef Path) : Type(RefName, Path) {}<br>
<br>
   bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }<br>
<br>
@@ -144,11 +152,13 @@ struct TypeInfo {<br>
 // Info for field types.<br>
 struct FieldTypeInfo : public TypeInfo {<br>
   FieldTypeInfo() = default;<br>
-  FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT,<br>
+  FieldTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,<br>
                 llvm::StringRef Name)<br>
-      : TypeInfo(Type, Field, IT), Name(Name) {}<br>
+      : TypeInfo(Type, Field, IT, Path), Name(Name) {}<br>
   FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)<br>
       : TypeInfo(RefName), Name(Name) {}<br>
+  FieldTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name)<br>
+      : TypeInfo(RefName, Path), Name(Name) {}<br>
<br>
   bool operator==(const FieldTypeInfo &Other) const {<br>
     return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);<br>
@@ -160,12 +170,15 @@ struct FieldTypeInfo : public TypeInfo {<br>
 // Info for member types.<br>
 struct MemberTypeInfo : public FieldTypeInfo {<br>
   MemberTypeInfo() = default;<br>
-  MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT,<br>
+  MemberTypeInfo(SymbolID Type, StringRef Field, InfoType IT, StringRef Path,<br>
                  llvm::StringRef Name, AccessSpecifier Access)<br>
-      : FieldTypeInfo(Type, Field, IT, Name), Access(Access) {}<br>
+      : FieldTypeInfo(Type, Field, IT, Path, Name), Access(Access) {}<br>
   MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name,<br>
                  AccessSpecifier Access)<br>
       : FieldTypeInfo(RefName, Name), Access(Access) {}<br>
+  MemberTypeInfo(llvm::StringRef RefName, StringRef Path, llvm::StringRef Name,<br>
+                 AccessSpecifier Access)<br>
+      : FieldTypeInfo(RefName, Path, Name), Access(Access) {}<br>
<br>
   bool operator==(const MemberTypeInfo &Other) const {<br>
     return std::tie(Type, Name, Access) ==<br>
@@ -220,6 +233,8 @@ struct Info {<br>
   llvm::SmallVector<Reference, 4><br>
       Namespace; // List of parent namespaces for this decl.<br>
   std::vector<CommentInfo> Description; // Comment description of this decl.<br>
+  llvm::SmallString<128> Path;          // Path of directory where the clang-doc<br>
+                                        // generated file will be saved<br>
<br>
   void mergeBase(Info &&I);<br>
   bool mergeable(const Info &Other);<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/Serialize.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Serialize.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/Serialize.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/Serialize.cpp Fri Jul 12 11:32:00 2019<br>
@@ -24,6 +24,43 @@ SymbolID hashUSR(llvm::StringRef USR) {<br>
   return llvm::SHA1::hash(arrayRefFromStringRef(USR));<br>
 }<br>
<br>
+template <typename T><br>
+static void<br>
+populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,<br>
+                         const T *D, bool &IsAnonymousNamespace);<br>
+<br>
+// A function to extract the appropriate relative path for a given info's<br>
+// documentation. The path returned is a composite of the parent namespaces.<br>
+//<br>
+// Example: Given the below, the diretory path for class C info will be<br>
+// <root>/A/B<br>
+//<br>
+// namespace A {<br>
+// namesapce B {<br>
+//<br>
+// class C {};<br>
+//<br>
+// }<br>
+// }<br>
+llvm::SmallString<128><br>
+getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {<br>
+  std::error_code OK;<br>
+  llvm::SmallString<128> Path;<br>
+  for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)<br>
+    llvm::sys::path::append(Path, R->Name);<br>
+  return Path;<br>
+}<br>
+<br>
+llvm::SmallString<128> getInfoRelativePath(const Decl *D) {<br>
+  llvm::SmallVector<Reference, 4> Namespaces;<br>
+  // The third arg in populateParentNamespaces is a boolean passed by reference,<br>
+  // its value is not relevant in here so it's not used anywhere besides the<br>
+  // function call<br>
+  bool B = true;<br>
+  populateParentNamespaces(Namespaces, D, B);<br>
+  return getInfoRelativePath(Namespaces);<br>
+}<br>
+<br>
 class ClangDocCommentVisitor<br>
     : public ConstCommentVisitor<ClangDocCommentVisitor> {<br>
 public:<br>
@@ -203,13 +240,13 @@ static void parseFields(RecordInfo &I, c<br>
       // valid, as opposed to an assert.<br>
       if (const auto *N = dyn_cast<EnumDecl>(T)) {<br>
         I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),<br>
-                               InfoType::IT_enum, F->getNameAsString(),<br>
-                               N->getAccessUnsafe());<br>
+                               InfoType::IT_enum, getInfoRelativePath(N),<br>
+                               F->getNameAsString(), N->getAccessUnsafe());<br>
         continue;<br>
       } else if (const auto *N = dyn_cast<RecordDecl>(T)) {<br>
         I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(),<br>
-                               InfoType::IT_record, F->getNameAsString(),<br>
-                               N->getAccessUnsafe());<br>
+                               InfoType::IT_record, getInfoRelativePath(N),<br>
+                               F->getNameAsString(), N->getAccessUnsafe());<br>
         continue;<br>
       }<br>
     }<br>
@@ -228,11 +265,13 @@ static void parseParameters(FunctionInfo<br>
     if (const auto *T = getDeclForType(P->getOriginalType())) {<br>
       if (const auto *N = dyn_cast<EnumDecl>(T)) {<br>
         I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),<br>
-                              InfoType::IT_enum, P->getNameAsString());<br>
+                              InfoType::IT_enum, getInfoRelativePath(N),<br>
+                              P->getNameAsString());<br>
         continue;<br>
       } else if (const auto *N = dyn_cast<RecordDecl>(T)) {<br>
         I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(),<br>
-                              InfoType::IT_record, P->getNameAsString());<br>
+                              InfoType::IT_record, getInfoRelativePath(N),<br>
+                              P->getNameAsString());<br>
         continue;<br>
       }<br>
     }<br>
@@ -254,14 +293,15 @@ static void parseBases(RecordInfo &I, co<br>
                              InfoType::IT_record);<br>
     } else if (const RecordDecl *P = getDeclForType(B.getType()))<br>
       I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),<br>
-                             InfoType::IT_record);<br>
+                             InfoType::IT_record, getInfoRelativePath(P));<br>
     else<br>
       I.Parents.emplace_back(B.getType().getAsString());<br>
   }<br>
   for (const CXXBaseSpecifier &B : D->vbases()) {<br>
     if (const auto *P = getDeclForType(B.getType()))<br>
       I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),<br>
-                                    InfoType::IT_record);<br>
+                                    InfoType::IT_record,<br>
+                                    getInfoRelativePath(P));<br>
     else<br>
       I.VirtualParents.emplace_back(B.getType().getAsString());<br>
   }<br>
@@ -270,14 +310,14 @@ static void parseBases(RecordInfo &I, co<br>
 template <typename T><br>
 static void<br>
 populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,<br>
-                         const T *D, bool &IsAnonymousNamespace) {<br>
+                         const T *D, bool &IsInAnonymousNamespace) {<br>
   const auto *DC = dyn_cast<DeclContext>(D);<br>
   while ((DC = DC->getParent())) {<br>
     if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {<br>
       std::string Namespace;<br>
       if (N->isAnonymousNamespace()) {<br>
         Namespace = "@nonymous_namespace";<br>
-        IsAnonymousNamespace = true;<br>
+        IsInAnonymousNamespace = true;<br>
       } else<br>
         Namespace = N->getNameAsString();<br>
       Namespaces.emplace_back(getUSRForDecl(N), Namespace,<br>
@@ -324,11 +364,11 @@ static void populateFunctionInfo(Functio<br>
   populateSymbolInfo(I, D, FC, LineNumber, Filename, IsInAnonymousNamespace);<br>
   if (const auto *T = getDeclForType(D->getReturnType())) {<br>
     if (dyn_cast<EnumDecl>(T))<br>
-      I.ReturnType =<br>
-          TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum);<br>
+      I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),<br>
+                              InfoType::IT_enum, getInfoRelativePath(T));<br>
     else if (dyn_cast<RecordDecl>(T))<br>
-      I.ReturnType =<br>
-          TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record);<br>
+      I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(),<br>
+                              InfoType::IT_record, getInfoRelativePath(T));<br>
   } else {<br>
     I.ReturnType = TypeInfo(D->getReturnType().getAsString());<br>
   }<br>
@@ -347,16 +387,18 @@ emitInfo(const NamespaceDecl *D, const F<br>
   I->Name = D->isAnonymousNamespace()<br>
                 ? llvm::SmallString<16>("@nonymous_namespace")<br>
                 : I->Name;<br>
+  I->Path = getInfoRelativePath(I->Namespace);<br>
   if (I->Namespace.empty() && I->USR == SymbolID())<br>
     return {std::unique_ptr<Info>{std::move(I)}, nullptr};<br>
<br>
-  SymbolID ParentUSR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;<br>
-<br>
-  auto Parent = llvm::make_unique<NamespaceInfo>();<br>
-  Parent->USR = ParentUSR;<br>
-  Parent->ChildNamespaces.emplace_back(I->USR, I->Name, InfoType::IT_namespace);<br>
+  auto ParentI = llvm::make_unique<NamespaceInfo>();<br>
+  ParentI->USR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;<br>
+  ParentI->ChildNamespaces.emplace_back(I->USR, I->Name,<br>
+                                        InfoType::IT_namespace);<br>
+  if (I->Namespace.empty())<br>
+    ParentI->Path = getInfoRelativePath(ParentI->Namespace);<br>
   return {std::unique_ptr<Info>{std::move(I)},<br>
-          std::unique_ptr<Info>{std::move(Parent)}};<br>
+          std::unique_ptr<Info>{std::move(ParentI)}};<br>
 }<br>
<br>
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>><br>
@@ -378,32 +420,34 @@ emitInfo(const RecordDecl *D, const Full<br>
     }<br>
     parseBases(*I, C);<br>
   }<br>
+  I->Path = getInfoRelativePath(I->Namespace);<br>
<br>
   if (I->Namespace.empty()) {<br>
-    auto Parent = llvm::make_unique<NamespaceInfo>();<br>
-    Parent->USR = SymbolID();<br>
-    Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);<br>
+    auto ParentI = llvm::make_unique<NamespaceInfo>();<br>
+    ParentI->USR = SymbolID();<br>
+    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);<br>
+    ParentI->Path = getInfoRelativePath(ParentI->Namespace);<br>
     return {std::unique_ptr<Info>{std::move(I)},<br>
-            std::unique_ptr<Info>{std::move(Parent)}};<br>
+            std::unique_ptr<Info>{std::move(ParentI)}};<br>
   }<br>
<br>
   switch (I->Namespace[0].RefType) {<br>
   case InfoType::IT_namespace: {<br>
-    auto Parent = llvm::make_unique<NamespaceInfo>();<br>
-    Parent->USR = I->Namespace[0].USR;<br>
-    Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);<br>
+    auto ParentI = llvm::make_unique<NamespaceInfo>();<br>
+    ParentI->USR = I->Namespace[0].USR;<br>
+    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);<br>
     return {std::unique_ptr<Info>{std::move(I)},<br>
-            std::unique_ptr<Info>{std::move(Parent)}};<br>
+            std::unique_ptr<Info>{std::move(ParentI)}};<br>
   }<br>
   case InfoType::IT_record: {<br>
-    auto Parent = llvm::make_unique<RecordInfo>();<br>
-    Parent->USR = I->Namespace[0].USR;<br>
-    Parent->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);<br>
+    auto ParentI = llvm::make_unique<RecordInfo>();<br>
+    ParentI->USR = I->Namespace[0].USR;<br>
+    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record);<br>
     return {std::unique_ptr<Info>{std::move(I)},<br>
-            std::unique_ptr<Info>{std::move(Parent)}};<br>
+            std::unique_ptr<Info>{std::move(ParentI)}};<br>
   }<br>
   default:<br>
-    llvm_unreachable("Invalid reference type");<br>
+    llvm_unreachable("Invalid reference type for parent namespace");<br>
   }<br>
 }<br>
<br>
@@ -420,14 +464,16 @@ emitInfo(const FunctionDecl *D, const Fu<br>
   Func.Access = clang::AccessSpecifier::AS_none;<br>
<br>
   // Wrap in enclosing scope<br>
-  auto I = llvm::make_unique<NamespaceInfo>();<br>
+  auto ParentI = llvm::make_unique<NamespaceInfo>();<br>
   if (!Func.Namespace.empty())<br>
-    I->USR = Func.Namespace[0].USR;<br>
+    ParentI->USR = Func.Namespace[0].USR;<br>
   else<br>
-    I->USR = SymbolID();<br>
-  I->ChildFunctions.emplace_back(std::move(Func));<br>
-  // Info es wrapped in its parent scope so it's returned in the second position<br>
-  return {nullptr, std::unique_ptr<Info>{std::move(I)}};<br>
+    ParentI->USR = SymbolID();<br>
+  if (Func.Namespace.empty())<br>
+    ParentI->Path = getInfoRelativePath(ParentI->Namespace);<br>
+  ParentI->ChildFunctions.emplace_back(std::move(Func));<br>
+  // Info is wrapped in its parent scope so it's returned in the second position<br>
+  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};<br>
 }<br>
<br>
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>><br>
@@ -455,11 +501,13 @@ emitInfo(const CXXMethodDecl *D, const F<br>
   Func.Access = D->getAccess();<br>
<br>
   // Wrap in enclosing scope<br>
-  auto I = llvm::make_unique<RecordInfo>();<br>
-  I->USR = ParentUSR;<br>
-  I->ChildFunctions.emplace_back(std::move(Func));<br>
+  auto ParentI = llvm::make_unique<RecordInfo>();<br>
+  ParentI->USR = ParentUSR;<br>
+  if (Func.Namespace.empty())<br>
+    ParentI->Path = getInfoRelativePath(ParentI->Namespace);<br>
+  ParentI->ChildFunctions.emplace_back(std::move(Func));<br>
   // Info is wrapped in its parent scope so it's returned in the second position<br>
-  return {nullptr, std::unique_ptr<Info>{std::move(I)}};<br>
+  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};<br>
 }<br>
<br>
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>><br>
@@ -475,36 +523,38 @@ emitInfo(const EnumDecl *D, const FullCo<br>
   Enum.Scoped = D->isScoped();<br>
   parseEnumerators(Enum, D);<br>
<br>
-  // Wrap in enclosing scope<br>
-  if (!Enum.Namespace.empty()) {<br>
-    switch (Enum.Namespace[0].RefType) {<br>
-    case InfoType::IT_namespace: {<br>
-      auto I = llvm::make_unique<NamespaceInfo>();<br>
-      I->USR = Enum.Namespace[0].USR;<br>
-      I->ChildEnums.emplace_back(std::move(Enum));<br>
-      // Info is wrapped in its parent scope so it's returned in the second<br>
-      // position<br>
-      return {nullptr, std::unique_ptr<Info>{std::move(I)}};<br>
-    }<br>
-    case InfoType::IT_record: {<br>
-      auto I = llvm::make_unique<RecordInfo>();<br>
-      I->USR = Enum.Namespace[0].USR;<br>
-      I->ChildEnums.emplace_back(std::move(Enum));<br>
-      // Info is wrapped in its parent scope so it's returned in the second<br>
-      // position<br>
-      return {nullptr, std::unique_ptr<Info>{std::move(I)}};<br>
-    }<br>
-    default:<br>
-      break;<br>
-    }<br>
+  // Put in global namespace<br>
+  if (Enum.Namespace.empty()) {<br>
+    auto ParentI = llvm::make_unique<NamespaceInfo>();<br>
+    ParentI->USR = SymbolID();<br>
+    ParentI->ChildEnums.emplace_back(std::move(Enum));<br>
+    ParentI->Path = getInfoRelativePath(ParentI->Namespace);<br>
+    // Info is wrapped in its parent scope so it's returned in the second<br>
+    // position<br>
+    return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};<br>
   }<br>
<br>
-  // Put in global namespace<br>
-  auto I = llvm::make_unique<NamespaceInfo>();<br>
-  I->USR = SymbolID();<br>
-  I->ChildEnums.emplace_back(std::move(Enum));<br>
-  // Info is wrapped in its parent scope so it's returned in the second position<br>
-  return {nullptr, std::unique_ptr<Info>{std::move(I)}};<br>
+  // Wrap in enclosing scope<br>
+  switch (Enum.Namespace[0].RefType) {<br>
+  case InfoType::IT_namespace: {<br>
+    auto ParentI = llvm::make_unique<NamespaceInfo>();<br>
+    ParentI->USR = Enum.Namespace[0].USR;<br>
+    ParentI->ChildEnums.emplace_back(std::move(Enum));<br>
+    // Info is wrapped in its parent scope so it's returned in the second<br>
+    // position<br>
+    return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};<br>
+  }<br>
+  case InfoType::IT_record: {<br>
+    auto ParentI = llvm::make_unique<RecordInfo>();<br>
+    ParentI->USR = Enum.Namespace[0].USR;<br>
+    ParentI->ChildEnums.emplace_back(std::move(Enum));<br>
+    // Info is wrapped in its parent scope so it's returned in the second<br>
+    // position<br>
+    return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};<br>
+  }<br>
+  default:<br>
+    llvm_unreachable("Invalid reference type for parent namespace");<br>
+  }<br>
 }<br>
<br>
 } // namespace serialize<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp Fri Jul 12 11:32:00 2019<br>
@@ -113,6 +113,7 @@ static void FieldTypeInfoMapping(IO &IO,<br>
 static void InfoMapping(IO &IO, Info &I) {<br>
   IO.mapRequired("USR", I.USR);<br>
   IO.mapOptional("Name", I.Name, SmallString<16>());<br>
+  IO.mapOptional("Path", I.Path, SmallString<128>());<br>
   IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());<br>
   IO.mapOptional("Description", I.Description);<br>
 }<br>
@@ -154,6 +155,7 @@ template <> struct MappingTraits<Referen<br>
     IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);<br>
     IO.mapOptional("Name", Ref.Name, SmallString<16>());<br>
     IO.mapOptional("USR", Ref.USR, SymbolID());<br>
+    IO.mapOptional("Path", Ref.Path, SmallString<128>());<br>
   }<br>
 };<br>
<br>
<br>
Modified: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp (original)<br>
+++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp Fri Jul 12 11:32:00 2019<br>
@@ -110,12 +110,13 @@ bool CreateDirectory(const Twine &DirNam<br>
   return false;<br>
 }<br>
<br>
-// A function to extract the appropriate path name for a given info's<br>
-// documentation. The path returned is a composite of the parent namespaces as<br>
-// directories plus the decl name as the filename.<br>
+// A function to extract the appropriate file name for a given info's<br>
+// documentation. The path returned is a composite of the output directory, the<br>
+// info's relative path and name and the extension. The relative path should<br>
+// have been constructed in the serialization phase.<br>
 //<br>
-// Example: Given the below, the <ext> path for class C will be <<br>
-// root>/A/B/C.<ext><br>
+// Example: Given the below, the <ext> path for class C will be<br>
+// <root>/A/B/C.<ext><br>
 //<br>
 // namespace A {<br>
 // namesapce B {<br>
@@ -124,16 +125,14 @@ bool CreateDirectory(const Twine &DirNam<br>
 //<br>
 // }<br>
 // }<br>
-llvm::Expected<llvm::SmallString<128>><br>
-getInfoOutputFile(StringRef Root,<br>
-                  llvm::SmallVectorImpl<doc::Reference> &Namespaces,<br>
-                  StringRef Name, StringRef Ext) {<br>
+llvm::Expected<llvm::SmallString<128>> getInfoOutputFile(StringRef Root,<br>
+                                                         StringRef RelativePath,<br>
+                                                         StringRef Name,<br>
+                                                         StringRef Ext) {<br>
   std::error_code OK;<br>
   llvm::SmallString<128> Path;<br>
   llvm::sys::path::native(Root, Path);<br>
-  for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)<br>
-    llvm::sys::path::append(Path, R->Name);<br>
-<br>
+  llvm::sys::path::append(Path, RelativePath);<br>
   if (CreateDirectory(Path))<br>
     return llvm::make_error<llvm::StringError>("Unable to create directory.\n",<br>
                                                llvm::inconvertibleErrorCode());<br>
@@ -223,12 +222,11 @@ int main(int argc, const char **argv) {<br>
     }<br>
<br>
     doc::Info *I = Reduced.get().get();<br>
-<br>
-    auto InfoPath = getInfoOutputFile(OutDirectory, I->Namespace,<br>
-                                      I->extractName(), "." + Format);<br>
+    auto InfoPath = getInfoOutputFile(OutDirectory, I->Path, I->extractName(),<br>
+                                      "." + Format);<br>
     if (!InfoPath) {<br>
       llvm::errs() << toString(InfoPath.takeError()) << "\n";<br>
-      continue;<br>
+      return 1;<br>
     }<br>
     std::error_code FileErr;<br>
     llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);<br>
<br>
Modified: clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp (original)<br>
+++ clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp Fri Jul 12 11:32:00 2019<br>
@@ -57,7 +57,7 @@ TEST(HTMLGeneratorTest, emitNamespaceHTM<br>
   <div><br>
     <h3>OneFunction</h3><br>
     <p><br>
-       OneFunction()<br>
+      OneFunction()<br>
     </p><br>
   </div><br>
   <h2>Enums</h2><br>
@@ -73,14 +73,16 @@ TEST(HTMLGeneratorTest, emitNamespaceHTM<br>
 TEST(HTMLGeneratorTest, emitRecordHTML) {<br>
   RecordInfo I;<br>
   I.Name = "r";<br>
+  I.Path = "X/Y/Z";<br>
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);<br>
<br>
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});<br>
   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});<br>
<br>
-  I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);<br>
+  I.Members.emplace_back("int", "X/Y", "X", AccessSpecifier::AS_private);<br>
   I.TagType = TagTypeKind::TTK_Class;<br>
-  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);<br>
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record,<br>
+                         llvm::SmallString<128>("path/to"));<br>
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);<br>
<br>
   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);<br>
@@ -104,11 +106,13 @@ TEST(HTMLGeneratorTest, emitRecordHTML)<br>
     Defined at line 10 of test.cpp<br>
   </p><br>
   <p><br>
-    Inherits from F, G<br>
+    Inherits from <br>
+    <a href="../../../path/to/F.html">F</a><br>
+    , G<br>
   </p><br>
   <h2>Members</h2><br>
   <ul><br>
-    <li>private int X</li><br>
+    <li>private <a href="../int.html">int</a> X</li><br>
   </ul><br>
   <h2>Records</h2><br>
   <ul><br>
@@ -118,7 +122,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML)<br>
   <div><br>
     <h3>OneFunction</h3><br>
     <p><br>
-       OneFunction()<br>
+      OneFunction()<br>
     </p><br>
   </div><br>
   <h2>Enums</h2><br>
@@ -139,8 +143,8 @@ TEST(HTMLGeneratorTest, emitFunctionHTML<br>
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});<br>
   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});<br>
<br>
-  I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);<br>
-  I.Params.emplace_back("int", "P");<br>
+  I.ReturnType = TypeInfo(EmptySID, "float", InfoType::IT_default, "path/to");<br>
+  I.Params.emplace_back("int", "path/to", "P");<br>
   I.IsMethod = true;<br>
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);<br>
<br>
@@ -156,7 +160,10 @@ TEST(HTMLGeneratorTest, emitFunctionHTML<br>
 <div><br>
   <h3>f</h3><br>
   <p><br>
-    void f(int P)<br>
+    <a href="path/to/float.html">float</a><br>
+     f(<br>
+    <a href="path/to/int.html">int</a><br>
+     P)<br>
   </p><br>
   <p><br>
     Defined at line 10 of test.cpp<br>
@@ -261,8 +268,7 @@ TEST(HTMLGeneratorTest, emitCommentHTML)<br>
          Brief description.<br>
       </p><br>
       <p><br>
-         Extended description that<br>
-         continues onto the next line.<br>
+         Extended description that continues onto the next line.<br>
       </p><br>
     </div><br>
   </div><br>
<br>
Modified: clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp?rev=365937&r1=365936&r2=365937&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp?rev=365937&r1=365936&r2=365937&view=diff</a><br>
==============================================================================<br>
--- clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp (original)<br>
+++ clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp Fri Jul 12 11:32:00 2019<br>
@@ -25,6 +25,7 @@ std::unique_ptr<Generator> getYAMLGenera<br>
 TEST(YAMLGeneratorTest, emitNamespaceYAML) {<br>
   NamespaceInfo I;<br>
   I.Name = "Namespace";<br>
+  I.Path = "path/to/A";<br>
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);<br>
<br>
   I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",<br>
@@ -45,6 +46,7 @@ TEST(YAMLGeneratorTest, emitNamespaceYAM<br>
       R"raw(---<br>
 USR:             '0000000000000000000000000000000000000000'<br>
 Name:            'Namespace'<br>
+Path:            'path/to/A'<br>
 Namespace:<br>
   - Type:            Namespace<br>
     Name:            'A'<br>
@@ -69,15 +71,18 @@ ChildEnums:<br>
 TEST(YAMLGeneratorTest, emitRecordYAML) {<br>
   RecordInfo I;<br>
   I.Name = "r";<br>
+  I.Path = "path/to/r";<br>
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);<br>
<br>
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});<br>
   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});<br>
<br>
-  I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);<br>
+  I.Members.emplace_back("int", "path/to/int", "X",<br>
+                         AccessSpecifier::AS_private);<br>
   I.TagType = TagTypeKind::TTK_Class;<br>
-  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);<br>
-  I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);<br>
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "path/to/F");<br>
+  I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,<br>
+                                "path/to/G");<br>
<br>
   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);<br>
   I.ChildFunctions.emplace_back();<br>
@@ -95,6 +100,7 @@ TEST(YAMLGeneratorTest, emitRecordYAML)<br>
       R"raw(---<br>
 USR:             '0000000000000000000000000000000000000000'<br>
 Name:            'r'<br>
+Path:            'path/to/r'<br>
 Namespace:<br>
   - Type:            Namespace<br>
     Name:            'A'<br>
@@ -108,14 +114,17 @@ TagType:         Class<br>
 Members:<br>
   - Type:<br>
       Name:            'int'<br>
+      Path:            'path/to/int'<br>
     Name:            'X'<br>
     Access:          Private<br>
 Parents:<br>
   - Type:            Record<br>
     Name:            'F'<br>
+    Path:            'path/to/F'<br>
 VirtualParents:<br>
   - Type:            Record<br>
     Name:            'G'<br>
+    Path:            'path/to/G'<br>
 ChildRecords:<br>
   - Type:            Record<br>
     Name:            'ChildStruct'<br>
@@ -139,8 +148,9 @@ TEST(YAMLGeneratorTest, emitFunctionYAML<br>
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});<br>
   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});<br>
<br>
-  I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);<br>
-  I.Params.emplace_back("int", "P");<br>
+  I.ReturnType =<br>
+      TypeInfo(EmptySID, "void", InfoType::IT_default, "path/to/void");<br>
+  I.Params.emplace_back("int", "path/to/int", "P");<br>
   I.IsMethod = true;<br>
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);<br>
<br>
@@ -170,10 +180,12 @@ Parent:<br>
 Params:<br>
   - Type:<br>
       Name:            'int'<br>
+      Path:            'path/to/int'<br>
     Name:            'P'<br>
 ReturnType:<br>
   Type:<br>
     Name:            'void'<br>
+    Path:            'path/to/void'<br>
 ...<br>
 )raw";<br>
   EXPECT_EQ(Expected, Actual.str());<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>