[clang-doc] Fix link generation

Before making a link to a reference it is required to check that the
reference has a path (eg. primitives won't have paths).
This was done by checking if the path was empty; that worked because
when generating paths the outdirectory was included, so if the path was
assigned it had that outdirectory at least.
The path generation was changed, it's now only the composite of the
namespaces without the outdirectory. So if the info is in the global
namespace the path would be empty and the old check wouldn't work as expected.
A new attribute has been added to the Reference struct that indicates if
the info's parent is the global namespace.
Paths generation now fails if the path is empty and if the info
is not in the global namespace.

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

git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@367958 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/clang-doc/BitcodeReader.cpp b/clang-doc/BitcodeReader.cpp
index 2b27d60..04be1ca 100644
--- a/clang-doc/BitcodeReader.cpp
+++ b/clang-doc/BitcodeReader.cpp
@@ -292,6 +292,8 @@
     return decodeRecord(R, I->RefType, Blob);
   case REFERENCE_PATH:
     return decodeRecord(R, I->Path, Blob);
+  case REFERENCE_IS_IN_GLOBAL_NAMESPACE:
+    return decodeRecord(R, I->IsInGlobalNamespace, Blob);
   case REFERENCE_FIELD:
     return decodeRecord(R, F, Blob);
   default:
diff --git a/clang-doc/BitcodeWriter.cpp b/clang-doc/BitcodeWriter.cpp
index 2adb936..d26f3db 100644
--- a/clang-doc/BitcodeWriter.cpp
+++ b/clang-doc/BitcodeWriter.cpp
@@ -172,6 +172,8 @@
           {REFERENCE_NAME, {"Name", &StringAbbrev}},
           {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
           {REFERENCE_PATH, {"Path", &StringAbbrev}},
+          {REFERENCE_IS_IN_GLOBAL_NAMESPACE,
+           {"IsInGlobalNamespace", &BoolAbbrev}},
           {REFERENCE_FIELD, {"Field", &IntAbbrev}}};
       assert(Inits.size() == RecordIdCount);
       for (const auto &Init : Inits) {
@@ -215,7 +217,7 @@
         // Reference Block
         {BI_REFERENCE_BLOCK_ID,
          {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH,
-          REFERENCE_FIELD}}};
+          REFERENCE_IS_IN_GLOBAL_NAMESPACE, REFERENCE_FIELD}}};
 
 // AbbreviationMap
 
@@ -387,6 +389,7 @@
   emitRecord(R.Name, REFERENCE_NAME);
   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
   emitRecord(R.Path, REFERENCE_PATH);
+  emitRecord(R.IsInGlobalNamespace, REFERENCE_IS_IN_GLOBAL_NAMESPACE);
   emitRecord((unsigned)Field, REFERENCE_FIELD);
 }
 
diff --git a/clang-doc/BitcodeWriter.h b/clang-doc/BitcodeWriter.h
index 3fa2125..dcb7c91 100644
--- a/clang-doc/BitcodeWriter.h
+++ b/clang-doc/BitcodeWriter.h
@@ -109,6 +109,7 @@
   REFERENCE_NAME,
   REFERENCE_TYPE,
   REFERENCE_PATH,
+  REFERENCE_IS_IN_GLOBAL_NAMESPACE,
   REFERENCE_FIELD,
   RI_LAST,
   RI_FIRST = VERSION
diff --git a/clang-doc/HTMLGenerator.cpp b/clang-doc/HTMLGenerator.cpp
index aa62624..cf11f75 100644
--- a/clang-doc/HTMLGenerator.cpp
+++ b/clang-doc/HTMLGenerator.cpp
@@ -247,7 +247,7 @@
 
 static std::unique_ptr<HTMLNode> genTypeReference(const Reference &Type,
                                                   StringRef CurrentDirectory) {
-  if (Type.Path.empty())
+  if (Type.Path.empty() && !Type.IsInGlobalNamespace)
     return llvm::make_unique<TextNode>(Type.Name);
   llvm::SmallString<128> Path =
       computeRelativePath(Type.Path, CurrentDirectory);
diff --git a/clang-doc/Representation.h b/clang-doc/Representation.h
index 6abccf8..c74ed81 100644
--- a/clang-doc/Representation.h
+++ b/clang-doc/Representation.h
@@ -114,11 +114,17 @@
 struct Reference {
   Reference() = default;
   Reference(llvm::StringRef Name) : Name(Name) {}
-  Reference(llvm::StringRef Name, StringRef Path) : Name(Name), Path(Path) {}
+  // An empty path means the info is in the global namespace because the path is
+  // a composite of the parent namespaces.
+  Reference(llvm::StringRef Name, StringRef Path)
+      : Name(Name), Path(Path), IsInGlobalNamespace(Path.empty()) {}
   Reference(SymbolID USR, StringRef Name, InfoType IT)
       : USR(USR), Name(Name), RefType(IT) {}
+  // An empty path means the info is in the global namespace because the path is
+  // a composite of the parent namespaces.
   Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
-      : USR(USR), Name(Name), RefType(IT), Path(Path) {}
+      : USR(USR), Name(Name), RefType(IT), Path(Path),
+        IsInGlobalNamespace(Path.empty()) {}
 
   bool operator==(const Reference &Other) const {
     return std::tie(USR, Name, RefType) ==
@@ -130,8 +136,12 @@
   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
+  // Path of directory where the clang-doc generated file will be saved
+  // (possibly unresolved)
+  llvm::SmallString<128> Path;
+  // Indicates if the info's parent is the global namespace, or if the info is
+  // the global namespace
+  bool IsInGlobalNamespace = false;
 };
 
 // A base struct for TypeInfos
diff --git a/clang-doc/YAMLGenerator.cpp b/clang-doc/YAMLGenerator.cpp
index 9a388b9..4f5e2fd 100644
--- a/clang-doc/YAMLGenerator.cpp
+++ b/clang-doc/YAMLGenerator.cpp
@@ -156,6 +156,7 @@
     IO.mapOptional("Name", Ref.Name, SmallString<16>());
     IO.mapOptional("USR", Ref.USR, SymbolID());
     IO.mapOptional("Path", Ref.Path, SmallString<128>());
+    IO.mapOptional("IsInGlobalNamespace", Ref.IsInGlobalNamespace, false);
   }
 };
 
diff --git a/unittests/clang-doc/YAMLGeneratorTest.cpp b/unittests/clang-doc/YAMLGeneratorTest.cpp
index 26379d2..262ba00 100644
--- a/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ b/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -80,7 +80,8 @@
   I.Members.emplace_back("int", "path/to/int", "X",
                          AccessSpecifier::AS_private);
   I.TagType = TagTypeKind::TTK_Class;
-  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "path/to/F");
+  // F is in the global namespace
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "");
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
                                 "path/to/G");
 
@@ -120,7 +121,7 @@
 Parents:
   - Type:            Record
     Name:            'F'
-    Path:            'path/to/F'
+    IsInGlobalNamespace: true
 VirtualParents:
   - Type:            Record
     Name:            'G'