1 //===- unittest/Tooling/CommentHandlerTest.cpp -----------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "TestVisitor.h"
10 #include "clang/Lex/Preprocessor.h"
15 Comment(const std::string
&Message
, unsigned Line
, unsigned Col
)
16 : Message(Message
), Line(Line
), Col(Col
) { }
22 class CommentVerifier
;
23 typedef std::vector
<Comment
> CommentList
;
25 class CommentHandlerVisitor
: public TestVisitor
<CommentHandlerVisitor
>,
26 public CommentHandler
{
27 typedef TestVisitor
<CommentHandlerVisitor
> base
;
30 CommentHandlerVisitor() : base(), PP(nullptr), Verified(false) {}
32 ~CommentHandlerVisitor() override
{
33 EXPECT_TRUE(Verified
) << "CommentVerifier not accessed";
36 bool HandleComment(Preprocessor
&PP
, SourceRange Loc
) override
{
37 assert(&PP
== this->PP
&& "Preprocessor changed!");
39 SourceLocation Start
= Loc
.getBegin();
40 SourceManager
&SM
= PP
.getSourceManager();
41 std::string
C(SM
.getCharacterData(Start
),
42 SM
.getCharacterData(Loc
.getEnd()));
45 unsigned CLine
= SM
.getSpellingLineNumber(Start
, &Invalid
);
46 EXPECT_TRUE(!Invalid
) << "Invalid line number on comment " << C
;
48 unsigned CCol
= SM
.getSpellingColumnNumber(Start
, &Invalid
);
49 EXPECT_TRUE(!Invalid
) << "Invalid column number on comment " << C
;
51 Comments
.push_back(Comment(C
, CLine
, CCol
));
55 CommentVerifier
GetVerifier();
58 std::unique_ptr
<ASTFrontendAction
> CreateTestAction() override
{
59 return std::make_unique
<CommentHandlerAction
>(this);
67 class CommentHandlerAction
: public base::TestAction
{
69 CommentHandlerAction(CommentHandlerVisitor
*Visitor
)
70 : TestAction(Visitor
) { }
72 bool BeginSourceFileAction(CompilerInstance
&CI
) override
{
73 CommentHandlerVisitor
*V
=
74 static_cast<CommentHandlerVisitor
*>(this->Visitor
);
75 V
->PP
= &CI
.getPreprocessor();
76 V
->PP
->addCommentHandler(V
);
80 void EndSourceFileAction() override
{
81 CommentHandlerVisitor
*V
=
82 static_cast<CommentHandlerVisitor
*>(this->Visitor
);
83 V
->PP
->removeCommentHandler(V
);
88 class CommentVerifier
{
89 CommentList::const_iterator Current
;
90 CommentList::const_iterator End
;
94 CommentVerifier(const CommentList
&Comments
, Preprocessor
*PP
)
95 : Current(Comments
.begin()), End(Comments
.end()), PP(PP
)
98 CommentVerifier(CommentVerifier
&&C
) : Current(C
.Current
), End(C
.End
), PP(C
.PP
) {
103 if (Current
!= End
) {
104 EXPECT_TRUE(Current
== End
) << "Unexpected comment \""
105 << Current
->Message
<< "\" at line " << Current
->Line
<< ", column "
110 void Match(const char *Message
, unsigned Line
, unsigned Col
) {
111 EXPECT_TRUE(Current
!= End
) << "Comment " << Message
<< " not found";
112 if (Current
== End
) return;
114 const Comment
&C
= *Current
;
115 EXPECT_TRUE(C
.Message
== Message
&& C
.Line
== Line
&& C
.Col
== Col
)
116 << "Expected comment \"" << Message
117 << "\" at line " << Line
<< ", column " << Col
118 << "\nActual comment \"" << C
.Message
119 << "\" at line " << C
.Line
<< ", column " << C
.Col
;
125 CommentVerifier
CommentHandlerVisitor::GetVerifier() {
127 return CommentVerifier(Comments
, PP
);
131 TEST(CommentHandlerTest
, BasicTest1
) {
132 CommentHandlerVisitor Visitor
;
133 EXPECT_TRUE(Visitor
.runOver("class X {}; int main() { return 0; }"));
134 CommentVerifier Verifier
= Visitor
.GetVerifier();
137 TEST(CommentHandlerTest
, BasicTest2
) {
138 CommentHandlerVisitor Visitor
;
139 EXPECT_TRUE(Visitor
.runOver(
140 "class X {}; int main() { /* comment */ return 0; }"));
141 CommentVerifier Verifier
= Visitor
.GetVerifier();
142 Verifier
.Match("/* comment */", 1, 26);
145 TEST(CommentHandlerTest
, BasicTest3
) {
146 CommentHandlerVisitor Visitor
;
147 EXPECT_TRUE(Visitor
.runOver(
148 "class X {}; // comment 1\n"
153 CommentVerifier Verifier
= Visitor
.GetVerifier();
154 Verifier
.Match("// comment 1", 1, 13);
155 Verifier
.Match("// comment 2", 3, 3);
158 TEST(CommentHandlerTest
, IfBlock1
) {
159 CommentHandlerVisitor Visitor
;
160 EXPECT_TRUE(Visitor
.runOver(
162 "// ignored comment\n"
164 "// visible comment\n"));
165 CommentVerifier Verifier
= Visitor
.GetVerifier();
166 Verifier
.Match("// visible comment", 4, 1);
169 TEST(CommentHandlerTest
, IfBlock2
) {
170 CommentHandlerVisitor Visitor
;
171 EXPECT_TRUE(Visitor
.runOver(
172 "#define TEST // visible_1\n"
173 "#ifndef TEST // visible_2\n"
175 "# ifdef UNDEFINED // ignored_4\n"
176 "# endif // ignored_5\n"
177 "#elif defined(TEST) // visible_6\n"
178 "# if 1 // visible_7\n"
180 "# else // visible_9\n"
182 "# ifndef TEST // ignored_11\n"
183 "# endif // ignored_12\n"
184 "# endif // visible_13\n"
185 "#endif // visible_14\n"));
187 CommentVerifier Verifier
= Visitor
.GetVerifier();
188 Verifier
.Match("// visible_1", 1, 21);
189 Verifier
.Match("// visible_2", 2, 21);
190 Verifier
.Match("// visible_6", 6, 21);
191 Verifier
.Match("// visible_7", 7, 21);
192 Verifier
.Match("// visible_8", 8, 21);
193 Verifier
.Match("// visible_9", 9, 21);
194 Verifier
.Match("// visible_13", 13, 21);
195 Verifier
.Match("// visible_14", 14, 21);
198 TEST(CommentHandlerTest
, IfBlock3
) {
200 "/* commented out ...\n"
205 CommentHandlerVisitor Visitor
;
206 EXPECT_TRUE(Visitor
.runOver(Source
));
207 CommentVerifier Verifier
= Visitor
.GetVerifier();
208 Verifier
.Match(Source
, 1, 1);
211 TEST(CommentHandlerTest
, PPDirectives
) {
212 CommentHandlerVisitor Visitor
;
213 EXPECT_TRUE(Visitor
.runOver(
214 "#warning Y // ignored_1\n" // #warning takes whole line as message
215 "#undef MACRO // visible_2\n"
216 "#line 1 // visible_3\n"));
218 CommentVerifier Verifier
= Visitor
.GetVerifier();
219 Verifier
.Match("// visible_2", 2, 14);
220 Verifier
.Match("// visible_3", 3, 14);
223 } // end namespace clang