6#include "clang/Tooling/Tooling.h"
7#include "clang/Tooling/CommonOptionsParser.h"
9#include <gtest/gtest.h>
17static llvm::cl::OptionCategory MyToolCategory(
"my-tool options");
44class MyPrinter :
public clang::ast_matchers::MatchFinder::MatchCallback {
47 clang::MangleContext *m_mangle_ctx;
48 std::vector<std::string > mangle_list;
50 MyPrinter() : m_mangle_ctx(nullptr) {
56 m_mangle_ctx =
nullptr;
60 virtual void run(
const clang::ast_matchers::MatchFinder::MatchResult &Result) {
62 clang::ASTContext *ctx = Result.Context;
66 m_mangle_ctx = ctx->createMangleContext();
72 llvm::raw_string_ostream raw(name);
78 if (
const auto decl = Result.Nodes.getNodeAs<clang::Decl>(
"decl")) {
79 name = decl->getDeclKindName();
80 if (name.compare(
"LinkageSpec") == 0
81 || name.compare(
"Namespace") == 0
82 || name.compare(
"ParmVar") == 0
83 || name.compare(
"Empty") == 0
84 || name.compare(
"TranslationUnit") == 0
85 || name.compare(
"Typedef") == 0
92 if (
const auto decl = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(
"decl")) {
95 if (decl->isReferenced() || decl->isImplicit() || decl->isClass()) {
100 if (
const auto decl = Result.Nodes.getNodeAs<clang::CXXDestructorDecl>(
"decl")) {
108 }
else if (
const auto decl = Result.Nodes.getNodeAs<clang::CXXConstructorDecl>(
"decl")) {
118 }
else if (
const auto decl = Result.Nodes.getNodeAs<clang::FunctionDecl>(
"decl")) {
119 if (m_mangle_ctx->shouldMangleCXXName(decl)) {
120 m_mangle_ctx->mangleCXXName(decl, raw);
122 if (name.compare(
"_Znwm") == 0
123 || name.compare(
"_Znam") == 0
124 || name.compare(
"_ZdlPv") == 0
125 || name.compare(
"_ZdaPv") == 0
126 || name.rfind(
"SEOS_") != std::string::npos
127 || name.rfind(
"SEOS0_") != std::string::npos
128 || name.rfind(
"SERKS_") != std::string::npos
129 || name.rfind(
"SERKS0_") != std::string::npos
134 name = decl->getNameAsString();
137 mangle_list.push_back(name);
139 }
else if (
const auto decl = Result.Nodes.getNodeAs<clang::VarDecl>(
"decl")) {
140 if (m_mangle_ctx->shouldMangleCXXName(decl)) {
141 m_mangle_ctx->mangleCXXName(decl, raw);
143 name = decl->getNameAsString();
146 mangle_list.push_back(name);
148 }
else if (
const auto decl = Result.Nodes.getNodeAs<clang::FieldDecl>(
"decl")) {
149 if (m_mangle_ctx->shouldMangleCXXName(decl)) {
150 m_mangle_ctx->mangleCXXName(decl, raw);
152 name = decl->getNameAsString();
155 mangle_list.push_back(name);
157 }
else if (
const auto decl = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(
"decl")) {
162 }
else if (
const auto decl = Result.Nodes.getNodeAs<clang::Decl>(
"decl")) {
168 for (
const auto &elem : Result.Nodes.getMap()) {
178const char * func_text = \
179 "int func(int arg, char, signed char, unsigned char);\n"
180 "int func(signed int arg, unsigned int arg2, signed short int arg3, unsigned short int arg4);\n"
181 "int func(const signed int arg, const unsigned int arg2);\n"
182 "int func(int &arg, int &&arg2, int *arg3); //, int **arg4, int **arg5, int ****arg6 \n"
183 "int func(const int &arg, const int &&arg2, const int *arg3); //, const int **arg4, const int **arg5, const int ****arg6 \n"
184 "void func(int arg, double arg2);\n"
185 "extern \"C\" int printf(const char * format, ...);\n"
186 "const int value_const=0;\n"
187 "namespace n { const int value_const=0; };\n"
189 "extern \"C\" int value_c;\n"
190 "namespace n { int value; };\n"
191 "class header_only;\n"
192 "class class_body{\n"
195 " virtual ~class_body(){};\n"
196 " void method_header();\n"
197 " void method_body(){};\n"
198 " static header_only * static_call(header_only *);"
201 "int func(int arg);\n"
204 " virtual void method_v();"
205 " virtual void method_v2()=0;"
206 " static void method_static();"
215std::vector <const char *> mangle_name = {
224 "_ZN1nL11value_constE",
228 "_ZN10class_body5fieldE",
229 "_ZN10class_body13method_headerEv",
230 "_ZN10class_body11method_bodyEv",
231 "_ZN10class_body11static_callEP11header_only",
233 "_ZN4name8ns_class6methodEv",
234 "_ZN4name8ns_class8method_vEv",
235 "_ZN4name8ns_class9method_v2Ev",
236 "_ZN4name8ns_class13method_staticEv",
243ATTR
int func1(
int arg,
char c1,
signed char c2,
unsigned char c3) {
249ATTR
int func2(
signed int arg,
unsigned int arg2,
signed short int arg3,
unsigned short int arg4) {
255ATTR
int func3(
int &arg,
int &&arg2,
int *arg3) {
261ATTR
int func4(
const int &arg,
const int &&arg2,
const int *arg3) {
267ATTR
void func5(
signed long long int arg,
double arg2) {
272 double func6(
signed long long int arg1,
const unsigned short arg2) {
278 float func7(
unsigned long long int arg1,
double arg2) {
284 ATTR
signed int value_const;
290 static ATTR
int * value_ptr;
301std::string toCXXProto(
const TermPtr term) {
303 int i1 = ns::value_const;
313 ObjType res_type = RunTime::BaseTypeFromString(
nullptr, term->m_type->m_text);
315 std::string cpp_prototype;
318 std::string name = &term->m_text[1];
320 bool is_static = (
isStaticName(name) && !term->isCall());
325 name = name.substr(2);
329 cpp_prototype +=
"namespace ";
330 cpp_prototype += name.substr(0, name.find(
"::"));
331 cpp_prototype +=
" { ";
333 name = name.substr(name.find(
"::") + 2);
337 if (is_static && !is_global) {
338 cpp_prototype +=
"static ";
341 cpp_prototype +=
toCXXType(res_type,
false);
342 cpp_prototype +=
" ";
344 if (term->m_type->m_ref) {
345 cpp_prototype +=
toCXXRef(term->m_type->m_ref->m_text);
346 cpp_prototype +=
" ";
350 cpp_prototype += name;
352 if (term->isCall()) {
354 cpp_prototype +=
"(";
355 for (
int i = 0; i < term->size(); i++) {
357 cpp_prototype +=
", ";
359 TermPtr arg = term->at(i).second;
362 LOG_RUNTIME(
"Type arg %d not defined '%s'", i, term->toString().c_str());
366 ObjType arg_type = RunTime::BaseTypeFromString(
nullptr, arg->m_type->m_text);
367 if (arg->m_type->m_ref) {
368 cpp_prototype +=
" ";
369 cpp_prototype +=
toCXXRef(arg->GetType()->m_ref->m_text);
371 if (arg->m_type->m_is_const) {
372 cpp_prototype +=
"const ";
374 cpp_prototype +=
toCXXType(arg_type,
false);
376 cpp_prototype +=
")";
378 if (term->m_is_const) {
379 cpp_prototype.insert(0,
" const");
383 if (term->m_is_const && !term->isCall()) {
385 cpp_prototype +=
"=\"\"";
387 cpp_prototype +=
"=L\"\"";
389 cpp_prototype +=
"=0";
391 cpp_prototype +=
"=nullptr";
395 if (term->m_is_const) {
396 cpp_prototype +=
"const ";
399 cpp_prototype += suffix;
400 cpp_prototype +=
";";
402 return cpp_prototype;
405std::string toCXXProto(std::string name) {
408 TermPtr term = Parser::ParseString(name,
nullptr);
410 return toCXXProto(term->Left());
504std::vector<std::string> GetMangledNames(
const std::string input_source) {
506 clang::CompilerInstance compilerInstance;
508 constexpr int COUNT = 3;
510 const char *argv[COUNT] = {
"",
"clang_mangled_names.cpp",
"--"};
512 auto OptionsParser = clang::tooling::CommonOptionsParser::create(argc, argv, MyToolCategory, llvm::cl::OneOrMore);
513 if (!OptionsParser) {
517 clang::tooling::ClangTool Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList());
519 Tool.mapVirtualFile(
"clang_mangled_names.cpp", clang::StringRef(input_source));
522 auto functionMatcher = clang::ast_matchers::decl(clang::ast_matchers::anything()).bind(
"decl");
524 clang::ast_matchers::MatchFinder Finder;
525 Finder.addMatcher(functionMatcher, &Printer);
527 if (0 != Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get())) {
535 return Printer.mangle_list;
538std::string GetMangledString(
const std::string_view source) {
539 std::vector<std::string> list = GetMangledNames(toCXXProto(std::string(source)));
540 if (list.size() != 1) {
541 LOG_RUNTIME(
"Source '%s' not a single mangled name!", source.begin());
546TEST(Class, MangledSimple) {
551 LLVMLoadLibraryPermanently(
nullptr);
553 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(
"printf"));
554 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(
"fopen"));
556 ASSERT_STREQ(
"signed int value_c;", toCXXProto(
"%value_c:Int32").c_str());
557 ASSERT_NO_THROW(mandled = GetMangledString(
"%value_c:Int32"));
558 ASSERT_STREQ(
"value_c", mandled.c_str());
559 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
562 ASSERT_STREQ(
"signed int func1(signed int, char, signed char, unsigned char);",
563 toCXXProto(
"%::func1(arg:Int32, arg:Int8, arg:Char, arg:Byte): Int32").c_str());
564 ASSERT_NO_THROW(mandled = GetMangledString(
"%::func1(arg:Int32, arg:Int8, arg:Char, arg:Byte): Int32"));
565 ASSERT_STREQ(
"_Z5func1icah", mandled.c_str());
566 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
569 ASSERT_STREQ(
"signed int func2(signed int, unsigned int, signed short, unsigned short);",
570 toCXXProto(
"%::func2(arg:Int32, arg2:DWord, arg3:Int16, arg4:Word): Int32").c_str());
571 ASSERT_NO_THROW(mandled = GetMangledString(
"%::func2(arg:Int32, arg2:DWord, arg3:Int16, arg4:Word): Int32"));
572 ASSERT_STREQ(
"_Z5func2ijst", mandled.c_str());
573 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
576 ASSERT_STREQ(
"void func5(signed long long int, double);",
577 toCXXProto(
"%::func5(arg:Int64, arg2:Double):None").c_str());
578 ASSERT_NO_THROW(mandled = GetMangledString(
"%::func5(arg:Int64, arg2:Double):None"));
579 ASSERT_STREQ(
"_Z5func5xd", mandled.c_str());
580 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
583 ASSERT_STREQ(
"namespace ns { double func6(signed long long int, const unsigned short); };",
584 toCXXProto(
"%::ns::func6(arg:Int64, arg2: Word^):Double").c_str());
585 ASSERT_NO_THROW(mandled = GetMangledString(
"%::ns::func6(arg:Int64, arg2:Word^):Double"));
586 ASSERT_STREQ(
"_ZN2ns5func6Ext", mandled.c_str());
587 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
590 ASSERT_STREQ(
"namespace ns { namespace ns { float func7(unsigned long long int, double); }; };",
591 toCXXProto(
"%ns::ns::func7(arg:DWord64, arg2:Double):Single").c_str());
592 ASSERT_NO_THROW(mandled = GetMangledString(
"%ns::ns::func7(arg:DWord64, arg2:Double):Single"));
593 ASSERT_STREQ(
"_ZN2ns2ns5func7Eyd", mandled.c_str());
594 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
597 ASSERT_STREQ(
"namespace ns { signed int value_const; };", toCXXProto(
"%::ns::value_const:Int32").c_str());
598 ASSERT_NO_THROW(mandled = GetMangledString(
"%::ns::value_const:Int32"));
599 ASSERT_STREQ(
"_ZN2ns11value_constE", mandled.c_str());
601 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
604 ASSERT_STREQ(
"signed int value_value;", toCXXProto(
"%value_value:Int32").c_str());
605 ASSERT_NO_THROW(mandled = GetMangledString(
"%value_value:Int32"));
606 ASSERT_STREQ(
"value_value", mandled.c_str());
607 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
609 name =
"%ns::value_ptr: &* Int32";
610 ASSERT_STREQ(
"namespace ns { static signed int * value_ptr; };", toCXXProto(name).c_str());
611 ASSERT_NO_THROW(mandled = GetMangledString(name)) << name;
612 ASSERT_STREQ(
"_ZN2nsL9value_ptrE", mandled.c_str());
615 ASSERT_FALSE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
631 static char static_field;
636 class_body(
int,
int *) {
639 virtual ~class_body() {
645 int method_body(
int arg) {
649 double method_body(
double arg) {
653 int method_body2(
int arg) {
657 virtual double method_virt() {
661 static float method_static() {
680 "static char static_field;"
684 " class_body(int, int *);"
686 " virtual ~class_body();"
688 " void method_body();"
690 " int method_body(int arg);"
692 " double method_body(double arg);"
694 " int method_body2(int arg);"
696 " virtual double method_virt();"
698 " static float method_static();"
702std::string FindMandledField(std::string source, std::vector<std::string> &list) {
705 TermPtr term = Parser::ParseString(source,
nullptr);
708 std::vector<std::string> names = GetMangledNames(toCXXProto(term->m_left));
709 if (names.size() != 1) {
710 LOG_RUNTIME(
"Source '%s' not a single mangled name!", source.c_str());
712 std::string mangled = names[0];
714 std::string search = term->m_left->m_text.substr(1);
716 search = search.substr(2);
720 std::string arg_types(
"E");
721 if (term->m_left->isCall()) {
722 arg_types += mangled.substr(mangled.find(search) + search.size());
725 for (
auto &elem : list) {
726 if (elem.find(search) != std::string::npos && (arg_types.empty() || elem.find(arg_types) != std::string::npos)) {
730 LOG_RUNTIME(
"Filed '%s' (%s)(%s) not found!", term->m_left->m_text.c_str(), search.c_str(), arg_types.c_str());
733template<
typename OUT,
typename IN>
734OUT ForceCast(IN in) {
745char class_body::static_field = 0;
747TEST(Class, MangledClass) {
753 data.method_body(0.0);
754 data.method_body2(0);
755 data.method_static();
758 std::vector<std::string> list;
761 LLVMLoadLibraryPermanently(
nullptr);
763 ASSERT_NO_THROW(list = GetMangledNames(cls));
764 ASSERT_EQ(8, list.size()) <<
Dump(list);
766 ASSERT_STREQ(
"void method_body();", toCXXProto(
"%method_body(): None").c_str());
767 ASSERT_NO_THROW(name = GetMangledString(
"%method_body(): None"));
768 ASSERT_STREQ(
"_Z11method_bodyv", name.c_str());
769 ASSERT_NO_THROW(name = FindMandledField(
"%method_body():None", list)) <<
Dump(list);
770 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name <<
"\n" <<
Dump(list);
772 ASSERT_STREQ(
"signed int method_body(signed int);", toCXXProto(
"%method_body(arg:Int32): Int32").c_str());
773 ASSERT_NO_THROW(name = GetMangledString(
"%method_body(arg:Int32): Int32"));
774 ASSERT_STREQ(
"_Z11method_bodyi", name.c_str());
775 ASSERT_NO_THROW(name = FindMandledField(
"%method_body(arg:Int32): Int32", list)) <<
Dump(list);
776 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name <<
"\n" <<
Dump(list);
778 ASSERT_STREQ(
"double method_body(double);", toCXXProto(
"%method_body(arg:Double): Double").c_str());
779 ASSERT_NO_THROW(name = GetMangledString(
"%method_body(arg:Double): Double"));
780 ASSERT_STREQ(
"_Z11method_bodyd", name.c_str());
781 ASSERT_NO_THROW(name = FindMandledField(
"%method_body(arg:Double): Double", list)) <<
Dump(list);
782 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name <<
"\n" <<
Dump(list);
787 ASSERT_STREQ(
"signed int method_body2(signed int);", toCXXProto(
"%method_body2(arg:Int32): Int32").c_str());
788 ASSERT_NO_THROW(name = GetMangledString(
"%method_body2(arg:Int32): Int32"));
789 ASSERT_STREQ(
"_Z12method_body2i", name.c_str());
790 ASSERT_NO_THROW(name = FindMandledField(
"%method_body2(arg:Int32): Int32", list)) <<
Dump(list);
791 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name <<
"\n" <<
Dump(list);
793 cast = ForceCast<void *>(&class_body::method_body2);
794 ASSERT_EQ(cast, LLVMSearchForAddressOfSymbol(name.c_str()));
796 ASSERT_STREQ(
"double method_virt();", toCXXProto(
"%method_virt(): Double").c_str());
797 ASSERT_NO_THROW(name = GetMangledString(
"%method_virt(): Double"));
798 ASSERT_STREQ(
"_Z11method_virtv", name.c_str());
799 ASSERT_NO_THROW(name = FindMandledField(
"%method_virt(): Double", list)) <<
Dump(list);
800 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name <<
"\n" <<
Dump(list);
819 ASSERT_STREQ(
"signed int static_field;", toCXXProto(
"%::static_field: Int32").c_str());
820 ASSERT_NO_THROW(name = GetMangledString(
"%::static_field: Int32"));
821 ASSERT_STREQ(
"static_field", name.c_str());
822 ASSERT_NO_THROW(name = FindMandledField(
"%::static_field: Int32", list)) <<
Dump(list);
823 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name <<
"\n" <<
Dump(list);
957void test_void_func() {
960const int test_void_val = 0;
962TEST(Class, Symbols) {
964 auto rt = RunTime::Init();
967 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(
"printf"));
968 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(
"fopen"));
970 EXPECT_FALSE(LLVMSearchForAddressOfSymbol(
"test_void_func"));
971 EXPECT_FALSE(LLVMSearchForAddressOfSymbol(
"test_void_val"));
973 LLVMAddSymbol(
"test_void_func", (
void *) &test_void_func);
974 LLVMAddSymbol(
"test_void_val", (
void *) &test_void_val);
976 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(
"test_void_func"));
977 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(
"test_void_val"));
979 EXPECT_EQ(&test_void_func, LLVMSearchForAddressOfSymbol(
"test_void_func"));
980 EXPECT_EQ(&test_void_val, LLVMSearchForAddressOfSymbol(
"test_void_val"));
#define LOG_RUNTIME(format,...)
#define ASSERT(condition)
bool isStringChar(ObjType t)
bool isStaticName(const std::string_view name)
bool isStringWide(ObjType t)
bool isArithmeticType(ObjType t)
bool isLocalName(const std::string_view name)
const char * toCXXType(ObjType type, bool int_bool)
bool isFieldName(const std::string_view name)
std::shared_ptr< Term > TermPtr
bool isGlobalScope(const std::string_view name)
const char * toCXXRef(const std::string_view ref)
bool isNativeName(const std::string_view name)
std::string Dump(const T &iterable)