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 | MacroExpanderTest() : Lex(Allocator, Buffers) {} |
15 | std::unique_ptr<MacroExpander> |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |