[llvm] [MSVC][Demangling] Make Microsoft demangling more configurable (PR #202702)

Fred Tingaud via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 01:49:19 PDT 2026


https://github.com/frederic-tingaud-sonarsource updated https://github.com/llvm/llvm-project/pull/202702

>From 94aa2ab69270d7e18dc43f94f7a1eb82b8498a0d Mon Sep 17 00:00:00 2001
From: Fred Tingaud <frederic.tingaud at sonarsource.com>
Date: Fri, 23 Jan 2026 15:47:44 +0100
Subject: [PATCH] [MSVC][Demangling] Make Microsoft demangling more
 configurable

The goal for us is to be able to demangle toward something that reads more like function names.
All default remain the same.

* Make the OF_NoTagSpecifier flag accessible from `microsoftDemangle`
* Add a flag to skip the "void" keyword when there is no parameter
* Add a flag to skip the type descriptions
* Respect MSDF_NoCallingConvention with function pointers
* More unit tests.

Assisted-by: Claude
---
 llvm/include/llvm/Demangle/Demangle.h         |   3 +
 .../llvm/Demangle/MicrosoftDemangleNodes.h    |  22 +-
 llvm/lib/Demangle/MicrosoftDemangle.cpp       |  19 +-
 llvm/lib/Demangle/MicrosoftDemangleNodes.cpp  |  23 +-
 llvm/unittests/Demangle/CMakeLists.txt        |   1 +
 .../Demangle/MicrosoftDemangleTest.cpp        | 318 ++++++++++++++++++
 6 files changed, 367 insertions(+), 19 deletions(-)
 create mode 100644 llvm/unittests/Demangle/MicrosoftDemangleTest.cpp

diff --git a/llvm/include/llvm/Demangle/Demangle.h b/llvm/include/llvm/Demangle/Demangle.h
index d9b08b2d856dc..d78fdd9aa3fe8 100644
--- a/llvm/include/llvm/Demangle/Demangle.h
+++ b/llvm/include/llvm/Demangle/Demangle.h
@@ -45,6 +45,9 @@ enum MSDemangleFlags {
   MSDF_NoReturnType = 1 << 3,
   MSDF_NoMemberType = 1 << 4,
   MSDF_NoVariableType = 1 << 5,
+  MSDF_NoTagSpecifier = 1 << 6,
+  MSDF_NoVoidParameter = 1 << 7,
+  MSDF_NoTypeDescription = 1 << 8,
 };
 
 /// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
diff --git a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
index 711aa70a4a8d3..2b826a3d38e75 100644
--- a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
+++ b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h
@@ -74,12 +74,14 @@ enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
 
 enum OutputFlags {
   OF_Default = 0,
-  OF_NoCallingConvention = 1,
-  OF_NoTagSpecifier = 2,
-  OF_NoAccessSpecifier = 4,
-  OF_NoMemberType = 8,
-  OF_NoReturnType = 16,
-  OF_NoVariableType = 32,
+  OF_NoCallingConvention = 1 << 0,
+  OF_NoTagSpecifier = 1 << 1,
+  OF_NoAccessSpecifier = 1 << 2,
+  OF_NoMemberType = 1 << 3,
+  OF_NoReturnType = 1 << 4,
+  OF_NoVariableType = 1 << 5,
+  OF_NoVoidParameter = 1 << 6,
+  OF_NoTypeDescription = 1 << 7,
 };
 
 // Types
@@ -748,10 +750,18 @@ struct DEMANGLE_ABI VariableSymbolNode : public SymbolNode {
     return N->kind() == NodeKind::VariableSymbol;
   }
 
+  virtual bool shouldOutputName(OutputFlags Flags) const;
+
   StorageClass SC = StorageClass::None;
   TypeNode *Type = nullptr;
 };
 
