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