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