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