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