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