1 #include "../../lib/Format/Macros.h"
2 #include "TestLexer.h"
3 #include "clang/Basic/FileManager.h"
4
5 #include "gtest/gtest.h"
6
7 namespace clang {
8 namespace format {
9
10 namespace {
11
12 class MacroExpanderTest : public ::testing::Test {
13 public:
MacroExpanderTest()14 MacroExpanderTest() : Lex(Allocator, Buffers) {}
15 std::unique_ptr<MacroExpander>
create(const std::vector<std::string> & MacroDefinitions)16 create(const std::vector<std::string> &MacroDefinitions) {
17 return std::make_unique<MacroExpander>(MacroDefinitions,
18 Lex.SourceMgr.get(), Lex.Style,
19 Lex.Allocator, Lex.IdentTable);
20 }
21
expand(MacroExpander & Macros,llvm::StringRef Name,const std::vector<std::string> & Args={})22 std::string expand(MacroExpander &Macros, llvm::StringRef Name,
23 const std::vector<std::string> &Args = {}) {
24 EXPECT_TRUE(Macros.defined(Name));
25 return text(Macros.expand(Lex.id(Name), lexArgs(Args)));
26 }
27
28 llvm::SmallVector<TokenList, 1>
lexArgs(const std::vector<std::string> & Args)29 lexArgs(const std::vector<std::string> &Args) {
30 llvm::SmallVector<TokenList, 1> Result;
31 for (const auto &Arg : Args)
32 Result.push_back(uneof(Lex.lex(Arg)));
33 return Result;
34 }
35
36 struct MacroAttributes {
37 clang::tok::TokenKind Kind;
38 MacroRole Role;
39 unsigned Start;
40 unsigned End;
41 llvm::SmallVector<FormatToken *, 1> ExpandedFrom;
42 };
43
expectAttributes(const TokenList & Tokens,const std::vector<MacroAttributes> & Attributes,const std::string & File,unsigned Line)44 void expectAttributes(const TokenList &Tokens,
45 const std::vector<MacroAttributes> &Attributes,
46 const std::string &File, unsigned Line) {
47 EXPECT_EQ(Tokens.size(), Attributes.size()) << text(Tokens);
48 for (size_t I = 0, E = Tokens.size(); I != E; ++I) {
49 if (I >= Attributes.size())
50 continue;
51 std::string Context =
52 ("for token " + llvm::Twine(I) + ": " + Tokens[I]->Tok.getName() +
53 " / " + Tokens[I]->TokenText)
54 .str();
55 EXPECT_TRUE(Tokens[I]->is(Attributes[I].Kind))
56 << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
57 EXPECT_EQ(Tokens[I]->MacroCtx->Role, Attributes[I].Role)
58 << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
59 EXPECT_EQ(Tokens[I]->MacroCtx->StartOfExpansion, Attributes[I].Start)
60 << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
61 EXPECT_EQ(Tokens[I]->MacroCtx->EndOfExpansion, Attributes[I].End)
62 << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
63 EXPECT_EQ(Tokens[I]->MacroCtx->ExpandedFrom, Attributes[I].ExpandedFrom)
64 << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
65 }
66 }
67
68 protected:
69 llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
70 std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
71 TestLexer Lex;
72 };
73
74 #define EXPECT_ATTRIBUTES(Tokens, Attributes) \
75 expectAttributes(Tokens, Attributes, __FILE__, __LINE__)
76
TEST_F(MacroExpanderTest,SkipsDefinitionOnError)77 TEST_F(MacroExpanderTest, SkipsDefinitionOnError) {
78 auto Macros =
79 create({"A(", "B(,", "C(a,", "D(a a", "E(a, a", "F(,)", "G(a;"});
80 for (const auto *Name : {"A", "B", "C", "D", "E", "F", "G"})
81 EXPECT_FALSE(Macros->defined(Name)) << "for Name " << Name;
82 }
83
TEST_F(MacroExpanderTest,ExpandsWithoutArguments)84 TEST_F(MacroExpanderTest, ExpandsWithoutArguments) {
85 auto Macros = create({
86 "A",
87 "B=b",
88 "C=c + c",
89 "D()",
90 });
91 EXPECT_TRUE(Macros->objectLike("A"));
92 EXPECT_TRUE(Macros->objectLike("B"));
93 EXPECT_TRUE(Macros->objectLike("C"));
94 EXPECT_TRUE(!Macros->objectLike("D"));
95 EXPECT_EQ("", expand(*Macros, "A"));
96 EXPECT_EQ("b", expand(*Macros, "B"));
97 EXPECT_EQ("c+c", expand(*Macros, "C"));
98 EXPECT_EQ("", expand(*Macros, "D"));
99 }
100
TEST_F(MacroExpanderTest,ExpandsWithArguments)101 TEST_F(MacroExpanderTest, ExpandsWithArguments) {
102 auto Macros = create({
103 "A(x)",
104 "B(x, y)=x + y",
105 });
106 EXPECT_EQ("", expand(*Macros, "A", {"a"}));
107 EXPECT_EQ("b1+b2+b3", expand(*Macros, "B", {"b1", "b2 + b3"}));
108 EXPECT_EQ("x+", expand(*Macros, "B", {"x"}));
109 }
110
TEST_F(MacroExpanderTest,AttributizesTokens)111 TEST_F(MacroExpanderTest, AttributizesTokens) {
112 auto Macros = create({
113 "A(x, y)={ x + y; }",
114 "B(x, y)=x + 3 + y",
115 });
116 auto *A = Lex.id("A");
117 auto AArgs = lexArgs({"a1 * a2", "a3 * a4"});
118 auto Result = Macros->expand(A, AArgs);
119 EXPECT_EQ(11U, Result.size()) << text(Result) << " / " << Result;
120 EXPECT_EQ("{a1*a2+a3*a4;}", text(Result));
121 std::vector<MacroAttributes> Attributes = {
122 {tok::l_brace, MR_Hidden, 1, 0, {A}},
123 {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
124 {tok::star, MR_ExpandedArg, 0, 0, {A}},
125 {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
126 {tok::plus, MR_Hidden, 0, 0, {A}},
127 {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
128 {tok::star, MR_ExpandedArg, 0, 0, {A}},
129 {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
130 {tok::semi, MR_Hidden, 0, 0, {A}},
131 {tok::r_brace, MR_Hidden, 0, 1, {A}},
132 {tok::eof, MR_Hidden, 0, 0, {A}},
133 };
134 EXPECT_ATTRIBUTES(Result, Attributes);
135
136 auto *B = Lex.id("B");
137 auto BArgs = lexArgs({"b1", "b2"});
138 Result = Macros->expand(B, BArgs);
139 EXPECT_EQ(6U, Result.size()) << text(Result) << " / " << Result;
140 EXPECT_EQ("b1+3+b2", text(Result));
141 Attributes = {
142 {tok::identifier, MR_ExpandedArg, 1, 0, {B}},
143 {tok::plus, MR_Hidden, 0, 0, {B}},
144 {tok::numeric_constant, MR_Hidden, 0, 0, {B}},
145 {tok::plus, MR_Hidden, 0, 0, {B}},
146 {tok::identifier, MR_ExpandedArg, 0, 1, {B}},
147 {tok::eof, MR_Hidden, 0, 0, {B}},
148 };
149 EXPECT_ATTRIBUTES(Result, Attributes);
150 }
151
TEST_F(MacroExpanderTest,RecursiveExpansion)152 TEST_F(MacroExpanderTest, RecursiveExpansion) {
153 auto Macros = create({
154 "A(x)=x",
155 "B(x)=x",
156 "C(x)=x",
157 });
158
159 auto *A = Lex.id("A");
160 auto *B = Lex.id("B");
161 auto *C = Lex.id("C");
162
163 auto Args = lexArgs({"id"});
164 auto CResult = uneof(Macros->expand(C, Args));
165 auto BResult = uneof(Macros->expand(B, CResult));
166 auto AResult = uneof(Macros->expand(A, BResult));
167
168 std::vector<MacroAttributes> Attributes = {
169 {tok::identifier, MR_ExpandedArg, 3, 3, {C, B, A}},
170 };
171 EXPECT_ATTRIBUTES(AResult, Attributes);
172 }
173
TEST_F(MacroExpanderTest,SingleExpansion)174 TEST_F(MacroExpanderTest, SingleExpansion) {
175 auto Macros = create({"A(x)=x+x"});
176 auto *A = Lex.id("A");
177 auto Args = lexArgs({"id"});
178 auto Result = uneof(Macros->expand(A, Args));
179 std::vector<MacroAttributes> Attributes = {
180 {tok::identifier, MR_ExpandedArg, 1, 0, {A}},
181 {tok::plus, MR_Hidden, 0, 0, {A}},
182 {tok::identifier, MR_Hidden, 0, 1, {A}},
183 };
184 EXPECT_ATTRIBUTES(Result, Attributes);
185 }
186
TEST_F(MacroExpanderTest,UnderstandsCppTokens)187 TEST_F(MacroExpanderTest, UnderstandsCppTokens) {
188 auto Macros = create({"A(T,name)=T name = 0;"});
189 auto *A = Lex.id("A");
190 auto Args = lexArgs({"const int", "x"});
191 auto Result = uneof(Macros->expand(A, Args));
192 std::vector<MacroAttributes> Attributes = {
193 {tok::kw_const, MR_ExpandedArg, 1, 0, {A}},
194 {tok::kw_int, MR_ExpandedArg, 0, 0, {A}},
195 {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
196 {tok::equal, MR_Hidden, 0, 0, {A}},
197 {tok::numeric_constant, MR_Hidden, 0, 0, {A}},
198 {tok::semi, MR_Hidden, 0, 1, {A}},
199 };
200 EXPECT_ATTRIBUTES(Result, Attributes);
201 }
202
203 } // namespace
204 } // namespace format
205 } // namespace clang
206