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