2018-04-13 04:41:38 +08:00
|
|
|
//===----------------------- PartialDemangleTest.cpp ----------------------===//
|
|
|
|
//
|
2019-01-19 18:56:40 +08:00
|
|
|
// 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
|
2018-04-13 04:41:38 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "llvm/Demangle/Demangle.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
struct ChoppedName {
|
|
|
|
const char *Mangled;
|
|
|
|
const char *ContextName, *BaseName, *ReturnType, *Params;
|
|
|
|
};
|
|
|
|
|
|
|
|
static ChoppedName NamesToTest[] = {
|
|
|
|
{"_Z1fv", "", "f", "", "()"},
|
|
|
|
{"_ZN1a1b1cIiiiEEvm", "a::b", "c", "void", "(unsigned long)"},
|
|
|
|
{"_ZZ5OuterIiEivEN5Inner12inner_memberEv",
|
|
|
|
"int Outer<int>()::Inner", "inner_member", "", "()"},
|
|
|
|
{"_Z1fIiEPFvvEv", "", "f", "void (*)()", "()"},
|
|
|
|
{"_ZN1S1fIiEEvv", "S", "f", "void", "()"},
|
|
|
|
|
|
|
|
// Call operator for a lambda in f().
|
|
|
|
{"_ZZ1fvENK3$_0clEi", "f()::$_0", "operator()", "", "(int)"},
|
|
|
|
|
|
|
|
// A call operator for a lambda in a lambda in f().
|
|
|
|
{"_ZZZ1fvENK3$_0clEvENKUlvE_clEv",
|
|
|
|
"f()::$_0::operator()() const::'lambda'()", "operator()", "", "()"},
|
|
|
|
|
|
|
|
{"_ZZN1S1fEiiEd0_NKUlvE_clEv",
|
|
|
|
"S::f(int, int)::'lambda'()", "operator()", "", "()"},
|
|
|
|
|
|
|
|
{"_ZN1Scv7MuncherIJDpPT_EEIJFivEA_iEEEv",
|
|
|
|
"S", "operator Muncher<int (*)(), int (*) []>", "", "()"},
|
|
|
|
|
|
|
|
// Attributes.
|
|
|
|
{"_ZN5test4IdE1fEUa9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEi",
|
|
|
|
"test4<double>", "f", "", "(int)"},
|
|
|
|
{"_ZN1SC2B8ctor_tagEv", "S", "S", "", "()"},
|
|
|
|
{"_ZN1S1fB4MERPIiEEvv", "S", "f", "void", "()"},
|
|
|
|
|
|
|
|
{"_ZNSsC1EmcRKSaIcE",
|
|
|
|
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
|
|
|
|
"basic_string", "", "(unsigned long, char, std::allocator<char> const&)"},
|
|
|
|
{"_ZNSsixEm", "std::string", "operator[]", "", "(unsigned long)"},
|
|
|
|
{"_ZSt17__throw_bad_allocv", "std", "__throw_bad_alloc", "", "()"},
|
|
|
|
|
|
|
|
{"_ZN1AI1BEC2Ev", "A<B>", "A", "", "()"},
|
|
|
|
{"_ZN1AI1BED2Ev", "A<B>", "~A", "", "()"},
|
|
|
|
{"_ZN1AI1BECI24BaseEi", "A<B>", "A", "", "(int)"},
|
|
|
|
{"_ZNKR1AI1BE1fIiEEiv", "A<B>", "f", "int", "()"},
|
|
|
|
|
|
|
|
{"_ZN1SIJicfEE3mfnIJjcdEEEvicfDpT_", "S<int, char, float>",
|
|
|
|
"mfn", "void", "(int, char, float, unsigned int, char, double)"},
|
|
|
|
};
|
|
|
|
|
2018-08-14 00:37:47 +08:00
|
|
|
TEST(PartialDemanglerTest, TestNameChopping) {
|
2018-04-13 04:41:38 +08:00
|
|
|
size_t Size = 1;
|
|
|
|
char *Buf = static_cast<char *>(std::malloc(Size));
|
|
|
|
|
|
|
|
llvm::ItaniumPartialDemangler D;
|
|
|
|
|
|
|
|
for (ChoppedName &N : NamesToTest) {
|
|
|
|
EXPECT_FALSE(D.partialDemangle(N.Mangled));
|
|
|
|
EXPECT_TRUE(D.isFunction());
|
|
|
|
EXPECT_FALSE(D.isData());
|
|
|
|
EXPECT_FALSE(D.isSpecialName());
|
|
|
|
|
|
|
|
Buf = D.getFunctionDeclContextName(Buf, &Size);
|
|
|
|
EXPECT_STREQ(Buf, N.ContextName);
|
|
|
|
|
|
|
|
Buf = D.getFunctionBaseName(Buf, &Size);
|
|
|
|
EXPECT_STREQ(Buf, N.BaseName);
|
|
|
|
|
|
|
|
Buf = D.getFunctionReturnType(Buf, &Size);
|
|
|
|
EXPECT_STREQ(Buf, N.ReturnType);
|
|
|
|
|
|
|
|
Buf = D.getFunctionParameters(Buf, &Size);
|
|
|
|
EXPECT_STREQ(Buf, N.Params);
|
|
|
|
}
|
2018-04-13 06:54:47 +08:00
|
|
|
|
|
|
|
std::free(Buf);
|
2018-04-13 04:41:38 +08:00
|
|
|
}
|
|
|
|
|
2018-08-14 00:37:47 +08:00
|
|
|
TEST(PartialDemanglerTest, TestNameMeta) {
|
2018-04-13 04:41:38 +08:00
|
|
|
llvm::ItaniumPartialDemangler Demangler;
|
|
|
|
|
|
|
|
EXPECT_FALSE(Demangler.partialDemangle("_ZNK1f1gEv"));
|
|
|
|
EXPECT_TRUE(Demangler.isFunction());
|
|
|
|
EXPECT_TRUE(Demangler.hasFunctionQualifiers());
|
|
|
|
EXPECT_FALSE(Demangler.isSpecialName());
|
|
|
|
EXPECT_FALSE(Demangler.isData());
|
|
|
|
|
|
|
|
EXPECT_FALSE(Demangler.partialDemangle("_Z1fv"));
|
|
|
|
EXPECT_FALSE(Demangler.hasFunctionQualifiers());
|
|
|
|
|
|
|
|
EXPECT_FALSE(Demangler.partialDemangle("_ZTV1S"));
|
|
|
|
EXPECT_TRUE(Demangler.isSpecialName());
|
|
|
|
EXPECT_FALSE(Demangler.isData());
|
|
|
|
EXPECT_FALSE(Demangler.isFunction());
|
|
|
|
|
|
|
|
EXPECT_FALSE(Demangler.partialDemangle("_ZN1aDC1a1b1cEE"));
|
|
|
|
EXPECT_FALSE(Demangler.isFunction());
|
|
|
|
EXPECT_FALSE(Demangler.isSpecialName());
|
|
|
|
EXPECT_TRUE(Demangler.isData());
|
|
|
|
}
|
|
|
|
|
2018-05-24 14:57:57 +08:00
|
|
|
TEST(PartialDemanglerTest, TestCtorOrDtor) {
|
|
|
|
static const char *Pos[] = {
|
|
|
|
"_ZN1AC1Ev", // A::A()
|
|
|
|
"_ZN1AC1IiEET_", // A::A<int>(int)
|
|
|
|
"_ZN1AD2Ev", // A::~A()
|
|
|
|
"_ZN1BIiEC1IcEET_", // B<int>::B<char>(char)
|
|
|
|
"_ZN1AC1B1TEv", // A::A[abi:T]()
|
|
|
|
"_ZNSt1AD2Ev", // std::A::~A()
|
|
|
|
"_ZN2ns1AD1Ev", // ns::A::~A()
|
|
|
|
};
|
|
|
|
static const char *Neg[] = {
|
|
|
|
"_Z1fv",
|
|
|
|
"_ZN1A1gIiEEvT_", // void A::g<int>(int)
|
|
|
|
};
|
|
|
|
|
|
|
|
llvm::ItaniumPartialDemangler D;
|
|
|
|
for (const char *N : Pos) {
|
|
|
|
EXPECT_FALSE(D.partialDemangle(N));
|
|
|
|
EXPECT_TRUE(D.isCtorOrDtor());
|
|
|
|
}
|
|
|
|
for (const char *N : Neg) {
|
|
|
|
EXPECT_FALSE(D.partialDemangle(N));
|
|
|
|
EXPECT_FALSE(D.isCtorOrDtor());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-13 04:41:38 +08:00
|
|
|
TEST(PartialDemanglerTest, TestMisc) {
|
|
|
|
llvm::ItaniumPartialDemangler D1, D2;
|
|
|
|
|
|
|
|
EXPECT_FALSE(D1.partialDemangle("_Z1fv"));
|
|
|
|
EXPECT_FALSE(D2.partialDemangle("_Z1g"));
|
|
|
|
std::swap(D1, D2);
|
|
|
|
EXPECT_FALSE(D1.isFunction());
|
|
|
|
EXPECT_TRUE(D2.isFunction());
|
|
|
|
|
|
|
|
EXPECT_TRUE(D1.partialDemangle("Not a mangled name!"));
|
2018-08-09 06:38:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PartialDemanglerTest, TestPrintCases) {
|
|
|
|
llvm::ItaniumPartialDemangler D;
|
|
|
|
|
|
|
|
const size_t OriginalSize = 4;
|
|
|
|
char *Buf = static_cast<char *>(std::malloc(OriginalSize));
|
|
|
|
const char *OriginalBuf = Buf;
|
|
|
|
|
|
|
|
// Default success case: Result fits into the given buffer.
|
|
|
|
// Res points to Buf. N returns string size including null termination.
|
|
|
|
{
|
|
|
|
EXPECT_FALSE(D.partialDemangle("_ZN1a1bEv"));
|
|
|
|
|
|
|
|
size_t N = OriginalSize;
|
|
|
|
char *Res = D.getFunctionDeclContextName(Buf, &N);
|
|
|
|
EXPECT_STREQ("a", Res);
|
|
|
|
EXPECT_EQ(OriginalBuf, Res);
|
|
|
|
EXPECT_EQ(strlen(Res) + 1, N);
|
|
|
|
}
|
2018-04-13 04:41:38 +08:00
|
|
|
|
2018-08-09 06:38:23 +08:00
|
|
|
// Realloc success case: Result does not fit into the given buffer.
|
|
|
|
// Res points to the new or extended buffer. N returns string size
|
|
|
|
// including null termination. Buf was extended or freed.
|
|
|
|
{
|
|
|
|
EXPECT_FALSE(D.partialDemangle("_ZN1a1b1cIiiiEEvm"));
|
|
|
|
|
|
|
|
size_t N = OriginalSize;
|
|
|
|
char *Res = D.finishDemangle(Buf, &N);
|
|
|
|
EXPECT_STREQ("void a::b::c<int, int, int>(unsigned long)", Res);
|
|
|
|
EXPECT_EQ(strlen(Res) + 1, N);
|
|
|
|
Buf = Res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Failure case: a::c is not a function.
|
|
|
|
// Res is nullptr. N remains unchanged.
|
|
|
|
{
|
|
|
|
EXPECT_FALSE(D.partialDemangle("_ZN1a1cE"));
|
|
|
|
|
|
|
|
size_t N = OriginalSize;
|
|
|
|
char *Res = D.getFunctionName(Buf, &N);
|
|
|
|
EXPECT_EQ(nullptr, Res);
|
|
|
|
EXPECT_EQ(OriginalSize, N);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::free(Buf);
|
2018-04-13 04:41:38 +08:00
|
|
|
}
|