+struct DEMANGLE_ABI TypeSymbolNode : public VariableSymbolNode {
+  using VariableSymbolNode::VariableSymbolNode;
+
+  bool shouldOutputName(OutputFlags Flags) const override;
+};
+
 struct DEMANGLE_ABI FunctionSymbolNode : public SymbolNode {
   FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {}
 
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index 769dbd4f2eb6e..1bb98d9e63744 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -409,12 +409,11 @@ static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,
   return synthesizeQualifiedName(Arena, Id);
 }
 
-static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena,
-                                              TypeNode *Type,
-                                              std::string_view VariableName) {
-  VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();
+static VariableSymbolNode *synthesizeType(ArenaAllocator &Arena, TypeNode *Type,
+                                          std::string_view Description) {
+  TypeSymbolNode *VSN = Arena.alloc<TypeSymbolNode>();
   VSN->Type = Type;
-  VSN->Name = synthesizeQualifiedName(Arena, VariableName);
+  VSN->Name = synthesizeQualifiedName(Arena, Description);
   return VSN;
 }
 
@@ -528,7 +527,7 @@ SymbolNode *Demangler::demangleSpecialIntrinsic(std::string_view &MangledName) {
       break;
     if (!MangledName.empty())
       break;
-    return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'");
+    return synthesizeType(Arena, T, "`RTTI Type Descriptor'");
   }
   case SpecialIntrinsicKind::RttiBaseClassArray:
     return demangleUntypedVariable(Arena, MangledName,
@@ -873,7 +872,7 @@ SymbolNode *Demangler::demangleTypeinfoName(std::string_view &MangledName) {
     Error = true;
     return nullptr;
   }
-  return synthesizeVariable(Arena, T, "`RTTI Type Descriptor Name'");
+  return synthesizeType(Arena, T, "`RTTI Type Descriptor Name'");
 }
 
 // Parser entry point.
@@ -2542,6 +2541,12 @@ char *llvm::microsoftDemangle(std::string_view MangledName, size_t *NMangled,
     OF = OutputFlags(OF | OF_NoMemberType);
   if (Flags & MSDF_NoVariableType)
     OF = OutputFlags(OF | OF_NoVariableType);
+  if (Flags & MSDF_NoTagSpecifier)
+    OF = OutputFlags(OF | OF_NoTagSpecifier);
+  if (Flags & MSDF_NoVoidParameter)
+    OF = OutputFlags(OF | OF_NoVoidParameter);
+  if (Flags & MSDF_NoTypeDescription)
+    OF = OutputFlags(OF | OF_NoTypeDescription);
 
   int InternalStatus = demangle_success;
   char *Buf;
diff --git a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
index 17c6aab500049..9e20f12f3360d 100644
--- a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
@@ -422,7 +422,7 @@ void FunctionSignatureNode::outputPost(OutputBuffer &OB,
     OB << "(";
     if (Params)
       Params->output(OB, Flags);
-    else
+    else if (!(Flags & OF_NoVoidParameter))
       OB << "void";
 
     if (IsVariadic) {
@@ -483,7 +483,7 @@ void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
     // It needs to go inside the parentheses.
     const FunctionSignatureNode *Sig =
         static_cast<const FunctionSignatureNode *>(Pointee);
-    Sig->outputPre(OB, OF_NoCallingConvention);
+    Sig->outputPre(OB, Flags);
   } else
     Pointee->outputPre(OB, Flags);
 
@@ -498,8 +498,10 @@ void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
     OB << "(";
     const FunctionSignatureNode *Sig =
         static_cast<const FunctionSignatureNode *>(Pointee);
-    outputCallingConvention(OB, Sig->CallConvention);
-    OB << " ";
+    if (!(Flags & OF_NoCallingConvention)) {
+      outputCallingConvention(OB, Sig->CallConvention);
+      OB << " ";
+    }
   }
 
   if (ClassParent) {
@@ -623,15 +625,24 @@ void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
   if (!(Flags & OF_NoMemberType) && IsStatic)
     OB << "static ";
 
-  if (!(Flags & OF_NoVariableType) && Type) {
+  if (!(Flags & OF_NoVariableType) && Type)
     Type->outputPre(OB, Flags);
+  if (shouldOutputName(Flags)) {
     outputSpaceIfNecessary(OB);
+    Name->output(OB, Flags);
   }
-  Name->output(OB, Flags);
   if (!(Flags & OF_NoVariableType) && Type)
     Type->outputPost(OB, Flags);
 }
 
+bool VariableSymbolNode::shouldOutputName(OutputFlags Flags) const {
+  return true;
+}
+
+bool TypeSymbolNode::shouldOutputName(OutputFlags Flags) const {
+  return !(Flags & OF_NoTypeDescription);
+}
+
 void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
   Identifier->output(OB, Flags);
 }
diff --git a/llvm/unittests/Demangle/CMakeLists.txt b/llvm/unittests/Demangle/CMakeLists.txt
index 105af816e2ca0..02153d2d63a50 100644
--- a/llvm/unittests/Demangle/CMakeLists.txt
+++ b/llvm/unittests/Demangle/CMakeLists.txt
@@ -7,6 +7,7 @@ add_llvm_unittest(DemangleTests
   DemangleTest.cpp
   DLangDemangleTest.cpp
   ItaniumDemangleTest.cpp
+  MicrosoftDemangleTest.cpp
   OutputBufferTest.cpp
   PartialDemangleTest.cpp
   RustDemangleTest.cpp
diff --git a/llvm/unittests/Demangle/MicrosoftDemangleTest.cpp b/llvm/unittests/Demangle/MicrosoftDemangleTest.cpp
new file mode 100644
index 0000000000000..e7aac305d52f9
--- /dev/null
+++ b/llvm/unittests/Demangle/MicrosoftDemangleTest.cpp
@@ -0,0 +1,318 @@
+//===-- MicrosoftDemangleTest.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/Demangle.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+#include <string>
+#include <string_view>
+
+using namespace llvm;
+
+namespace {
+std::string microsoftDemangleString(std::string_view MangledName,
+                                    MSDemangleFlags Flags) {
+  char *Demangled = microsoftDemangle(MangledName, nullptr, nullptr, Flags);
+  if (!Demangled)
+    return std::string(MangledName);
+  std::string Result(Demangled);
+  std::free(Demangled);
+  return Result;
+}
+} // namespace
+
+TEST(MicrosoftDemangle, demangleFunction) {
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXXZ", MSDF_None),
+            "void __cdecl foo(void)");
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXXZ", MSDF_NoReturnType),
+            "__cdecl foo(void)");
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXXZ", MSDF_NoCallingConvention),
+            "void foo(void)");
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXXZ", MSDF_NoVoidParameter),
+            "void __cdecl foo()");
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXXZ",
+                                    MSDemangleFlags(MSDF_NoCallingConvention |
+                                                    MSDF_NoReturnType |
+                                                    MSDF_NoVoidParameter)),
+            "foo()");
+}
+
+TEST(MicrosoftDemangle, demangleFunctionWithParameters) {
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXHH at Z", MSDF_None),
+            "void __cdecl foo(int, int)");
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXHH at Z", MSDF_NoReturnType),
+            "__cdecl foo(int, int)");
+  EXPECT_EQ(microsoftDemangleString("?foo@@YAXHH at Z", MSDF_NoCallingConvention),
+            "void foo(int, int)");
+  EXPECT_EQ(microsoftDemangleString(
+                "?foo@@YAXHH at Z",
+                MSDemangleFlags(MSDF_NoReturnType | MSDF_NoCallingConvention)),
+            "foo(int, int)");
+}
+
+TEST(MicrosoftDemangle, demangleMethod) {
+  EXPECT_EQ(microsoftDemangleString("?method at Struct@@QEAAXXZ", MSDF_None),
+            "public: void __cdecl Struct::method(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?method at Struct@@QEAAXXZ", MSDF_NoReturnType),
+      "public: __cdecl Struct::method(void)");
+  EXPECT_EQ(microsoftDemangleString("?method at Struct@@QEAAXXZ",
+                                    MSDF_NoCallingConvention),
+            "public: void Struct::method(void)");
+  EXPECT_EQ(microsoftDemangleString("?method at Struct@@QEAAXXZ",
+                                    MSDF_NoAccessSpecifier),
+            "void __cdecl Struct::method(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?method at Struct@@QEAAXXZ", MSDF_NoVoidParameter),
+      "public: void __cdecl Struct::method()");
+  EXPECT_EQ(
+      microsoftDemangleString(
+          "?method at Struct@@QEAAXXZ",
+          MSDemangleFlags(MSDF_NoCallingConvention | MSDF_NoAccessSpecifier |
+                          MSDF_NoReturnType | MSDF_NoVoidParameter)),
+      "Struct::method()");
+  EXPECT_EQ(
+      microsoftDemangleString("?privateMethod at Struct@@AEAAXXZ", MSDF_None),
+      "private: void __cdecl Struct::privateMethod(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?protectedMethod at Struct@@IEAAXXZ", MSDF_None),
+      "protected: void __cdecl Struct::protectedMethod(void)");
+}
+
+TEST(MicrosoftDemangle, demangleConstMethod) {
+  EXPECT_EQ(microsoftDemangleString("?constMethod at Struct@@QEBAXXZ", MSDF_None),
+            "public: void __cdecl Struct::constMethod(void) const");
+  EXPECT_EQ(microsoftDemangleString("?constMethod at Struct@@QEBAXXZ",
+                                    MSDF_NoReturnType),
+            "public: __cdecl Struct::constMethod(void) const");
+  EXPECT_EQ(microsoftDemangleString("?constMethod at Struct@@QEBAXXZ",
+                                    MSDF_NoCallingConvention),
+            "public: void Struct::constMethod(void) const");
+  EXPECT_EQ(microsoftDemangleString("?constMethod at Struct@@QEBAXXZ",
+                                    MSDF_NoVoidParameter),
+            "public: void __cdecl Struct::constMethod() const");
+  EXPECT_EQ(microsoftDemangleString("?constMethod at Struct@@QEBAXXZ",
+                                    MSDemangleFlags(MSDF_NoReturnType |
+                                                    MSDF_NoCallingConvention |
+                                                    MSDF_NoVoidParameter)),
+            "public: Struct::constMethod() const");
+}
+
+TEST(MicrosoftDemangle, demangleVirtualMethod) {
+  EXPECT_EQ(microsoftDemangleString("?vfunc at Base@@UEAAXXZ", MSDF_None),
+            "public: virtual void __cdecl Base::vfunc(void)");
+  EXPECT_EQ(microsoftDemangleString("?vfunc at Base@@UEAAXXZ", MSDF_NoReturnType),
+            "public: virtual __cdecl Base::vfunc(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?vfunc at Base@@UEAAXXZ", MSDF_NoAccessSpecifier),
+      "virtual void __cdecl Base::vfunc(void)");
+  EXPECT_EQ(microsoftDemangleString(
+                "?vfunc at Base@@UEAAXXZ",
+                MSDemangleFlags(MSDF_NoReturnType | MSDF_NoAccessSpecifier)),
+            "virtual __cdecl Base::vfunc(void)");
+}
+
+TEST(MicrosoftDemangle, demangleStaticMethod) {
+  EXPECT_EQ(microsoftDemangleString("?staticMethod at Struct@@SAXXZ", MSDF_None),
+            "public: static void __cdecl Struct::staticMethod(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?staticMethod at Struct@@SAXXZ", MSDF_NoReturnType),
+      "public: static __cdecl Struct::staticMethod(void)");
+  EXPECT_EQ(microsoftDemangleString("?staticMethod at Struct@@SAXXZ",
+                                    MSDF_NoAccessSpecifier),
+            "static void __cdecl Struct::staticMethod(void)");
+  EXPECT_EQ(microsoftDemangleString("?staticMethod at Struct@@SAXXZ",
+                                    MSDF_NoCallingConvention),
+            "public: static void Struct::staticMethod(void)");
+  EXPECT_EQ(microsoftDemangleString("?staticMethod at Struct@@SAXXZ",
+                                    MSDemangleFlags(MSDF_NoReturnType |
+                                                    MSDF_NoAccessSpecifier |
+                                                    MSDF_NoCallingConvention)),
+            "static Struct::staticMethod(void)");
+}
+
+TEST(MicrosoftDemangle, demangleConstructor) {
+  EXPECT_EQ(microsoftDemangleString("??0Animal@@QEAA at XZ", MSDF_None),
+            "public: __cdecl Animal::Animal(void)");
+  EXPECT_EQ(microsoftDemangleString("??0Animal@@QEAA at XZ", MSDF_NoReturnType),
+            "public: __cdecl Animal::Animal(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("??0Animal@@QEAA at XZ", MSDF_NoCallingConvention),
+      "public: Animal::Animal(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("??0Animal@@QEAA at XZ", MSDF_NoAccessSpecifier),
+      "__cdecl Animal::Animal(void)");
+  EXPECT_EQ(microsoftDemangleString("??0Animal@@QEAA at XZ", MSDF_NoVoidParameter),
+            "public: __cdecl Animal::Animal()");
+  EXPECT_EQ(
+      microsoftDemangleString(
+          "??0Animal@@QEAA at XZ",
+          MSDemangleFlags(MSDF_NoCallingConvention | MSDF_NoAccessSpecifier |
+                          MSDF_NoReturnType | MSDF_NoVoidParameter)),
+      "Animal::Animal()");
+}
+
+TEST(MicrosoftDemangle, demangleDestructor) {
+  EXPECT_EQ(microsoftDemangleString("??1Animal@@QEAA at XZ", MSDF_None),
+            "public: __cdecl Animal::~Animal(void)");
+  EXPECT_EQ(microsoftDemangleString("??1Animal@@QEAA at XZ", MSDF_NoReturnType),
+            "public: __cdecl Animal::~Animal(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("??1Animal@@QEAA at XZ", MSDF_NoCallingConvention),
+      "public: Animal::~Animal(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("??1Animal@@QEAA at XZ", MSDF_NoAccessSpecifier),
+      "__cdecl Animal::~Animal(void)");
+  EXPECT_EQ(microsoftDemangleString("??1Animal@@QEAA at XZ", MSDF_NoVoidParameter),
+            "public: __cdecl Animal::~Animal()");
+  EXPECT_EQ(
+      microsoftDemangleString(
+          "??1Animal@@QEAA at XZ",
+          MSDemangleFlags(MSDF_NoCallingConvention | MSDF_NoAccessSpecifier |
+                          MSDF_NoReturnType | MSDF_NoVoidParameter)),
+      "Animal::~Animal()");
+}
+
+TEST(MicrosoftDemangle, demangleOperatorPlus) {
+  EXPECT_EQ(microsoftDemangleString("??HInt@@QEAAHH at Z", MSDF_None),
+            "public: int __cdecl Int::operator+(int)");
+  EXPECT_EQ(microsoftDemangleString("??HInt@@QEAAHH at Z", MSDF_NoReturnType),
+            "public: __cdecl Int::operator+(int)");
+  EXPECT_EQ(
+      microsoftDemangleString("??HInt@@QEAAHH at Z", MSDF_NoCallingConvention),
+      "public: int Int::operator+(int)");
+  EXPECT_EQ(microsoftDemangleString(
+                "??HInt@@QEAAHH at Z",
+                MSDemangleFlags(MSDF_NoReturnType | MSDF_NoCallingConvention)),
+            "public: Int::operator+(int)");
+}
+
+TEST(MicrosoftDemangle, demangleCopyOperator) {
+  EXPECT_EQ(microsoftDemangleString("??0Dog@@QEAA at AEBU0@@Z", MSDF_None),
+            "public: __cdecl Dog::Dog(struct Dog const &)");
+  EXPECT_EQ(microsoftDemangleString("??0Dog@@QEAA at AEBU0@@Z", MSDF_NoReturnType),
+            "public: __cdecl Dog::Dog(struct Dog const &)");
+  EXPECT_EQ(microsoftDemangleString("??0Dog@@QEAA at AEBU0@@Z",
+                                    MSDF_NoCallingConvention),
+            "public: Dog::Dog(struct Dog const &)");
+  EXPECT_EQ(
+      microsoftDemangleString("??0Dog@@QEAA at AEBU0@@Z", MSDF_NoAccessSpecifier),
+      "__cdecl Dog::Dog(struct Dog const &)");
+  EXPECT_EQ(
+      microsoftDemangleString("??0Dog@@QEAA at AEBU0@@Z", MSDF_NoTagSpecifier),
+      "public: __cdecl Dog::Dog(Dog const &)");
+  EXPECT_EQ(microsoftDemangleString("??0Dog@@QEAA at AEBU0@@Z",
+                                    MSDemangleFlags(MSDF_NoCallingConvention |
+                                                    MSDF_NoAccessSpecifier |
+                                                    MSDF_NoTagSpecifier)),
+            "Dog::Dog(Dog const &)");
+}
+
+TEST(MicrosoftDemangle, demangleAssignmentOperator) {
+  EXPECT_EQ(microsoftDemangleString("??4Dog@@QEAAAEAU0 at AEBU0@@Z", MSDF_None),
+            "public: struct Dog & __cdecl Dog::operator=(struct Dog const &)");
+  EXPECT_EQ(
+      microsoftDemangleString("??4Dog@@QEAAAEAU0 at AEBU0@@Z", MSDF_NoReturnType),
+      "public: __cdecl Dog::operator=(struct Dog const &)");
+  EXPECT_EQ(microsoftDemangleString("??4Dog@@QEAAAEAU0 at AEBU0@@Z",
+                                    MSDF_NoCallingConvention),
+            "public: struct Dog & Dog::operator=(struct Dog const &)");
+  EXPECT_EQ(microsoftDemangleString("??4Dog@@QEAAAEAU0 at AEBU0@@Z",
+                                    MSDF_NoAccessSpecifier),
+            "struct Dog & __cdecl Dog::operator=(struct Dog const &)");
+  EXPECT_EQ(microsoftDemangleString("??4Dog@@QEAAAEAU0 at AEBU0@@Z",
+                                    MSDF_NoTagSpecifier),
+            "public: Dog & __cdecl Dog::operator=(Dog const &)");
+  EXPECT_EQ(microsoftDemangleString(
+                "??4Dog@@QEAAAEAU0 at AEBU0@@Z",
+                MSDemangleFlags(MSDF_NoReturnType | MSDF_NoCallingConvention |
+                                MSDF_NoAccessSpecifier | MSDF_NoTagSpecifier)),
+            "Dog::operator=(Dog const &)");
+}
+
+TEST(MicrosoftDemangle, demangleType) {
+  EXPECT_EQ(microsoftDemangleString(".?AUStruct@@", MSDF_None),
+            "struct Struct `RTTI Type Descriptor Name'");
+  EXPECT_EQ(microsoftDemangleString(".?AUStruct@@", MSDF_NoTagSpecifier),
+            "Struct `RTTI Type Descriptor Name'");
+  EXPECT_EQ(microsoftDemangleString(".?AUStruct@@", MSDF_NoTypeDescription),
+            "struct Struct");
+  EXPECT_EQ(microsoftDemangleString(
+                ".?AUStruct@@",
+                MSDemangleFlags(MSDF_NoTagSpecifier | MSDF_NoTypeDescription)),
+            "Struct");
+}
+
+TEST(MicrosoftDemangle, demangleVariable) {
+  EXPECT_EQ(microsoftDemangleString("?globalVar@@3HA", MSDF_None),
+            "int globalVar");
+  EXPECT_EQ(microsoftDemangleString("?globalVar@@3HA", MSDF_NoVariableType),
+            "globalVar");
+  // This flag should not impact variables
+  EXPECT_EQ(microsoftDemangleString("?globalVar@@3HA", MSDF_NoTypeDescription),
+            "int globalVar");
+}
+
+TEST(MicrosoftDemangle, demangleMemberVariable) {
+  EXPECT_EQ(microsoftDemangleString("?var at Struct@@2HA", MSDF_None),
+            "public: static int Struct::var");
+  EXPECT_EQ(microsoftDemangleString("?var at Struct@@2HA", MSDF_NoVariableType),
+            "public: static Struct::var");
+  EXPECT_EQ(microsoftDemangleString("?var at Struct@@2HA", MSDF_NoAccessSpecifier),
+            "static int Struct::var");
+  EXPECT_EQ(microsoftDemangleString("?var at Struct@@2HA", MSDF_NoMemberType),
+            "public: int Struct::var");
+  EXPECT_EQ(microsoftDemangleString("?var at Struct@@2HA",
+                                    MSDemangleFlags(MSDF_NoAccessSpecifier |
+                                                    MSDF_NoVariableType |
+                                                    MSDF_NoMemberType)),
+            "Struct::var");
+}
+
+TEST(MicrosoftDemangle, demangleIndirectVariables) {
+  EXPECT_EQ(microsoftDemangleString("?ptr@@3PEAHA", MSDF_None), "int *ptr");
+  EXPECT_EQ(microsoftDemangleString("?ptr@@3PEAHA", MSDF_NoVariableType),
+            "ptr");
+  EXPECT_EQ(microsoftDemangleString("?ptrConst@@3PEBHA", MSDF_None),
+            "int const *ptrConst");
+  EXPECT_EQ(microsoftDemangleString("?ptrPtr@@3PEAPEAHA", MSDF_None),
+            "int **ptrPtr");
+  EXPECT_EQ(microsoftDemangleString("?ref@@3AEAHA", MSDF_None), "int &ref");
+}
+
+TEST(MicrosoftDemangle, demangleFunctionPointers) {
+  EXPECT_EQ(microsoftDemangleString("?funcPtr@@3P6AXXZA", MSDF_None),
+            "void __cdecl (__cdecl *funcPtr)(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?funcPtr@@3P6AXXZA", MSDF_NoCallingConvention),
+      "void (*funcPtr)(void)");
+  EXPECT_EQ(microsoftDemangleString("?funcPtr@@3P6AXXZA", MSDF_NoVariableType),
+            "funcPtr");
+}
+
+TEST(MicrosoftDemangle, demangleNestedClass) {
+  EXPECT_EQ(microsoftDemangleString("?inner at Outer@@QEAAXXZ", MSDF_None),
+            "public: void __cdecl Outer::inner(void)");
+  EXPECT_EQ(microsoftDemangleString("?inner at Outer@@QEAAXXZ", MSDF_NoReturnType),
+            "public: __cdecl Outer::inner(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?inner at Outer@@QEAAXXZ", MSDF_NoAccessSpecifier),
+      "void __cdecl Outer::inner(void)");
+  EXPECT_EQ(microsoftDemangleString(
+                "?inner at Outer@@QEAAXXZ",
+                MSDemangleFlags(MSDF_NoReturnType | MSDF_NoAccessSpecifier)),
+            "__cdecl Outer::inner(void)");
+}
+
+TEST(MicrosoftDemangle, demangleStdcallFunction) {
+  EXPECT_EQ(microsoftDemangleString("?stdcallFunc@@YGXXZ", MSDF_None),
+            "void __stdcall stdcallFunc(void)");
+  EXPECT_EQ(
+      microsoftDemangleString("?stdcallFunc@@YGXXZ", MSDF_NoCallingConvention),
+      "void stdcallFunc(void)");
+}



More information about the llvm-commits mailing list