xref: /llvm-project/clang/unittests/Format/MacroExpanderTest.cpp (revision 1c58208d899285318c89e069268145c85ec33368)
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