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