[Demangle] Add support for multiple identifiers in D qualified names

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D114305
diff --git a/llvm/lib/Demangle/DLangDemangle.cpp b/llvm/lib/Demangle/DLangDemangle.cpp
index 73d5ce1..a877174 100644
--- a/llvm/lib/Demangle/DLangDemangle.cpp
+++ b/llvm/lib/Demangle/DLangDemangle.cpp
@@ -69,6 +69,15 @@
   /// \see https://dlang.org/spec/abi.html#Number .
   const char *decodeNumber(const char *Mangled, unsigned long *Ret);
 
+  /// Check whether it is the beginning of a symbol name.
+  ///
+  /// \param Mangled string to extract the symbol name.
+  ///
+  /// \return true on success, false otherwise.
+  ///
+  /// \see https://dlang.org/spec/abi.html#SymbolName .
+  bool isSymbolName(const char *Mangled);
+
   /// Extract and demangle an identifier from a given mangled symbol append it
   /// to the output string.
   ///
@@ -136,6 +145,14 @@
   return Mangled;
 }
 
+bool Demangler::isSymbolName(const char *Mangled) {
+  if (std::isdigit(*Mangled))
+    return true;
+
+  // TODO: Handle symbol back references and template instances.
+  return false;
+}
+
 const char *Demangler::parseMangle(OutputBuffer *Demangled,
                                    const char *Mangled) {
   // A D mangled symbol is comprised of both scope and type information.
@@ -180,9 +197,18 @@
   //        SymbolName M TypeModifiers TypeFunctionNoReturn
   // The start pointer should be at the above location.
 
-  // TODO: Parse multiple identifiers
+  // Whether it has more than one symbol
+  size_t NotFirst = false;
+  do {
+    if (NotFirst)
+      *Demangled << '.';
+    NotFirst = true;
 
-  return parseIdentifier(Demangled, Mangled);
+    Mangled = parseIdentifier(Demangled, Mangled);
+
+  } while (Mangled && isSymbolName(Mangled));
+
+  return Mangled;
 }
 
 const char *Demangler::parseIdentifier(OutputBuffer *Demangled,
diff --git a/llvm/unittests/Demangle/DLangDemangleTest.cpp b/llvm/unittests/Demangle/DLangDemangleTest.cpp
index ad814cb..750ce88 100644
--- a/llvm/unittests/Demangle/DLangDemangleTest.cpp
+++ b/llvm/unittests/Demangle/DLangDemangleTest.cpp
@@ -26,11 +26,12 @@
   EXPECT_STREQ(Demangled, GetParam().second);
 }
 
-INSTANTIATE_TEST_SUITE_P(DLangDemangleTest, DLangDemangleTestFixture,
-                         testing::Values(std::make_pair("_Dmain", "D main"),
-                                         std::make_pair(nullptr, nullptr),
-                                         std::make_pair("_Z", nullptr),
-                                         std::make_pair("_DDD", nullptr),
-                                         std::make_pair("_D88", nullptr),
-                                         std::make_pair("_D8demangleZ",
-                                                        "demangle")));
+INSTANTIATE_TEST_SUITE_P(
+    DLangDemangleTest, DLangDemangleTestFixture,
+    testing::Values(
+        std::make_pair("_Dmain", "D main"), std::make_pair(nullptr, nullptr),
+        std::make_pair("_Z", nullptr), std::make_pair("_DDD", nullptr),
+        std::make_pair("_D88", nullptr),
+        std::make_pair("_D8demangleZ", "demangle"),
+        std::make_pair("_D8demangle4testZ", "demangle.test"),
+        std::make_pair("_D8demangle4test5test2Z", "demangle.test.test2")));