1e336b74cSManuel Klimek #include "../../lib/Format/Macros.h"
2e336b74cSManuel Klimek #include "TestLexer.h"
3e336b74cSManuel Klimek #include "clang/Basic/FileManager.h"
4e336b74cSManuel Klimek
5e336b74cSManuel Klimek #include "gtest/gtest.h"
6e336b74cSManuel Klimek
7e336b74cSManuel Klimek namespace clang {
8e336b74cSManuel Klimek namespace format {
9e336b74cSManuel Klimek
10e336b74cSManuel Klimek namespace {
11e336b74cSManuel Klimek
12*1c58208dSOwen Pan class MacroExpanderTest : public testing::Test {
13e336b74cSManuel Klimek public:
MacroExpanderTest()1475a1790fSAlex Richardson MacroExpanderTest() : Lex(Allocator, Buffers) {}
15e336b74cSManuel Klimek std::unique_ptr<MacroExpander>
create(const std::vector<std::string> & MacroDefinitions)16e336b74cSManuel Klimek create(const std::vector<std::string> &MacroDefinitions) {
17e336b74cSManuel Klimek return std::make_unique<MacroExpander>(MacroDefinitions,
18e336b74cSManuel Klimek Lex.SourceMgr.get(), Lex.Style,
19e336b74cSManuel Klimek Lex.Allocator, Lex.IdentTable);
20e336b74cSManuel Klimek }
21e336b74cSManuel Klimek
expand(MacroExpander & Macros,StringRef Name)22*1c58208dSOwen Pan std::string expand(MacroExpander &Macros, StringRef Name) {
2301402831SManuel Klimek EXPECT_TRUE(Macros.defined(Name))
2401402831SManuel Klimek << "Macro not defined: \"" << Name << "\"";
2501402831SManuel Klimek return text(Macros.expand(Lex.id(Name), {}));
2601402831SManuel Klimek }
2701402831SManuel Klimek
expand(MacroExpander & Macros,StringRef Name,const std::vector<std::string> & Args)28*1c58208dSOwen Pan std::string expand(MacroExpander &Macros, StringRef Name,
2901402831SManuel Klimek const std::vector<std::string> &Args) {
3001402831SManuel Klimek EXPECT_TRUE(Macros.defined(Name))
3101402831SManuel Klimek << "Macro not defined: \"" << Name << "\"";
32e336b74cSManuel Klimek return text(Macros.expand(Lex.id(Name), lexArgs(Args)));
33e336b74cSManuel Klimek }
34e336b74cSManuel Klimek
lexArgs(const std::vector<std::string> & Args)35*1c58208dSOwen Pan SmallVector<TokenList, 1> lexArgs(const std::vector<std::string> &Args) {
36*1c58208dSOwen Pan SmallVector<TokenList, 1> Result;
3734ce42feSMarek Kurdej for (const auto &Arg : Args)
38e336b74cSManuel Klimek Result.push_back(uneof(Lex.lex(Arg)));
39e336b74cSManuel Klimek return Result;
40e336b74cSManuel Klimek }
41e336b74cSManuel Klimek
42e336b74cSManuel Klimek struct MacroAttributes {
43*1c58208dSOwen Pan tok::TokenKind Kind;
44e336b74cSManuel Klimek MacroRole Role;
45e336b74cSManuel Klimek unsigned Start;
46e336b74cSManuel Klimek unsigned End;
47*1c58208dSOwen Pan SmallVector<FormatToken *, 1> ExpandedFrom;
48e336b74cSManuel Klimek };
49e336b74cSManuel Klimek
expectAttributes(const TokenList & Tokens,const std::vector<MacroAttributes> & Attributes,const std::string & File,unsigned Line)50e336b74cSManuel Klimek void expectAttributes(const TokenList &Tokens,
51e336b74cSManuel Klimek const std::vector<MacroAttributes> &Attributes,
52e336b74cSManuel Klimek const std::string &File, unsigned Line) {
53e336b74cSManuel Klimek EXPECT_EQ(Tokens.size(), Attributes.size()) << text(Tokens);
54e336b74cSManuel Klimek for (size_t I = 0, E = Tokens.size(); I != E; ++I) {
55e336b74cSManuel Klimek if (I >= Attributes.size())
56e336b74cSManuel Klimek continue;
57e336b74cSManuel Klimek std::string Context =
58*1c58208dSOwen Pan ("for token " + Twine(I) + ": " + Tokens[I]->Tok.getName() + " / " +
59*1c58208dSOwen Pan Tokens[I]->TokenText)
60e336b74cSManuel Klimek .str();
61e336b74cSManuel Klimek EXPECT_TRUE(Tokens[I]->is(Attributes[I].Kind))
62e336b74cSManuel Klimek << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
63e336b74cSManuel Klimek EXPECT_EQ(Tokens[I]->MacroCtx->Role, Attributes[I].Role)
64e336b74cSManuel Klimek << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
65e336b74cSManuel Klimek EXPECT_EQ(Tokens[I]->MacroCtx->StartOfExpansion, Attributes[I].Start)
66e336b74cSManuel Klimek << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
67e336b74cSManuel Klimek EXPECT_EQ(Tokens[I]->MacroCtx->EndOfExpansion, Attributes[I].End)
68e336b74cSManuel Klimek << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
69e336b74cSManuel Klimek EXPECT_EQ(Tokens[I]->MacroCtx->ExpandedFrom, Attributes[I].ExpandedFrom)
70e336b74cSManuel Klimek << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
71e336b74cSManuel Klimek }
72e336b74cSManuel Klimek }
730e226d00Smydeveloperday
7475a1790fSAlex Richardson protected:
7575a1790fSAlex Richardson llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
7675a1790fSAlex Richardson std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
77e336b74cSManuel Klimek TestLexer Lex;
78e336b74cSManuel Klimek };
79e336b74cSManuel Klimek
80e336b74cSManuel Klimek #define EXPECT_ATTRIBUTES(Tokens, Attributes) \
81e336b74cSManuel Klimek expectAttributes(Tokens, Attributes, __FILE__, __LINE__)
82e336b74cSManuel Klimek
TEST_F(MacroExpanderTest,SkipsDefinitionOnError)83e336b74cSManuel Klimek TEST_F(MacroExpanderTest, SkipsDefinitionOnError) {
84e336b74cSManuel Klimek auto Macros =
85e336b74cSManuel Klimek create({"A(", "B(,", "C(a,", "D(a a", "E(a, a", "F(,)", "G(a;"});
8634ce42feSMarek Kurdej for (const auto *Name : {"A", "B", "C", "D", "E", "F", "G"})
87e336b74cSManuel Klimek EXPECT_FALSE(Macros->defined(Name)) << "for Name " << Name;
88e336b74cSManuel Klimek }
89e336b74cSManuel Klimek
TEST_F(MacroExpanderTest,ExpandsWithoutArguments)90e336b74cSManuel Klimek TEST_F(MacroExpanderTest, ExpandsWithoutArguments) {
91e336b74cSManuel Klimek auto Macros = create({
92e336b74cSManuel Klimek "A",
93e336b74cSManuel Klimek "B=b",
94e336b74cSManuel Klimek "C=c + c",
95e336b74cSManuel Klimek "D()",
96e336b74cSManuel Klimek });
97e336b74cSManuel Klimek EXPECT_TRUE(Macros->objectLike("A"));
98e336b74cSManuel Klimek EXPECT_TRUE(Macros->objectLike("B"));
99e336b74cSManuel Klimek EXPECT_TRUE(Macros->objectLike("C"));
100e336b74cSManuel Klimek EXPECT_TRUE(!Macros->objectLike("D"));
101e336b74cSManuel Klimek EXPECT_EQ("", expand(*Macros, "A"));
102e336b74cSManuel Klimek EXPECT_EQ("b", expand(*Macros, "B"));
103e336b74cSManuel Klimek EXPECT_EQ("c+c", expand(*Macros, "C"));
10401402831SManuel Klimek EXPECT_EQ("", expand(*Macros, "D", {}));
105e336b74cSManuel Klimek }
106e336b74cSManuel Klimek
TEST_F(MacroExpanderTest,ExpandsWithArguments)107e336b74cSManuel Klimek TEST_F(MacroExpanderTest, ExpandsWithArguments) {
108e336b74cSManuel Klimek auto Macros = create({
109e336b74cSManuel Klimek "A(x)",
110e336b74cSManuel Klimek "B(x, y)=x + y",
111e336b74cSManuel Klimek });
112e336b74cSManuel Klimek EXPECT_EQ("", expand(*Macros, "A", {"a"}));
113e336b74cSManuel Klimek EXPECT_EQ("b1+b2+b3", expand(*Macros, "B", {"b1", "b2 + b3"}));
114e336b74cSManuel Klimek }
115e336b74cSManuel Klimek
TEST_F(MacroExpanderTest,AttributizesTokens)116e336b74cSManuel Klimek TEST_F(MacroExpanderTest, AttributizesTokens) {
117e336b74cSManuel Klimek auto Macros = create({
118e336b74cSManuel Klimek "A(x, y)={ x + y; }",
119e336b74cSManuel Klimek "B(x, y)=x + 3 + y",
120e336b74cSManuel Klimek });
121e336b74cSManuel Klimek auto *A = Lex.id("A");
122e336b74cSManuel Klimek auto AArgs = lexArgs({"a1 * a2", "a3 * a4"});
123e336b74cSManuel Klimek auto Result = Macros->expand(A, AArgs);
124e336b74cSManuel Klimek EXPECT_EQ(11U, Result.size()) << text(Result) << " / " << Result;
125e336b74cSManuel Klimek EXPECT_EQ("{a1*a2+a3*a4;}", text(Result));
126e336b74cSManuel Klimek std::vector<MacroAttributes> Attributes = {
127e336b74cSManuel Klimek {tok::l_brace, MR_Hidden, 1, 0, {A}},
128e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
129e336b74cSManuel Klimek {tok::star, MR_ExpandedArg, 0, 0, {A}},
130e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
131e336b74cSManuel Klimek {tok::plus, MR_Hidden, 0, 0, {A}},
132e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
133e336b74cSManuel Klimek {tok::star, MR_ExpandedArg, 0, 0, {A}},
134e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
135e336b74cSManuel Klimek {tok::semi, MR_Hidden, 0, 0, {A}},
136e336b74cSManuel Klimek {tok::r_brace, MR_Hidden, 0, 1, {A}},
137e336b74cSManuel Klimek {tok::eof, MR_Hidden, 0, 0, {A}},
138e336b74cSManuel Klimek };
139e336b74cSManuel Klimek EXPECT_ATTRIBUTES(Result, Attributes);
140e336b74cSManuel Klimek
141e336b74cSManuel Klimek auto *B = Lex.id("B");
142e336b74cSManuel Klimek auto BArgs = lexArgs({"b1", "b2"});
143e336b74cSManuel Klimek Result = Macros->expand(B, BArgs);
144e336b74cSManuel Klimek EXPECT_EQ(6U, Result.size()) << text(Result) << " / " << Result;
145e336b74cSManuel Klimek EXPECT_EQ("b1+3+b2", text(Result));
146e336b74cSManuel Klimek Attributes = {
147e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 1, 0, {B}},
148e336b74cSManuel Klimek {tok::plus, MR_Hidden, 0, 0, {B}},
149e336b74cSManuel Klimek {tok::numeric_constant, MR_Hidden, 0, 0, {B}},
150e336b74cSManuel Klimek {tok::plus, MR_Hidden, 0, 0, {B}},
151e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 0, 1, {B}},
152e336b74cSManuel Klimek {tok::eof, MR_Hidden, 0, 0, {B}},
153e336b74cSManuel Klimek };
154e336b74cSManuel Klimek EXPECT_ATTRIBUTES(Result, Attributes);
155e336b74cSManuel Klimek }
156e336b74cSManuel Klimek
TEST_F(MacroExpanderTest,RecursiveExpansion)157e336b74cSManuel Klimek TEST_F(MacroExpanderTest, RecursiveExpansion) {
158e336b74cSManuel Klimek auto Macros = create({
159e336b74cSManuel Klimek "A(x)=x",
160e336b74cSManuel Klimek "B(x)=x",
161e336b74cSManuel Klimek "C(x)=x",
162e336b74cSManuel Klimek });
163e336b74cSManuel Klimek
164e336b74cSManuel Klimek auto *A = Lex.id("A");
165e336b74cSManuel Klimek auto *B = Lex.id("B");
166e336b74cSManuel Klimek auto *C = Lex.id("C");
167e336b74cSManuel Klimek
168e336b74cSManuel Klimek auto Args = lexArgs({"id"});
169e336b74cSManuel Klimek auto CResult = uneof(Macros->expand(C, Args));
170e336b74cSManuel Klimek auto BResult = uneof(Macros->expand(B, CResult));
171e336b74cSManuel Klimek auto AResult = uneof(Macros->expand(A, BResult));
172e336b74cSManuel Klimek
173e336b74cSManuel Klimek std::vector<MacroAttributes> Attributes = {
174e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 3, 3, {C, B, A}},
175e336b74cSManuel Klimek };
176e336b74cSManuel Klimek EXPECT_ATTRIBUTES(AResult, Attributes);
177e336b74cSManuel Klimek }
178e336b74cSManuel Klimek
TEST_F(MacroExpanderTest,SingleExpansion)179e336b74cSManuel Klimek TEST_F(MacroExpanderTest, SingleExpansion) {
180e336b74cSManuel Klimek auto Macros = create({"A(x)=x+x"});
181e336b74cSManuel Klimek auto *A = Lex.id("A");
182e336b74cSManuel Klimek auto Args = lexArgs({"id"});
183e336b74cSManuel Klimek auto Result = uneof(Macros->expand(A, Args));
184e336b74cSManuel Klimek std::vector<MacroAttributes> Attributes = {
185e336b74cSManuel Klimek {tok::identifier, MR_ExpandedArg, 1, 0, {A}},
186e336b74cSManuel Klimek {tok::plus, MR_Hidden, 0, 0, {A}},
187e336b74cSManuel Klimek {tok::identifier, MR_Hidden, 0, 1, {A}},
188e336b74cSManuel Klimek };
189e336b74cSManuel Klimek EXPECT_ATTRIBUTES(Result, Attributes);
190e336b74cSManuel Klimek }
191e336b74cSManuel Klimek
TEST_F(MacroExpanderTest,UnderstandsCppTokens)192ff6e4441SAlex Richardson TEST_F(MacroExpanderTest, UnderstandsCppTokens) {
193ff6e4441SAlex Richardson auto Macros = create({"A(T,name)=T name = 0;"});
194ff6e4441SAlex Richardson auto *A = Lex.id("A");
195ff6e4441SAlex Richardson auto Args = lexArgs({"const int", "x"});
196ff6e4441SAlex Richardson auto Result = uneof(Macros->expand(A, Args));
197ff6e4441SAlex Richardson std::vector<MacroAttributes> Attributes = {
198ff6e4441SAlex Richardson {tok::kw_const, MR_ExpandedArg, 1, 0, {A}},
199ff6e4441SAlex Richardson {tok::kw_int, MR_ExpandedArg, 0, 0, {A}},
200ff6e4441SAlex Richardson {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
201ff6e4441SAlex Richardson {tok::equal, MR_Hidden, 0, 0, {A}},
202ff6e4441SAlex Richardson {tok::numeric_constant, MR_Hidden, 0, 0, {A}},
203ff6e4441SAlex Richardson {tok::semi, MR_Hidden, 0, 1, {A}},
204ff6e4441SAlex Richardson };
205ff6e4441SAlex Richardson EXPECT_ATTRIBUTES(Result, Attributes);
206ff6e4441SAlex Richardson }
207ff6e4441SAlex Richardson
TEST_F(MacroExpanderTest,Overloads)20801402831SManuel Klimek TEST_F(MacroExpanderTest, Overloads) {
20901402831SManuel Klimek auto Macros = create({"A=x", "A()=y", "A(a)=a", "A(a, b)=a b"});
21001402831SManuel Klimek EXPECT_EQ("x", expand(*Macros, "A"));
21101402831SManuel Klimek EXPECT_EQ("y", expand(*Macros, "A", {}));
21201402831SManuel Klimek EXPECT_EQ("z", expand(*Macros, "A", {"z"}));
21301402831SManuel Klimek EXPECT_EQ("xy", expand(*Macros, "A", {"x", "y"}));
21401402831SManuel Klimek }
21501402831SManuel Klimek
216e336b74cSManuel Klimek } // namespace
217e336b74cSManuel Klimek } // namespace format
218e336b74cSManuel Klimek } // namespace clang
219