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

source code of clang/unittests/Format/MacroExpanderTest.cpp