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