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 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
48private:
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
91struct 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.
102struct 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
131UnexpandedMap 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
141class MacroCallReconstructorTest : public testing::Test {
142public:
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
187bool 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}
207MATCHER_P(matchesLine, line, "") { return matchesTokens(arg, line); }
208
209TEST_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
221TEST_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
233TEST_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
246TEST_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
264TEST_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
295TEST_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
321TEST_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
375TEST_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
454TEST_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
475TEST_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
489TEST_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
511TEST_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
567TEST_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
607TEST_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
632TEST_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
674TEST_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
700TEST_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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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