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