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

Fred Tingaud via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 08:57:57 PDT 2026


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

The goal for us is to be able to demangle Microsoft mangled function names toward something that reads more like AST function names and Itanium demangled names. All defaults remain the same and no existing code or tool user should be impacted by the change.

* 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

>From 6abd8c5197a056b9c17fe93e219b19802adf92fc 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  |  21 +-
 llvm/unittests/Demangle/CMakeLists.txt        |   1 +
 .../Demangle/MicrosoftDemangleTest.cpp        | 318 ++++++++++++++++++
 6 files changed, 366 insertions(+), 18 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..5fa605c726e5f 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) {
@@ -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..bc5d4edb07de8
--- /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 *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