1 | #include "../../lib/Format/Macros.h" |
2 | #include "../../lib/Format/UnwrappedLineParser.h" |
3 | #include "TestLexer.h" |
4 | #include "llvm/ADT/ArrayRef.h" |
5 | #include "llvm/ADT/SmallVector.h" |
6 | #include "llvm/ADT/StringRef.h" |
7 | |
8 | #include "gmock/gmock.h" |
9 | #include "gtest/gtest.h" |
10 | #include <map> |
11 | #include <memory> |
12 | #include <vector> |
13 | |
14 | namespace clang { |
15 | namespace format { |
16 | namespace { |
17 | |
18 | using UnexpandedMap = |
19 | llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>; |
20 | |
21 | // Keeps track of a sequence of macro expansions. |
22 | // |
23 | // The expanded tokens are accessible via getTokens(), while a map of macro call |
24 | // identifier token to unexpanded token stream is accessible via |
25 | // getUnexpanded(). |
26 | class Expansion { |
27 | public: |
28 | Expansion(TestLexer &Lex, MacroExpander &Macros) : Lex(Lex), Macros(Macros) {} |
29 | |
30 | // Appends the token stream obtained from expanding the macro Name given |
31 | // the provided arguments, to be later retrieved with getTokens(). |
32 | // Returns the list of tokens making up the unexpanded macro call. |
33 | TokenList expand(StringRef Name, |
34 | const SmallVector<SmallVector<FormatToken *, 8>, 1> &Args) { |
35 | return expandInternal(Name, Args); |
36 | } |
37 | |
38 | TokenList expand(StringRef Name) { return expandInternal(Name, Args: {}); } |
39 | |
40 | TokenList expand(StringRef Name, const std::vector<std::string> &Args) { |
41 | return expandInternal(Name, Args: lexArgs(Args)); |
42 | } |
43 | |
44 | const UnexpandedMap &getUnexpanded() const { return Unexpanded; } |
45 | |
46 | const TokenList &getTokens() const { return Tokens; } |
47 | |
48 | private: |
49 | TokenList expandInternal( |
50 | StringRef Name, |
51 | const std::optional<SmallVector<SmallVector<FormatToken *, 8>, 1>> |
52 | &Args) { |
53 | auto *ID = Lex.id(Code: Name); |
54 | auto UnexpandedLine = std::make_unique<UnwrappedLine>(); |
55 | UnexpandedLine->Tokens.push_back(x: ID); |
56 | if (Args && !Args->empty()) { |
57 | UnexpandedLine->Tokens.push_back(x: Lex.id(Code: "(" )); |
58 | for (auto I = Args->begin(), E = Args->end(); I != E; ++I) { |
59 | if (I != Args->begin()) |
60 | UnexpandedLine->Tokens.push_back(x: Lex.id(Code: "," )); |
61 | UnexpandedLine->Tokens.insert(position: UnexpandedLine->Tokens.end(), first: I->begin(), |
62 | last: I->end()); |
63 | } |
64 | UnexpandedLine->Tokens.push_back(x: Lex.id(Code: ")" )); |
65 | } |
66 | Unexpanded[ID] = std::move(UnexpandedLine); |
67 | |
68 | auto Expanded = Macros.expand(ID, OptionalArgs: Args); |
69 | if (Expanded.size() > 1) |
70 | Expanded = uneof(Tokens: Expanded); |
71 | Tokens.append(in_start: Expanded.begin(), in_end: Expanded.end()); |
72 | |
73 | TokenList UnexpandedTokens; |
74 | for (const UnwrappedLineNode &Node : Unexpanded[ID]->Tokens) |
75 | UnexpandedTokens.push_back(Elt: Node.Tok); |
76 | return UnexpandedTokens; |
77 | } |
78 | |
79 | SmallVector<TokenList, 1> lexArgs(const std::vector<std::string> &Args) { |
80 | SmallVector<TokenList, 1> Result; |
81 | for (const auto &Arg : Args) |
82 | Result.push_back(Elt: uneof(Tokens: Lex.lex(Code: Arg))); |
83 | return Result; |
84 | } |
85 | llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>> Unexpanded; |
86 | SmallVector<FormatToken *, 8> Tokens; |
87 | TestLexer &Lex; |
88 | MacroExpander &Macros; |
89 | }; |
90 | |
91 | struct Chunk { |
92 | Chunk(ArrayRef<FormatToken *> Tokens) : Tokens(Tokens) {} |
93 | Chunk(ArrayRef<UnwrappedLine> Children) : Children(Children) {} |
94 | SmallVector<UnwrappedLineNode, 1> Tokens; |
95 | SmallVector<UnwrappedLine, 0> Children; |
96 | }; |
97 | |
98 | // Allows to produce chunks of a token list by typing the code of equal tokens. |
99 | // |
100 | // Created from a list of tokens, users call "consume" to get the next chunk |
101 | // of tokens, checking that they match the written code. |
102 | struct Matcher { |
103 | Matcher(const TokenList &Tokens, TestLexer &Lex) |
104 | : Tokens(Tokens), It(this->Tokens.begin()), Lex(Lex) {} |
105 | |
106 | bool tokenMatches(const FormatToken *Left, const FormatToken *Right) { |
107 | if (Left->getType() == Right->getType() && |
108 | Left->TokenText == Right->TokenText) { |
109 | return true; |
110 | } |
111 | llvm::dbgs() << Left->TokenText << " != " << Right->TokenText << "\n" ; |
112 | return false; |
113 | } |
114 | |
115 | Chunk consume(StringRef Tokens) { |
116 | TokenList Result; |
117 | for (const FormatToken *Token : uneof(Tokens: Lex.lex(Code: Tokens))) { |
118 | (void)Token; // Fix unused variable warning when asserts are disabled. |
119 | assert(tokenMatches(*It, Token)); |
120 | Result.push_back(Elt: *It); |
121 | ++It; |
122 | } |
123 | return Chunk(Result); |
124 | } |
125 | |
126 | TokenList Tokens; |
127 | TokenList::iterator It; |
128 | TestLexer &Lex; |
129 | }; |
130 | |
131 | UnexpandedMap mergeUnexpanded(const UnexpandedMap &M1, |
132 | const UnexpandedMap &M2) { |
133 | UnexpandedMap Result; |
134 | for (const auto &KV : M1) |
135 | Result[KV.first] = std::make_unique<UnwrappedLine>(args&: *KV.second); |
136 | for (const auto &KV : M2) |
137 | Result[KV.first] = std::make_unique<UnwrappedLine>(args&: *KV.second); |
138 | return Result; |
139 | } |
140 | |
141 | class MacroCallReconstructorTest : public testing::Test { |
142 | public: |
143 | MacroCallReconstructorTest() : Lex(Allocator, Buffers) {} |
144 | |
145 | std::unique_ptr<MacroExpander> |
146 | createExpander(const std::vector<std::string> &MacroDefinitions) { |
147 | return std::make_unique<MacroExpander>(MacroDefinitions, |
148 | Lex.SourceMgr.get(), Lex.Style, |
149 | Lex.Allocator, Lex.IdentTable); |
150 | } |
151 | |
152 | UnwrappedLine line(ArrayRef<FormatToken *> Tokens, unsigned Level = 0) { |
153 | UnwrappedLine Result; |
154 | Result.Level = Level; |
155 | for (FormatToken *Tok : Tokens) |
156 | Result.Tokens.push_back(x: UnwrappedLineNode(Tok)); |
157 | return Result; |
158 | } |
159 | |
160 | UnwrappedLine line(StringRef Text, unsigned Level = 0) { |
161 | return line(Tokens: {lex(Text)}, Level); |
162 | } |
163 | |
164 | UnwrappedLine line(ArrayRef<Chunk> Chunks, unsigned Level = 0) { |
165 | UnwrappedLine Result; |
166 | Result.Level = Level; |
167 | for (const Chunk &Chunk : Chunks) { |
168 | llvm::append_range(C&: Result.Tokens, R: Chunk.Tokens); |
169 | assert(!Result.Tokens.empty()); |
170 | Result.Tokens.back().Children.append(in_start: Chunk.Children.begin(), |
171 | in_end: Chunk.Children.end()); |
172 | } |
173 | return Result; |
174 | } |
175 | |
176 | TokenList lex(StringRef Text) { return uneof(Lex.lex(Text)); } |
177 | |
178 | Chunk tokens(StringRef Text) { return Chunk(lex(Text)); } |
179 | |
180 | Chunk children(ArrayRef<UnwrappedLine> Children) { return Chunk(Children); } |
181 | |
182 | llvm::SpecificBumpPtrAllocator<FormatToken> Allocator; |
183 | std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers; |
184 | TestLexer Lex; |
185 | }; |
186 | |
187 | bool matchesTokens(const UnwrappedLine &L1, const UnwrappedLine &L2) { |
188 | if (L1.Level != L2.Level) |
189 | return false; |
190 | if (L1.Tokens.size() != L2.Tokens.size()) |
191 | return false; |
192 | for (auto L1It = L1.Tokens.begin(), L2It = L2.Tokens.begin(); |
193 | L1It != L1.Tokens.end(); ++L1It, ++L2It) { |
194 | if (L1It->Tok != L2It->Tok) |
195 | return false; |
196 | if (L1It->Children.size() != L2It->Children.size()) |
197 | return false; |
198 | for (auto L1ChildIt = L1It->Children.begin(), |
199 | L2ChildIt = L2It->Children.begin(); |
200 | L1ChildIt != L1It->Children.end(); ++L1ChildIt, ++L2ChildIt) { |
201 | if (!matchesTokens(L1: *L1ChildIt, L2: *L2ChildIt)) |
202 | return false; |
203 | } |
204 | } |
205 | return true; |
206 | } |
207 | MATCHER_P(matchesLine, line, "" ) { return matchesTokens(arg, line); } |
208 | |
209 | TEST_F(MacroCallReconstructorTest, Identifier) { |
210 | auto Macros = createExpander({"X=x" }); |
211 | Expansion Exp(Lex, *Macros); |
212 | TokenList Call = Exp.expand(Name: "X" ); |
213 | |
214 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
215 | Unexp.addLine(Line: line(Exp.getTokens())); |
216 | EXPECT_TRUE(Unexp.finished()); |
217 | Matcher U(Call, Lex); |
218 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(line(U.consume("X" )))); |
219 | } |
220 | |
221 | TEST_F(MacroCallReconstructorTest, EmptyDefinition) { |
222 | auto Macros = createExpander({"X" }); |
223 | Expansion Exp(Lex, *Macros); |
224 | TokenList Call = Exp.expand(Name: "X" ); |
225 | |
226 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
227 | Unexp.addLine(Line: line(Exp.getTokens())); |
228 | EXPECT_TRUE(Unexp.finished()); |
229 | Matcher U(Call, Lex); |
230 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(line(U.consume("X" )))); |
231 | } |
232 | |
233 | TEST_F(MacroCallReconstructorTest, EmptyExpansion) { |
234 | auto Macros = createExpander({"A(x)=x" }); |
235 | Expansion Exp(Lex, *Macros); |
236 | TokenList Call = Exp.expand(Name: "A" , Args: {"" }); |
237 | |
238 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
239 | Unexp.addLine(Line: line(Exp.getTokens())); |
240 | EXPECT_TRUE(Unexp.finished()); |
241 | Matcher U(Call, Lex); |
242 | EXPECT_THAT(std::move(Unexp).takeResult(), |
243 | matchesLine(line(U.consume("A()" )))); |
244 | } |
245 | |
246 | TEST_F(MacroCallReconstructorTest, NestedLineWithinCall) { |
247 | auto Macros = createExpander({"C(a)=class X { a; };" }); |
248 | Expansion Exp(Lex, *Macros); |
249 | TokenList Call = Exp.expand(Name: "C" , Args: {"void f()" }); |
250 | |
251 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
252 | Matcher E(Exp.getTokens(), Lex); |
253 | Unexp.addLine(Line: line(E.consume(Tokens: "class X {" ))); |
254 | EXPECT_FALSE(Unexp.finished()); |
255 | Unexp.addLine(Line: line(E.consume(Tokens: "void f();" ))); |
256 | EXPECT_FALSE(Unexp.finished()); |
257 | Unexp.addLine(Line: line(E.consume(Tokens: "};" ))); |
258 | EXPECT_TRUE(Unexp.finished()); |
259 | Matcher U(Call, Lex); |
260 | EXPECT_THAT(std::move(Unexp).takeResult(), |
261 | matchesLine(line(U.consume("C(void f())" )))); |
262 | } |
263 | |
264 | TEST_F(MacroCallReconstructorTest, MultipleLinesInNestedMultiParamsExpansion) { |
265 | auto Macros = createExpander({"C(a, b)=a b" , "B(a)={a}" }); |
266 | Expansion Exp1(Lex, *Macros); |
267 | TokenList Call1 = Exp1.expand(Name: "B" , Args: {"b" }); |
268 | Expansion Exp2(Lex, *Macros); |
269 | TokenList Call2 = Exp2.expand("C" , {uneof(Lex.lex("a" )), Exp1.getTokens()}); |
270 | |
271 | UnexpandedMap Unexpanded = |
272 | mergeUnexpanded(M1: Exp1.getUnexpanded(), M2: Exp2.getUnexpanded()); |
273 | MacroCallReconstructor Unexp(0, Unexpanded); |
274 | Matcher E(Exp2.getTokens(), Lex); |
275 | Unexp.addLine(Line: line(E.consume(Tokens: "a" ))); |
276 | EXPECT_FALSE(Unexp.finished()); |
277 | Unexp.addLine(Line: line(E.consume(Tokens: "{" ))); |
278 | EXPECT_FALSE(Unexp.finished()); |
279 | Unexp.addLine(Line: line(E.consume(Tokens: "b" ))); |
280 | EXPECT_FALSE(Unexp.finished()); |
281 | Unexp.addLine(Line: line(E.consume(Tokens: "}" ))); |
282 | EXPECT_TRUE(Unexp.finished()); |
283 | |
284 | Matcher U1(Call1, Lex); |
285 | auto Middle = U1.consume(Tokens: "B(b)" ); |
286 | Matcher U2(Call2, Lex); |
287 | auto Chunk1 = U2.consume(Tokens: "C(a, " ); |
288 | auto Chunk2 = U2.consume(Tokens: "{ b }" ); |
289 | auto Chunk3 = U2.consume(Tokens: ")" ); |
290 | |
291 | EXPECT_THAT(std::move(Unexp).takeResult(), |
292 | matchesLine(line({Chunk1, Middle, Chunk3}))); |
293 | } |
294 | |
295 | TEST_F(MacroCallReconstructorTest, StatementSequence) { |
296 | auto Macros = createExpander({"SEMI=;" }); |
297 | Expansion Exp(Lex, *Macros); |
298 | TokenList Call1 = Exp.expand(Name: "SEMI" ); |
299 | TokenList Call2 = Exp.expand(Name: "SEMI" ); |
300 | TokenList Call3 = Exp.expand(Name: "SEMI" ); |
301 | |
302 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
303 | Matcher E(Exp.getTokens(), Lex); |
304 | Unexp.addLine(Line: line(E.consume(Tokens: ";" ))); |
305 | EXPECT_TRUE(Unexp.finished()); |
306 | Unexp.addLine(Line: line(E.consume(Tokens: ";" ))); |
307 | EXPECT_TRUE(Unexp.finished()); |
308 | Unexp.addLine(Line: line(E.consume(Tokens: ";" ))); |
309 | EXPECT_TRUE(Unexp.finished()); |
310 | Matcher U1(Call1, Lex); |
311 | Matcher U2(Call2, Lex); |
312 | Matcher U3(Call3, Lex); |
313 | EXPECT_THAT(std::move(Unexp).takeResult(), |
314 | matchesLine(line( |
315 | {U1.consume("SEMI" ), |
316 | children({line({U2.consume("SEMI" ), |
317 | children({line(U3.consume("SEMI" ), 2)})}, |
318 | 1)})}))); |
319 | } |
320 | |
321 | TEST_F(MacroCallReconstructorTest, NestedBlock) { |
322 | auto Macros = createExpander({"ID(x)=x" }); |
323 | // Test: ID({ ID(a *b); }) |
324 | // 1. expand ID(a *b) -> a *b |
325 | Expansion Exp1(Lex, *Macros); |
326 | TokenList Call1 = Exp1.expand(Name: "ID" , Args: {"a *b" }); |
327 | // 2. expand ID({ a *b; }) |
328 | TokenList Arg; |
329 | Arg.push_back(Lex.id("{" )); |
330 | Arg.append(in_start: Exp1.getTokens().begin(), in_end: Exp1.getTokens().end()); |
331 | Arg.push_back(Lex.id(";" )); |
332 | Arg.push_back(Lex.id("}" )); |
333 | Expansion Exp2(Lex, *Macros); |
334 | TokenList Call2 = Exp2.expand(Name: "ID" , Args: {Arg}); |
335 | |
336 | // Consume as-if formatted: |
337 | // { |
338 | // a *b; |
339 | // } |
340 | UnexpandedMap Unexpanded = |
341 | mergeUnexpanded(M1: Exp1.getUnexpanded(), M2: Exp2.getUnexpanded()); |
342 | MacroCallReconstructor Unexp(0, Unexpanded); |
343 | Matcher E(Exp2.getTokens(), Lex); |
344 | Unexp.addLine(Line: line(E.consume(Tokens: "{" ))); |
345 | EXPECT_FALSE(Unexp.finished()); |
346 | Unexp.addLine(Line: line(E.consume(Tokens: "a *b;" ))); |
347 | EXPECT_FALSE(Unexp.finished()); |
348 | Unexp.addLine(Line: line(E.consume(Tokens: "}" ))); |
349 | EXPECT_TRUE(Unexp.finished()); |
350 | |
351 | // Expect lines: |
352 | // ID({ |
353 | // ID(a *b); |
354 | // }) |
355 | Matcher U1(Call1, Lex); |
356 | Matcher U2(Call2, Lex); |
357 | auto Chunk2Start = U2.consume(Tokens: "ID(" ); |
358 | auto Chunk2LBrace = U2.consume(Tokens: "{" ); |
359 | U2.consume(Tokens: "a *b" ); |
360 | auto Chunk2Mid = U2.consume(Tokens: ";" ); |
361 | auto Chunk2RBrace = U2.consume(Tokens: "}" ); |
362 | auto Chunk2End = U2.consume(Tokens: ")" ); |
363 | auto Chunk1 = U1.consume(Tokens: "ID(a *b)" ); |
364 | |
365 | auto Expected = line({Chunk2Start, |
366 | children({ |
367 | line(Chunk2LBrace, 1), |
368 | line({Chunk1, Chunk2Mid}, 1), |
369 | line(Chunk2RBrace, 1), |
370 | }), |
371 | Chunk2End}); |
372 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
373 | } |
374 | |
375 | TEST_F(MacroCallReconstructorTest, NestedChildBlocks) { |
376 | auto Macros = createExpander({"ID(x)=x" , "CALL(x)=f([] { x })" }); |
377 | // Test: ID(CALL(CALL(return a * b;))) |
378 | // 1. expand CALL(return a * b;) |
379 | Expansion Exp1(Lex, *Macros); |
380 | TokenList Call1 = Exp1.expand(Name: "CALL" , Args: {"return a * b;" }); |
381 | // 2. expand CALL(f([] { return a * b; })) |
382 | Expansion Exp2(Lex, *Macros); |
383 | TokenList Call2 = Exp2.expand(Name: "CALL" , Args: {Exp1.getTokens()}); |
384 | // 3. expand ID({ f([] { f([] { return a * b; }) }) }) |
385 | TokenList Arg3; |
386 | Arg3.push_back(Lex.id("{" )); |
387 | Arg3.append(in_start: Exp2.getTokens().begin(), in_end: Exp2.getTokens().end()); |
388 | Arg3.push_back(Lex.id("}" )); |
389 | Expansion Exp3(Lex, *Macros); |
390 | TokenList Call3 = Exp3.expand(Name: "ID" , Args: {Arg3}); |
391 | |
392 | // Consume as-if formatted in three unwrapped lines: |
393 | // 0: { |
394 | // 1: f([] { |
395 | // f([] { |
396 | // return a * b; |
397 | // }) |
398 | // }) |
399 | // 2: } |
400 | UnexpandedMap Unexpanded = mergeUnexpanded( |
401 | M1: Exp1.getUnexpanded(), |
402 | M2: mergeUnexpanded(M1: Exp2.getUnexpanded(), M2: Exp3.getUnexpanded())); |
403 | MacroCallReconstructor Unexp(0, Unexpanded); |
404 | Matcher E(Exp3.getTokens(), Lex); |
405 | Unexp.addLine(Line: line(E.consume(Tokens: "{" ))); |
406 | Unexp.addLine( |
407 | Line: line({E.consume(Tokens: "f([] {" ), |
408 | children(Children: {line({E.consume(Tokens: "f([] {" ), |
409 | children({line(E.consume(Tokens: "return a * b;" ), 3)}), |
410 | E.consume(Tokens: "})" )}, |
411 | 2)}), |
412 | E.consume(Tokens: "})" )}, |
413 | 1)); |
414 | Unexp.addLine(Line: line(E.consume(Tokens: "}" ))); |
415 | EXPECT_TRUE(Unexp.finished()); |
416 | |
417 | // Expect lines: |
418 | // ID( |
419 | // { |
420 | // CALL(CALL(return a * b;)) |
421 | // } |
422 | // ) |
423 | Matcher U1(Call1, Lex); |
424 | Matcher U2(Call2, Lex); |
425 | Matcher U3(Call3, Lex); |
426 | auto Chunk3Start = U3.consume(Tokens: "ID(" ); |
427 | auto Chunk3LBrace = U3.consume(Tokens: "{" ); |
428 | U3.consume(Tokens: "f([] { f([] { return a * b; }) })" ); |
429 | auto Chunk3RBrace = U3.consume(Tokens: "}" ); |
430 | auto Chunk3End = U3.consume(Tokens: ")" ); |
431 | auto Chunk2Start = U2.consume(Tokens: "CALL(" ); |
432 | U2.consume(Tokens: "f([] { return a * b; })" ); |
433 | auto Chunk2End = U2.consume(Tokens: ")" ); |
434 | auto Chunk1 = U1.consume(Tokens: "CALL(return a * b;)" ); |
435 | |
436 | auto Expected = line({ |
437 | Chunk3Start, |
438 | children({ |
439 | line(Chunk3LBrace, 1), |
440 | line( |
441 | { |
442 | Chunk2Start, |
443 | Chunk1, |
444 | Chunk2End, |
445 | }, |
446 | 2), |
447 | line(Chunk3RBrace, 1), |
448 | }), |
449 | Chunk3End, |
450 | }); |
451 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
452 | } |
453 | |
454 | TEST_F(MacroCallReconstructorTest, NestedChildrenMultipleArguments) { |
455 | auto Macros = createExpander({"CALL(a, b)=f([] { a; b; })" }); |
456 | Expansion Exp(Lex, *Macros); |
457 | TokenList Call = Exp.expand(Name: "CALL" , Args: {std::string("int a" ), "int b" }); |
458 | |
459 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
460 | Matcher E(Exp.getTokens(), Lex); |
461 | Unexp.addLine(Line: line({ |
462 | E.consume(Tokens: "f([] {" ), |
463 | children({ |
464 | line(E.consume(Tokens: "int a;" )), |
465 | line(E.consume(Tokens: "int b;" )), |
466 | }), |
467 | E.consume(Tokens: "})" ), |
468 | })); |
469 | EXPECT_TRUE(Unexp.finished()); |
470 | Matcher U(Call, Lex); |
471 | auto Expected = line(U.consume(Tokens: "CALL(int a, int b)" )); |
472 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
473 | } |
474 | |
475 | TEST_F(MacroCallReconstructorTest, ReverseOrderArgumentsInExpansion) { |
476 | auto Macros = createExpander({"CALL(a, b)=b + a" }); |
477 | Expansion Exp(Lex, *Macros); |
478 | TokenList Call = Exp.expand(Name: "CALL" , Args: {std::string("x" ), "y" }); |
479 | |
480 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
481 | Matcher E(Exp.getTokens(), Lex); |
482 | Unexp.addLine(Line: line(E.consume(Tokens: "y + x" ))); |
483 | EXPECT_TRUE(Unexp.finished()); |
484 | Matcher U(Call, Lex); |
485 | auto Expected = line(U.consume(Tokens: "CALL(x, y)" )); |
486 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
487 | } |
488 | |
489 | TEST_F(MacroCallReconstructorTest, MultipleToplevelUnwrappedLines) { |
490 | auto Macros = createExpander({"ID(a, b)=a b" }); |
491 | Expansion Exp(Lex, *Macros); |
492 | TokenList Call = Exp.expand(Name: "ID" , Args: {std::string("x; x" ), "y" }); |
493 | |
494 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
495 | Matcher E(Exp.getTokens(), Lex); |
496 | Unexp.addLine(Line: line(E.consume(Tokens: "x;" ))); |
497 | Unexp.addLine(Line: line(E.consume(Tokens: "x y" ))); |
498 | EXPECT_TRUE(Unexp.finished()); |
499 | Matcher U(Call, Lex); |
500 | auto Expected = line({ |
501 | U.consume(Tokens: "ID(" ), |
502 | children({ |
503 | line(U.consume(Tokens: "x;" ), 1), |
504 | line(U.consume(Tokens: "x" ), 1), |
505 | }), |
506 | U.consume(Tokens: ", y)" ), |
507 | }); |
508 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
509 | } |
510 | |
511 | TEST_F(MacroCallReconstructorTest, NestedCallsMultipleLines) { |
512 | auto Macros = createExpander({"ID(x)=x" }); |
513 | // Test: ID({ID(a * b);}) |
514 | // 1. expand ID(a * b) |
515 | Expansion Exp1(Lex, *Macros); |
516 | TokenList Call1 = Exp1.expand(Name: "ID" , Args: {"a * b" }); |
517 | // 2. expand ID({ a * b; }) |
518 | Expansion Exp2(Lex, *Macros); |
519 | TokenList Arg2; |
520 | Arg2.push_back(Lex.id("{" )); |
521 | Arg2.append(in_start: Exp1.getTokens().begin(), in_end: Exp1.getTokens().end()); |
522 | Arg2.push_back(Lex.id(";" )); |
523 | Arg2.push_back(Lex.id("}" )); |
524 | TokenList Call2 = Exp2.expand(Name: "ID" , Args: {Arg2}); |
525 | |
526 | // Consume as-if formatted in three unwrapped lines: |
527 | // 0: { |
528 | // 1: a * b; |
529 | // 2: } |
530 | UnexpandedMap Unexpanded = |
531 | mergeUnexpanded(M1: Exp1.getUnexpanded(), M2: Exp2.getUnexpanded()); |
532 | MacroCallReconstructor Unexp(0, Unexpanded); |
533 | Matcher E(Exp2.getTokens(), Lex); |
534 | Unexp.addLine(Line: line(E.consume(Tokens: "{" ))); |
535 | Unexp.addLine(Line: line(E.consume(Tokens: "a * b;" ))); |
536 | Unexp.addLine(Line: line(E.consume(Tokens: "}" ))); |
537 | EXPECT_TRUE(Unexp.finished()); |
538 | |
539 | // Expect lines: |
540 | // ID( |
541 | // { |
542 | // ID(a * b); |
543 | // } |
544 | // ) |
545 | Matcher U1(Call1, Lex); |
546 | Matcher U2(Call2, Lex); |
547 | auto Chunk2Start = U2.consume(Tokens: "ID(" ); |
548 | auto Chunk2LBrace = U2.consume(Tokens: "{" ); |
549 | U2.consume(Tokens: "a * b" ); |
550 | auto Chunk2Semi = U2.consume(Tokens: ";" ); |
551 | auto Chunk2RBrace = U2.consume(Tokens: "}" ); |
552 | auto Chunk2End = U2.consume(Tokens: ")" ); |
553 | auto Chunk1 = U1.consume(Tokens: "ID(a * b)" ); |
554 | |
555 | auto Expected = line({ |
556 | Chunk2Start, |
557 | children({ |
558 | line({Chunk2LBrace}, 1), |
559 | line({Chunk1, Chunk2Semi}, 1), |
560 | line({Chunk2RBrace}, 1), |
561 | }), |
562 | Chunk2End, |
563 | }); |
564 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
565 | } |
566 | |
567 | TEST_F(MacroCallReconstructorTest, ParentOutsideMacroCall) { |
568 | auto Macros = createExpander({"ID(a)=a" }); |
569 | Expansion Exp(Lex, *Macros); |
570 | TokenList Call = Exp.expand(Name: "ID" , Args: {std::string("x; y; z;" )}); |
571 | |
572 | auto Prefix = tokens("int a = []() {" ); |
573 | auto Postfix = tokens("}();" ); |
574 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
575 | Matcher E(Exp.getTokens(), Lex); |
576 | Unexp.addLine(Line: line({ |
577 | Prefix, |
578 | children({ |
579 | line(E.consume(Tokens: "x;" )), |
580 | line(E.consume(Tokens: "y;" )), |
581 | line(E.consume(Tokens: "z;" )), |
582 | }), |
583 | Postfix, |
584 | })); |
585 | EXPECT_TRUE(Unexp.finished()); |
586 | Matcher U(Call, Lex); |
587 | auto Expected = line({ |
588 | Prefix, |
589 | children(Children: { |
590 | line( |
591 | { |
592 | U.consume(Tokens: "ID(" ), |
593 | children({ |
594 | line(U.consume(Tokens: "x;" ), 2), |
595 | line(U.consume(Tokens: "y;" ), 2), |
596 | line(U.consume(Tokens: "z;" ), 2), |
597 | }), |
598 | U.consume(Tokens: ")" ), |
599 | }, |
600 | 1), |
601 | }), |
602 | Postfix, |
603 | }); |
604 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
605 | } |
606 | |
607 | TEST_F(MacroCallReconstructorTest, ChildrenSplitAcrossArguments) { |
608 | auto Macros = createExpander({"CALL(a, b)=f([]() a b)" }); |
609 | Expansion Exp(Lex, *Macros); |
610 | TokenList Call = Exp.expand(Name: "CALL" , Args: {std::string("{ a;" ), "b; }" }); |
611 | |
612 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
613 | Matcher E(Exp.getTokens(), Lex); |
614 | Unexp.addLine(Line: line({ |
615 | E.consume(Tokens: "f([]() {" ), |
616 | children({ |
617 | line(E.consume(Tokens: "a;" )), |
618 | line(E.consume(Tokens: "b;" )), |
619 | }), |
620 | E.consume(Tokens: "})" ), |
621 | })); |
622 | EXPECT_TRUE(Unexp.finished()); |
623 | Matcher U(Call, Lex); |
624 | auto Expected = line({ |
625 | U.consume(Tokens: "CALL({" ), |
626 | children(line(U.consume(Tokens: "a;" ), 1)), |
627 | U.consume(Tokens: ", b; })" ), |
628 | }); |
629 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
630 | } |
631 | |
632 | TEST_F(MacroCallReconstructorTest, ChildrenAfterMacroCall) { |
633 | auto Macros = createExpander({"CALL(a, b)=f([]() a b" }); |
634 | Expansion Exp(Lex, *Macros); |
635 | TokenList Call = Exp.expand(Name: "CALL" , Args: {std::string("{ a" ), "b" }); |
636 | |
637 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
638 | Matcher E(Exp.getTokens(), Lex); |
639 | auto Semi = tokens(";" ); |
640 | auto SecondLine = tokens("c d;" ); |
641 | auto ThirdLine = tokens("e f;" ); |
642 | auto Postfix = tokens("})" ); |
643 | Unexp.addLine(Line: line({ |
644 | E.consume(Tokens: "f([]() {" ), |
645 | children(Children: { |
646 | line({E.consume(Tokens: "a b" ), Semi}), |
647 | line(SecondLine), |
648 | line(ThirdLine), |
649 | }), |
650 | Postfix, |
651 | })); |
652 | EXPECT_TRUE(Unexp.finished()); |
653 | Matcher U(Call, Lex); |
654 | auto Expected = line({ |
655 | U.consume(Tokens: "CALL({" ), |
656 | children(line(U.consume(Tokens: "a" ), 1)), |
657 | U.consume(Tokens: ", b)" ), |
658 | Semi, |
659 | children(Children: line( |
660 | { |
661 | SecondLine, |
662 | children(Children: line( |
663 | { |
664 | ThirdLine, |
665 | Postfix, |
666 | }, |
667 | 2)), |
668 | }, |
669 | 1)), |
670 | }); |
671 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
672 | } |
673 | |
674 | TEST_F(MacroCallReconstructorTest, InvalidCodeSplittingBracesAcrossArgs) { |
675 | auto Macros = createExpander({"M(a, b, c)=(a) (b) c" }); |
676 | Expansion Exp(Lex, *Macros); |
677 | TokenList Call = Exp.expand(Name: "M" , Args: {std::string("{" ), "x" , "" }); |
678 | |
679 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
680 | Matcher E(Exp.getTokens(), Lex); |
681 | auto Prefix = tokens("({" ); |
682 | Unexp.addLine(Line: line({ |
683 | Prefix, |
684 | children(Children: { |
685 | line({ |
686 | E.consume(Tokens: "({" ), |
687 | children({line(E.consume(Tokens: ")(x)" ))}), |
688 | }), |
689 | }), |
690 | })); |
691 | EXPECT_TRUE(Unexp.finished()); |
692 | Matcher U(Call, Lex); |
693 | auto Expected = line({ |
694 | Prefix, |
695 | children({line(U.consume(Tokens: "M({,x,)" ), 1)}), |
696 | }); |
697 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
698 | } |
699 | |
700 | TEST_F(MacroCallReconstructorTest, IndentLevelInExpandedCode) { |
701 | auto Macros = createExpander({"ID(a)=a" }); |
702 | Expansion Exp(Lex, *Macros); |
703 | TokenList Call = Exp.expand(Name: "ID" , Args: {std::string("[] { { x; } }" )}); |
704 | |
705 | MacroCallReconstructor Unexp(0, Exp.getUnexpanded()); |
706 | Matcher E(Exp.getTokens(), Lex); |
707 | Unexp.addLine(Line: line({ |
708 | E.consume(Tokens: "[] {" ), |
709 | children({ |
710 | line(E.consume(Tokens: "{" ), 1), |
711 | line(E.consume(Tokens: "x;" ), 2), |
712 | line(E.consume(Tokens: "}" ), 1), |
713 | }), |
714 | E.consume(Tokens: "}" ), |
715 | })); |
716 | EXPECT_TRUE(Unexp.finished()); |
717 | Matcher U(Call, Lex); |
718 | auto Expected = line({ |
719 | U.consume(Tokens: "ID([] {" ), |
720 | children({ |
721 | line(U.consume(Tokens: "{" ), 1), |
722 | line(U.consume(Tokens: "x;" ), 2), |
723 | line(U.consume(Tokens: "}" ), 1), |
724 | }), |
725 | U.consume(Tokens: "})" ), |
726 | }); |
727 | EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(Expected)); |
728 | } |
729 | |
730 | } // namespace |
731 | } // namespace format |
732 | } // namespace clang |
733 | |