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 |
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 | |
49 | private: |
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 | |
91 | struct 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. |
104 | struct 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 | |
133 | UnexpandedMap 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 | |
143 | class MacroCallReconstructorTest : public ::testing::Test { |
144 | public: |
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 | |
192 | bool 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 | } |
212 | MATCHER_P(matchesLine, line, "" ) { return matchesTokens(arg, line); } |
213 | |
214 | TEST_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 | |
226 | TEST_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 | |
244 | TEST_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 | |
275 | TEST_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 | |
301 | TEST_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 | |
355 | TEST_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 | |
434 | TEST_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 | |
455 | TEST_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 | |
469 | TEST_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 | |
491 | TEST_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 | |
547 | TEST_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 | |
587 | TEST_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 | |
612 | TEST_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 | |
654 | TEST_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 | |
680 | TEST_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 | |