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

source code of clang/unittests/Format/MacroCallReconstructorTest.cpp