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<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(Start), 42 SM.getCharacterData(Loc.getEnd())); 43 44 bool Invalid; 45 unsigned CLine = SM.getSpellingLineNumber(Start, &Invalid); 46 EXPECT_TRUE(!Invalid) << "Invalid line number on comment " << C; 47 48 unsigned CCol = SM.getSpellingColumnNumber(Start, &Invalid); 49 EXPECT_TRUE(!Invalid) << "Invalid column number on comment " << C; 50 51 Comments.push_back(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>(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(V); 77 return true; 78 } 79 80 void EndSourceFileAction() override { 81 CommentHandlerVisitor *V = 82 static_cast<CommentHandlerVisitor*>(this->Visitor); 83 V->PP->removeCommentHandler(V); 84 } 85 }; 86 }; 87 88 class CommentVerifier { 89 CommentList::const_iterator Current; 90 CommentList::const_iterator End; 91 Preprocessor *PP; 92 93 public: 94 CommentVerifier(const CommentList &Comments, Preprocessor *PP) 95 : Current(Comments.begin()), End(Comments.end()), PP(PP) 96 { } 97 98 CommentVerifier(CommentVerifier &&C) : Current(C.Current), End(C.End), PP(C.PP) { 99 C.Current = C.End; 100 } 101 102 ~CommentVerifier() { 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 Match(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("/* comment */", 1, 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("// comment 1", 1, 13); 155 Verifier.Match("// comment 2", 3, 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("// visible comment", 4, 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("// 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); 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(Source, 1, 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("// visible_2", 2, 14); 220 Verifier.Match("// visible_3", 3, 14); 221 } 222 223 } // end namespace clang 224