1 | //===- unittest/Tooling/CommentHandlerTest.cpp -----------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "TestVisitor.h" |
10 | #include "clang/Lex/Preprocessor.h" |
11 | |
12 | namespace clang { |
13 | |
14 | struct { |
15 | (const std::string &Message, unsigned Line, unsigned Col) |
16 | : Message(Message), Line(Line), Col(Col) { } |
17 | |
18 | std::string ; |
19 | unsigned , ; |
20 | }; |
21 | |
22 | class CommentVerifier; |
23 | typedef std::vector<Comment> ; |
24 | |
25 | class CommentHandlerVisitor : public TestVisitor<CommentHandlerVisitor>, |
26 | public CommentHandler { |
27 | typedef TestVisitor<CommentHandlerVisitor> base; |
28 | |
29 | public: |
30 | CommentHandlerVisitor() : base(), PP(nullptr), Verified(false) {} |
31 | |
32 | ~CommentHandlerVisitor() override { |
33 | EXPECT_TRUE(Verified) << "CommentVerifier not accessed" ; |
34 | } |
35 | |
36 | bool HandleComment(Preprocessor &PP, SourceRange Loc) override { |
37 | assert(&PP == this->PP && "Preprocessor changed!" ); |
38 | |
39 | SourceLocation Start = Loc.getBegin(); |
40 | SourceManager &SM = PP.getSourceManager(); |
41 | std::string C(SM.getCharacterData(SL: Start), |
42 | SM.getCharacterData(SL: Loc.getEnd())); |
43 | |
44 | bool Invalid; |
45 | unsigned CLine = SM.getSpellingLineNumber(Loc: Start, Invalid: &Invalid); |
46 | EXPECT_TRUE(!Invalid) << "Invalid line number on comment " << C; |
47 | |
48 | unsigned CCol = SM.getSpellingColumnNumber(Loc: Start, Invalid: &Invalid); |
49 | EXPECT_TRUE(!Invalid) << "Invalid column number on comment " << C; |
50 | |
51 | Comments.push_back(x: Comment(C, CLine, CCol)); |
52 | return false; |
53 | } |
54 | |
55 | CommentVerifier GetVerifier(); |
56 | |
57 | protected: |
58 | std::unique_ptr<ASTFrontendAction> CreateTestAction() override { |
59 | return std::make_unique<CommentHandlerAction>(args: this); |
60 | } |
61 | |
62 | private: |
63 | Preprocessor *PP; |
64 | CommentList Comments; |
65 | bool Verified; |
66 | |
67 | class CommentHandlerAction : public base::TestAction { |
68 | public: |
69 | CommentHandlerAction(CommentHandlerVisitor *Visitor) |
70 | : TestAction(Visitor) { } |
71 | |
72 | bool BeginSourceFileAction(CompilerInstance &CI) override { |
73 | CommentHandlerVisitor *V = |
74 | static_cast<CommentHandlerVisitor*>(this->Visitor); |
75 | V->PP = &CI.getPreprocessor(); |
76 | V->PP->addCommentHandler(Handler: V); |
77 | return true; |
78 | } |
79 | |
80 | void EndSourceFileAction() override { |
81 | CommentHandlerVisitor *V = |
82 | static_cast<CommentHandlerVisitor*>(this->Visitor); |
83 | V->PP->removeCommentHandler(Handler: V); |
84 | } |
85 | }; |
86 | }; |
87 | |
88 | class { |
89 | CommentList::const_iterator ; |
90 | CommentList::const_iterator ; |
91 | Preprocessor *; |
92 | |
93 | public: |
94 | (const CommentList &, Preprocessor *PP) |
95 | : Current(Comments.begin()), End(Comments.end()), PP(PP) |
96 | { } |
97 | |
98 | (CommentVerifier &&C) : Current(C.Current), End(C.End), PP(C.PP) { |
99 | C.Current = C.End; |
100 | } |
101 | |
102 | () { |
103 | if (Current != End) { |
104 | EXPECT_TRUE(Current == End) << "Unexpected comment \"" |
105 | << Current->Message << "\" at line " << Current->Line << ", column " |
106 | << Current->Col; |
107 | } |
108 | } |
109 | |
110 | void (const char *Message, unsigned Line, unsigned Col) { |
111 | EXPECT_TRUE(Current != End) << "Comment " << Message << " not found" ; |
112 | if (Current == End) return; |
113 | |
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; |
120 | |
121 | ++Current; |
122 | } |
123 | }; |
124 | |
125 | CommentVerifier CommentHandlerVisitor::GetVerifier() { |
126 | Verified = true; |
127 | return CommentVerifier(Comments, PP); |
128 | } |
129 | |
130 | |
131 | TEST(CommentHandlerTest, BasicTest1) { |
132 | CommentHandlerVisitor Visitor; |
133 | EXPECT_TRUE(Visitor.runOver("class X {}; int main() { return 0; }" )); |
134 | CommentVerifier Verifier = Visitor.GetVerifier(); |
135 | } |
136 | |
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(Message: "/* comment */" , Line: 1, Col: 26); |
143 | } |
144 | |
145 | TEST(CommentHandlerTest, BasicTest3) { |
146 | CommentHandlerVisitor Visitor; |
147 | EXPECT_TRUE(Visitor.runOver( |
148 | "class X {}; // comment 1\n" |
149 | "int main() {\n" |
150 | " // comment 2\n" |
151 | " return 0;\n" |
152 | "}" )); |
153 | CommentVerifier Verifier = Visitor.GetVerifier(); |
154 | Verifier.Match(Message: "// comment 1" , Line: 1, Col: 13); |
155 | Verifier.Match(Message: "// comment 2" , Line: 3, Col: 3); |
156 | } |
157 | |
158 | TEST(CommentHandlerTest, IfBlock1) { |
159 | CommentHandlerVisitor Visitor; |
160 | EXPECT_TRUE(Visitor.runOver( |
161 | "#if 0\n" |
162 | "// ignored comment\n" |
163 | "#endif\n" |
164 | "// visible comment\n" )); |
165 | CommentVerifier Verifier = Visitor.GetVerifier(); |
166 | Verifier.Match(Message: "// visible comment" , Line: 4, Col: 1); |
167 | } |
168 | |
169 | TEST(CommentHandlerTest, IfBlock2) { |
170 | CommentHandlerVisitor Visitor; |
171 | EXPECT_TRUE(Visitor.runOver( |
172 | "#define TEST // visible_1\n" |
173 | "#ifndef TEST // visible_2\n" |
174 | " // ignored_3\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" |
179 | " // visible_8\n" |
180 | "# else // visible_9\n" |
181 | " // ignored_10\n" |
182 | "# ifndef TEST // ignored_11\n" |
183 | "# endif // ignored_12\n" |
184 | "# endif // visible_13\n" |
185 | "#endif // visible_14\n" )); |
186 | |
187 | CommentVerifier Verifier = Visitor.GetVerifier(); |
188 | Verifier.Match(Message: "// visible_1" , Line: 1, Col: 21); |
189 | Verifier.Match(Message: "// visible_2" , Line: 2, Col: 21); |
190 | Verifier.Match(Message: "// visible_6" , Line: 6, Col: 21); |
191 | Verifier.Match(Message: "// visible_7" , Line: 7, Col: 21); |
192 | Verifier.Match(Message: "// visible_8" , Line: 8, Col: 21); |
193 | Verifier.Match(Message: "// visible_9" , Line: 9, Col: 21); |
194 | Verifier.Match(Message: "// visible_13" , Line: 13, Col: 21); |
195 | Verifier.Match(Message: "// visible_14" , Line: 14, Col: 21); |
196 | } |
197 | |
198 | TEST(CommentHandlerTest, IfBlock3) { |
199 | const char *Source = |
200 | "/* commented out ...\n" |
201 | "#if 0\n" |
202 | "// enclosed\n" |
203 | "#endif */" ; |
204 | |
205 | CommentHandlerVisitor Visitor; |
206 | EXPECT_TRUE(Visitor.runOver(Source)); |
207 | CommentVerifier Verifier = Visitor.GetVerifier(); |
208 | Verifier.Match(Message: Source, Line: 1, Col: 1); |
209 | } |
210 | |
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" )); |
217 | |
218 | CommentVerifier Verifier = Visitor.GetVerifier(); |
219 | Verifier.Match(Message: "// visible_2" , Line: 2, Col: 14); |
220 | Verifier.Match(Message: "// visible_3" , Line: 3, Col: 14); |
221 | } |
222 | |
223 | } // end namespace clang |
224 | |