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 
12e336b74cSManuel Klimek 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,llvm::StringRef Name,const std::vector<std::string> & Args={})22e336b74cSManuel Klimek   std::string expand(MacroExpander &Macros, llvm::StringRef Name,
23e336b74cSManuel Klimek                      const std::vector<std::string> &Args = {}) {
24e336b74cSManuel Klimek     EXPECT_TRUE(Macros.defined(Name));
25e336b74cSManuel Klimek     return text(Macros.expand(Lex.id(Name), lexArgs(Args)));
26e336b74cSManuel Klimek   }
27e336b74cSManuel Klimek 
28e336b74cSManuel Klimek   llvm::SmallVector<TokenList, 1>
lexArgs(const std::vector<std::string> & Args)29e336b74cSManuel Klimek   lexArgs(const std::vector<std::string> &Args) {
30e336b74cSManuel Klimek     llvm::SmallVector<TokenList, 1> Result;
31*34ce42feSMarek Kurdej     for (const auto &Arg : Args)
32e336b74cSManuel Klimek       Result.push_back(uneof(Lex.lex(Arg)));
33e336b74cSManuel Klimek     return Result;
34e336b74cSManuel Klimek   }
35e336b74cSManuel Klimek 
36e336b74cSManuel Klimek   struct MacroAttributes {
37e336b74cSManuel Klimek     clang::tok::TokenKind Kind;
38e336b74cSManuel Klimek     MacroRole Role;
39e336b74cSManuel Klimek     unsigned Start;
40e336b74cSManuel Klimek     unsigned End;
41e336b74cSManuel Klimek     llvm::SmallVector<FormatToken *, 1> ExpandedFrom;
42e336b74cSManuel Klimek   };
43e336b74cSManuel Klimek 
expectAttributes(const TokenList & Tokens,const std::vector<MacroAttributes> & Attributes,const std::string & File,unsigned Line)44e336b74cSManuel Klimek   void expectAttributes(const TokenList &Tokens,
45e336b74cSManuel Klimek                         const std::vector<MacroAttributes> &Attributes,
46e336b74cSManuel Klimek                         const std::string &File, unsigned Line) {
47e336b74cSManuel Klimek     EXPECT_EQ(Tokens.size(), Attributes.size()) << text(Tokens);
48e336b74cSManuel Klimek     for (size_t I = 0, E = Tokens.size(); I != E; ++I) {
49e336b74cSManuel Klimek       if (I >= Attributes.size())
50e336b74cSManuel Klimek         continue;
51e336b74cSManuel Klimek       std::string Context =
52e336b74cSManuel Klimek           ("for token " + llvm::Twine(I) + ": " + Tokens[I]->Tok.getName() +
53e336b74cSManuel Klimek            " / " + Tokens[I]->TokenText)
54e336b74cSManuel Klimek               .str();
55e336b74cSManuel Klimek       EXPECT_TRUE(Tokens[I]->is(Attributes[I].Kind))
56e336b74cSManuel Klimek           << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
57e336b74cSManuel Klimek       EXPECT_EQ(Tokens[I]->MacroCtx->Role, Attributes[I].Role)
58e336b74cSManuel Klimek           << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
59e336b74cSManuel Klimek       EXPECT_EQ(Tokens[I]->MacroCtx->StartOfExpansion, Attributes[I].Start)
60e336b74cSManuel Klimek           << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
61e336b74cSManuel Klimek       EXPECT_EQ(Tokens[I]->MacroCtx->EndOfExpansion, Attributes[I].End)
62e336b74cSManuel Klimek           << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
63e336b74cSManuel Klimek       EXPECT_EQ(Tokens[I]->MacroCtx->ExpandedFrom, Attributes[I].ExpandedFrom)
64e336b74cSManuel Klimek           << Context << " in " << text(Tokens) << " at " << File << ":" << Line;
65e336b74cSManuel Klimek     }
66e336b74cSManuel Klimek   }
670e226d00Smydeveloperday 
6875a1790fSAlex Richardson protected:
6975a1790fSAlex Richardson   llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
7075a1790fSAlex Richardson   std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
71e336b74cSManuel Klimek   TestLexer Lex;
72e336b74cSManuel Klimek };
73e336b74cSManuel Klimek 
74e336b74cSManuel Klimek #define EXPECT_ATTRIBUTES(Tokens, Attributes)                                  \
75e336b74cSManuel Klimek   expectAttributes(Tokens, Attributes, __FILE__, __LINE__)
76e336b74cSManuel Klimek 
TEST_F(MacroExpanderTest,SkipsDefinitionOnError)77e336b74cSManuel Klimek TEST_F(MacroExpanderTest, SkipsDefinitionOnError) {
78e336b74cSManuel Klimek   auto Macros =
79e336b74cSManuel Klimek       create({"A(", "B(,", "C(a,", "D(a a", "E(a, a", "F(,)", "G(a;"});
80*34ce42feSMarek Kurdej   for (const auto *Name : {"A", "B", "C", "D", "E", "F", "G"})
81e336b74cSManuel Klimek     EXPECT_FALSE(Macros->defined(Name)) << "for Name " << Name;
82e336b74cSManuel Klimek }
83e336b74cSManuel Klimek 
TEST_F(MacroExpanderTest,ExpandsWithoutArguments)84e336b74cSManuel Klimek TEST_F(MacroExpanderTest, ExpandsWithoutArguments) {
85e336b74cSManuel Klimek   auto Macros = create({
86e336b74cSManuel Klimek       "A",
87e336b74cSManuel Klimek       "B=b",
88e336b74cSManuel Klimek       "C=c + c",
89e336b74cSManuel Klimek       "D()",
90e336b74cSManuel Klimek   });
91e336b74cSManuel Klimek   EXPECT_TRUE(Macros->objectLike("A"));
92e336b74cSManuel Klimek   EXPECT_TRUE(Macros->objectLike("B"));
93e336b74cSManuel Klimek   EXPECT_TRUE(Macros->objectLike("C"));
94e336b74cSManuel Klimek   EXPECT_TRUE(!Macros->objectLike("D"));
95e336b74cSManuel Klimek   EXPECT_EQ("", expand(*Macros, "A"));
96e336b74cSManuel Klimek   EXPECT_EQ("b", expand(*Macros, "B"));
97e336b74cSManuel Klimek   EXPECT_EQ("c+c", expand(*Macros, "C"));
98e336b74cSManuel Klimek   EXPECT_EQ("", expand(*Macros, "D"));
99e336b74cSManuel Klimek }
100e336b74cSManuel Klimek 
TEST_F(MacroExpanderTest,ExpandsWithArguments)101e336b74cSManuel Klimek TEST_F(MacroExpanderTest, ExpandsWithArguments) {
102e336b74cSManuel Klimek   auto Macros = create({
103e336b74cSManuel Klimek       "A(x)",
104e336b74cSManuel Klimek       "B(x, y)=x + y",
105e336b74cSManuel Klimek   });
106e336b74cSManuel Klimek   EXPECT_EQ("", expand(*Macros, "A", {"a"}));
107e336b74cSManuel Klimek   EXPECT_EQ("b1+b2+b3", expand(*Macros, "B", {"b1", "b2 + b3"}));
108e336b74cSManuel Klimek   EXPECT_EQ("x+", expand(*Macros, "B", {"x"}));
109e336b74cSManuel Klimek }
110e336b74cSManuel Klimek 
TEST_F(MacroExpanderTest,AttributizesTokens)111e336b74cSManuel Klimek TEST_F(MacroExpanderTest, AttributizesTokens) {
112e336b74cSManuel Klimek   auto Macros = create({
113e336b74cSManuel Klimek       "A(x, y)={ x + y; }",
114e336b74cSManuel Klimek       "B(x, y)=x + 3 + y",
115e336b74cSManuel Klimek   });
116e336b74cSManuel Klimek   auto *A = Lex.id("A");
117e336b74cSManuel Klimek   auto AArgs = lexArgs({"a1 * a2", "a3 * a4"});
118e336b74cSManuel Klimek   auto Result = Macros->expand(A, AArgs);
119e336b74cSManuel Klimek   EXPECT_EQ(11U, Result.size()) << text(Result) << " / " << Result;
120e336b74cSManuel Klimek   EXPECT_EQ("{a1*a2+a3*a4;}", text(Result));
121e336b74cSManuel Klimek   std::vector<MacroAttributes> Attributes = {
122e336b74cSManuel Klimek       {tok::l_brace, MR_Hidden, 1, 0, {A}},
123e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
124e336b74cSManuel Klimek       {tok::star, MR_ExpandedArg, 0, 0, {A}},
125e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
126e336b74cSManuel Klimek       {tok::plus, MR_Hidden, 0, 0, {A}},
127e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
128e336b74cSManuel Klimek       {tok::star, MR_ExpandedArg, 0, 0, {A}},
129e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
130e336b74cSManuel Klimek       {tok::semi, MR_Hidden, 0, 0, {A}},
131e336b74cSManuel Klimek       {tok::r_brace, MR_Hidden, 0, 1, {A}},
132e336b74cSManuel Klimek       {tok::eof, MR_Hidden, 0, 0, {A}},
133e336b74cSManuel Klimek   };
134e336b74cSManuel Klimek   EXPECT_ATTRIBUTES(Result, Attributes);
135e336b74cSManuel Klimek 
136e336b74cSManuel Klimek   auto *B = Lex.id("B");
137e336b74cSManuel Klimek   auto BArgs = lexArgs({"b1", "b2"});
138e336b74cSManuel Klimek   Result = Macros->expand(B, BArgs);
139e336b74cSManuel Klimek   EXPECT_EQ(6U, Result.size()) << text(Result) << " / " << Result;
140e336b74cSManuel Klimek   EXPECT_EQ("b1+3+b2", text(Result));
141e336b74cSManuel Klimek   Attributes = {
142e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 1, 0, {B}},
143e336b74cSManuel Klimek       {tok::plus, MR_Hidden, 0, 0, {B}},
144e336b74cSManuel Klimek       {tok::numeric_constant, MR_Hidden, 0, 0, {B}},
145e336b74cSManuel Klimek       {tok::plus, MR_Hidden, 0, 0, {B}},
146e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 0, 1, {B}},
147e336b74cSManuel Klimek       {tok::eof, MR_Hidden, 0, 0, {B}},
148e336b74cSManuel Klimek   };
149e336b74cSManuel Klimek   EXPECT_ATTRIBUTES(Result, Attributes);
150e336b74cSManuel Klimek }
151e336b74cSManuel Klimek 
TEST_F(MacroExpanderTest,RecursiveExpansion)152e336b74cSManuel Klimek TEST_F(MacroExpanderTest, RecursiveExpansion) {
153e336b74cSManuel Klimek   auto Macros = create({
154e336b74cSManuel Klimek       "A(x)=x",
155e336b74cSManuel Klimek       "B(x)=x",
156e336b74cSManuel Klimek       "C(x)=x",
157e336b74cSManuel Klimek   });
158e336b74cSManuel Klimek 
159e336b74cSManuel Klimek   auto *A = Lex.id("A");
160e336b74cSManuel Klimek   auto *B = Lex.id("B");
161e336b74cSManuel Klimek   auto *C = Lex.id("C");
162e336b74cSManuel Klimek 
163e336b74cSManuel Klimek   auto Args = lexArgs({"id"});
164e336b74cSManuel Klimek   auto CResult = uneof(Macros->expand(C, Args));
165e336b74cSManuel Klimek   auto BResult = uneof(Macros->expand(B, CResult));
166e336b74cSManuel Klimek   auto AResult = uneof(Macros->expand(A, BResult));
167e336b74cSManuel Klimek 
168e336b74cSManuel Klimek   std::vector<MacroAttributes> Attributes = {
169e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 3, 3, {C, B, A}},
170e336b74cSManuel Klimek   };
171e336b74cSManuel Klimek   EXPECT_ATTRIBUTES(AResult, Attributes);
172e336b74cSManuel Klimek }
173e336b74cSManuel Klimek 
TEST_F(MacroExpanderTest,SingleExpansion)174e336b74cSManuel Klimek TEST_F(MacroExpanderTest, SingleExpansion) {
175e336b74cSManuel Klimek   auto Macros = create({"A(x)=x+x"});
176e336b74cSManuel Klimek   auto *A = Lex.id("A");
177e336b74cSManuel Klimek   auto Args = lexArgs({"id"});
178e336b74cSManuel Klimek   auto Result = uneof(Macros->expand(A, Args));
179e336b74cSManuel Klimek   std::vector<MacroAttributes> Attributes = {
180e336b74cSManuel Klimek       {tok::identifier, MR_ExpandedArg, 1, 0, {A}},
181e336b74cSManuel Klimek       {tok::plus, MR_Hidden, 0, 0, {A}},
182e336b74cSManuel Klimek       {tok::identifier, MR_Hidden, 0, 1, {A}},
183e336b74cSManuel Klimek   };
184e336b74cSManuel Klimek   EXPECT_ATTRIBUTES(Result, Attributes);
185e336b74cSManuel Klimek }
186e336b74cSManuel Klimek 
TEST_F(MacroExpanderTest,UnderstandsCppTokens)187ff6e4441SAlex Richardson TEST_F(MacroExpanderTest, UnderstandsCppTokens) {
188ff6e4441SAlex Richardson   auto Macros = create({"A(T,name)=T name = 0;"});
189ff6e4441SAlex Richardson   auto *A = Lex.id("A");
190ff6e4441SAlex Richardson   auto Args = lexArgs({"const int", "x"});
191ff6e4441SAlex Richardson   auto Result = uneof(Macros->expand(A, Args));
192ff6e4441SAlex Richardson   std::vector<MacroAttributes> Attributes = {
193ff6e4441SAlex Richardson       {tok::kw_const, MR_ExpandedArg, 1, 0, {A}},
194ff6e4441SAlex Richardson       {tok::kw_int, MR_ExpandedArg, 0, 0, {A}},
195ff6e4441SAlex Richardson       {tok::identifier, MR_ExpandedArg, 0, 0, {A}},
196ff6e4441SAlex Richardson       {tok::equal, MR_Hidden, 0, 0, {A}},
197ff6e4441SAlex Richardson       {tok::numeric_constant, MR_Hidden, 0, 0, {A}},
198ff6e4441SAlex Richardson       {tok::semi, MR_Hidden, 0, 1, {A}},
199ff6e4441SAlex Richardson   };
200ff6e4441SAlex Richardson   EXPECT_ATTRIBUTES(Result, Attributes);
201ff6e4441SAlex Richardson }
202ff6e4441SAlex Richardson 
203e336b74cSManuel Klimek } // namespace
204e336b74cSManuel Klimek } // namespace format
205e336b74cSManuel Klimek } // namespace clang
206