1 #include "../../lib/Format/Macros.h"
3 #include "clang/Basic/FileManager.h"
5 #include "gtest/gtest.h"
12 class MacroExpanderTest
: public ::testing::Test
{
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
);
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
), {}));
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
)));
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
)));
43 struct MacroAttributes
{
44 clang::tok::TokenKind Kind
;
48 llvm::SmallVector
<FormatToken
*, 1> ExpandedFrom
;
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())
59 ("for token " + llvm::Twine(I
) + ": " + Tokens
[I
]->Tok
.getName() +
60 " / " + Tokens
[I
]->TokenText
)
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
;
76 llvm::SpecificBumpPtrAllocator
<FormatToken
> Allocator
;
77 std::vector
<std::unique_ptr
<llvm::MemoryBuffer
>> Buffers
;
81 #define EXPECT_ATTRIBUTES(Tokens, Attributes) \
82 expectAttributes(Tokens, Attributes, __FILE__, __LINE__)
84 TEST_F(MacroExpanderTest
, SkipsDefinitionOnError
) {
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
;
91 TEST_F(MacroExpanderTest
, ExpandsWithoutArguments
) {
92 auto Macros
= create({
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", {}));
108 TEST_F(MacroExpanderTest
, ExpandsWithArguments
) {
109 auto Macros
= create({
113 EXPECT_EQ("", expand(*Macros
, "A", {"a"}));
114 EXPECT_EQ("b1+b2+b3", expand(*Macros
, "B", {"b1", "b2 + b3"}));
117 TEST_F(MacroExpanderTest
, AttributizesTokens
) {
118 auto Macros
= create({
119 "A(x, y)={ x + y; }",
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
}},
140 EXPECT_ATTRIBUTES(Result
, Attributes
);
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
));
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
}},
155 EXPECT_ATTRIBUTES(Result
, Attributes
);
158 TEST_F(MacroExpanderTest
, RecursiveExpansion
) {
159 auto Macros
= create({
165 auto *A
= Lex
.id("A");
166 auto *B
= Lex
.id("B");
167 auto *C
= Lex
.id("C");
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
));
174 std::vector
<MacroAttributes
> Attributes
= {
175 {tok::identifier
, MR_ExpandedArg
, 3, 3, {C
, B
, A
}},
177 EXPECT_ATTRIBUTES(AResult
, Attributes
);
180 TEST_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
}},
190 EXPECT_ATTRIBUTES(Result
, Attributes
);
193 TEST_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
}},
206 EXPECT_ATTRIBUTES(Result
, Attributes
);
209 TEST_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"}));
218 } // namespace format