1 //===------------------ ItaniumDemangleTest.cpp ---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Demangle/ItaniumDemangle.h"
10 #include "llvm/Support/Allocator.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 #include <cstdlib>
14 #include <vector>
15 
16 using namespace llvm;
17 using namespace llvm::itanium_demangle;
18 
19 namespace {
20 class TestAllocator {
21   BumpPtrAllocator Alloc;
22 
23 public:
reset()24   void reset() { Alloc.Reset(); }
25 
makeNode(Args &&...args)26   template <typename T, typename... Args> T *makeNode(Args &&... args) {
27     return new (Alloc.Allocate(sizeof(T), alignof(T)))
28         T(std::forward<Args>(args)...);
29   }
30 
allocateNodeArray(size_t sz)31   void *allocateNodeArray(size_t sz) {
32     return Alloc.Allocate(sizeof(Node *) * sz, alignof(Node *));
33   }
34 };
35 } // namespace
36 
37 namespace NodeMatcher {
38 // Make sure the node matchers provide constructor parameters. This is a
39 // compilation test.
40 template <typename NT> struct Ctor {
operator ()NodeMatcher::Ctor41   template <typename... Args> void operator()(Args &&...args) {
42     auto _ = NT(std::forward<Args>(args)...);
43   }
44 };
45 
Visit(const NT * Node)46 template <typename NT> void Visit(const NT *Node) { Node->match(Ctor<NT>{}); }
47 #define NOMATCHER(X)                                                           \
48   template <> void Visit<itanium_demangle::X>(const itanium_demangle::X *) {}
49 // Some nodes have no match member.
NOMATCHER(ForwardTemplateReference)50 NOMATCHER(ForwardTemplateReference)
51 #undef NOMATCHER
52 
53 void Visitor() {
54 #define NODE(X) Visit(static_cast<const itanium_demangle::X *>(nullptr));
55 #include "llvm/Demangle/ItaniumNodes.def"
56 }
57 } // namespace NodeMatcher
58 
59 // Verify Operator table is ordered
TEST(ItaniumDemangle,OperatorOrdering)60 TEST(ItaniumDemangle, OperatorOrdering) {
61   struct TestParser : AbstractManglingParser<TestParser, TestAllocator> {};
62   for (const auto *Op = &TestParser::Ops[0];
63        Op != &TestParser::Ops[TestParser::NumOps - 1]; Op++)
64     ASSERT_LT(Op[0], Op[1]);
65 }
66 
TEST(ItaniumDemangle,MethodOverride)67 TEST(ItaniumDemangle, MethodOverride) {
68   struct TestParser : AbstractManglingParser<TestParser, TestAllocator> {
69     std::vector<char> Types;
70 
71     TestParser(const char *Str)
72         : AbstractManglingParser(Str, Str + strlen(Str)) {}
73 
74     Node *parseType() {
75       Types.push_back(*First);
76       return AbstractManglingParser<TestParser, TestAllocator>::parseType();
77     }
78   };
79 
80   TestParser Parser("_Z1fIiEjl");
81   ASSERT_NE(nullptr, Parser.parse());
82   EXPECT_THAT(Parser.Types, testing::ElementsAre('i', 'j', 'l'));
83 }
84 
toString(OutputBuffer & OB)85 static std::string toString(OutputBuffer &OB) {
86   StringView SV = OB;
87   return {SV.begin(), SV.end()};
88 }
89 
TEST(ItaniumDemangle,HalfType)90 TEST(ItaniumDemangle, HalfType) {
91   struct TestParser : AbstractManglingParser<TestParser, TestAllocator> {
92     std::vector<std::string> Types;
93 
94     TestParser(const char *Str)
95         : AbstractManglingParser(Str, Str + strlen(Str)) {}
96 
97     Node *parseType() {
98       OutputBuffer OB;
99       Node *N = AbstractManglingParser<TestParser, TestAllocator>::parseType();
100       N->printLeft(OB);
101       StringView Name = N->getBaseName();
102       if (!Name.empty())
103         Types.push_back(std::string(Name.begin(), Name.end()));
104       else
105         Types.push_back(toString(OB));
106       std::free(OB.getBuffer());
107       return N;
108     }
109   };
110 
111   // void f(A<_Float16>, _Float16);
112   TestParser Parser("_Z1f1AIDF16_EDF16_");
113   ASSERT_NE(nullptr, Parser.parse());
114   EXPECT_THAT(Parser.Types, testing::ElementsAre("_Float16", "A", "_Float16"));
115 }
116