187d8fb91SRichard Smith //===- unittest/Tooling/CommentHandlerTest.cpp -----------------------===// 287d8fb91SRichard Smith // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 687d8fb91SRichard Smith // 787d8fb91SRichard Smith //===----------------------------------------------------------------------===// 887d8fb91SRichard Smith 987d8fb91SRichard Smith #include "TestVisitor.h" 1087d8fb91SRichard Smith #include "clang/Lex/Preprocessor.h" 1187d8fb91SRichard Smith 1287d8fb91SRichard Smith namespace clang { 1387d8fb91SRichard Smith 1487d8fb91SRichard Smith struct Comment { 1587d8fb91SRichard Smith Comment(const std::string &Message, unsigned Line, unsigned Col) 1687d8fb91SRichard Smith : Message(Message), Line(Line), Col(Col) { } 1787d8fb91SRichard Smith 1887d8fb91SRichard Smith std::string Message; 1987d8fb91SRichard Smith unsigned Line, Col; 2087d8fb91SRichard Smith }; 2187d8fb91SRichard Smith 2287d8fb91SRichard Smith class CommentVerifier; 2387d8fb91SRichard Smith typedef std::vector<Comment> CommentList; 2487d8fb91SRichard Smith 2587d8fb91SRichard Smith class CommentHandlerVisitor : public TestVisitor<CommentHandlerVisitor>, 2687d8fb91SRichard Smith public CommentHandler { 2787d8fb91SRichard Smith typedef TestVisitor<CommentHandlerVisitor> base; 2887d8fb91SRichard Smith 2987d8fb91SRichard Smith public: 30416fa34bSCraig Topper CommentHandlerVisitor() : base(), PP(nullptr), Verified(false) {} 3187d8fb91SRichard Smith 3234eb2072SAlexander Kornienko ~CommentHandlerVisitor() override { 3387d8fb91SRichard Smith EXPECT_TRUE(Verified) << "CommentVerifier not accessed"; 3487d8fb91SRichard Smith } 3587d8fb91SRichard Smith 3634eb2072SAlexander Kornienko bool HandleComment(Preprocessor &PP, SourceRange Loc) override { 3787d8fb91SRichard Smith assert(&PP == this->PP && "Preprocessor changed!"); 3887d8fb91SRichard Smith 3987d8fb91SRichard Smith SourceLocation Start = Loc.getBegin(); 4087d8fb91SRichard Smith SourceManager &SM = PP.getSourceManager(); 4187d8fb91SRichard Smith std::string C(SM.getCharacterData(Start), 4287d8fb91SRichard Smith SM.getCharacterData(Loc.getEnd())); 4387d8fb91SRichard Smith 4487d8fb91SRichard Smith bool Invalid; 4587d8fb91SRichard Smith unsigned CLine = SM.getSpellingLineNumber(Start, &Invalid); 4687d8fb91SRichard Smith EXPECT_TRUE(!Invalid) << "Invalid line number on comment " << C; 4787d8fb91SRichard Smith 4887d8fb91SRichard Smith unsigned CCol = SM.getSpellingColumnNumber(Start, &Invalid); 4987d8fb91SRichard Smith EXPECT_TRUE(!Invalid) << "Invalid column number on comment " << C; 5087d8fb91SRichard Smith 5187d8fb91SRichard Smith Comments.push_back(Comment(C, CLine, CCol)); 5287d8fb91SRichard Smith return false; 5387d8fb91SRichard Smith } 5487d8fb91SRichard Smith 5587d8fb91SRichard Smith CommentVerifier GetVerifier(); 5687d8fb91SRichard Smith 5787d8fb91SRichard Smith protected: 58497fd98aSRoman Lebedev ASTFrontendAction *CreateTestAction() override { 59497fd98aSRoman Lebedev return new CommentHandlerAction(this); 6087d8fb91SRichard Smith } 6187d8fb91SRichard Smith 6287d8fb91SRichard Smith private: 6387d8fb91SRichard Smith Preprocessor *PP; 6487d8fb91SRichard Smith CommentList Comments; 6587d8fb91SRichard Smith bool Verified; 6687d8fb91SRichard Smith 6787d8fb91SRichard Smith class CommentHandlerAction : public base::TestAction { 6887d8fb91SRichard Smith public: 6987d8fb91SRichard Smith CommentHandlerAction(CommentHandlerVisitor *Visitor) 7087d8fb91SRichard Smith : TestAction(Visitor) { } 7187d8fb91SRichard Smith 72d9259c2fSRichard Smith bool BeginSourceFileAction(CompilerInstance &CI) override { 7387d8fb91SRichard Smith CommentHandlerVisitor *V = 7487d8fb91SRichard Smith static_cast<CommentHandlerVisitor*>(this->Visitor); 7587d8fb91SRichard Smith V->PP = &CI.getPreprocessor(); 7687d8fb91SRichard Smith V->PP->addCommentHandler(V); 7787d8fb91SRichard Smith return true; 7887d8fb91SRichard Smith } 7987d8fb91SRichard Smith 8034eb2072SAlexander Kornienko void EndSourceFileAction() override { 8187d8fb91SRichard Smith CommentHandlerVisitor *V = 8287d8fb91SRichard Smith static_cast<CommentHandlerVisitor*>(this->Visitor); 8387d8fb91SRichard Smith V->PP->removeCommentHandler(V); 8487d8fb91SRichard Smith } 8587d8fb91SRichard Smith }; 8687d8fb91SRichard Smith }; 8787d8fb91SRichard Smith 8887d8fb91SRichard Smith class CommentVerifier { 8987d8fb91SRichard Smith CommentList::const_iterator Current; 9087d8fb91SRichard Smith CommentList::const_iterator End; 9187d8fb91SRichard Smith Preprocessor *PP; 9287d8fb91SRichard Smith 9387d8fb91SRichard Smith public: 9487d8fb91SRichard Smith CommentVerifier(const CommentList &Comments, Preprocessor *PP) 9587d8fb91SRichard Smith : Current(Comments.begin()), End(Comments.end()), PP(PP) 9687d8fb91SRichard Smith { } 9787d8fb91SRichard Smith 98e438127bSDavid Blaikie CommentVerifier(CommentVerifier &&C) : Current(C.Current), End(C.End), PP(C.PP) { 99e438127bSDavid Blaikie C.Current = C.End; 100e438127bSDavid Blaikie } 101e438127bSDavid Blaikie 10287d8fb91SRichard Smith ~CommentVerifier() { 10387d8fb91SRichard Smith if (Current != End) { 10487d8fb91SRichard Smith EXPECT_TRUE(Current == End) << "Unexpected comment \"" 10587d8fb91SRichard Smith << Current->Message << "\" at line " << Current->Line << ", column " 10687d8fb91SRichard Smith << Current->Col; 10787d8fb91SRichard Smith } 10887d8fb91SRichard Smith } 10987d8fb91SRichard Smith 11087d8fb91SRichard Smith void Match(const char *Message, unsigned Line, unsigned Col) { 11187d8fb91SRichard Smith EXPECT_TRUE(Current != End) << "Comment " << Message << " not found"; 11287d8fb91SRichard Smith if (Current == End) return; 11387d8fb91SRichard Smith 11487d8fb91SRichard Smith const Comment &C = *Current; 11587d8fb91SRichard Smith EXPECT_TRUE(C.Message == Message && C.Line == Line && C.Col == Col) 11687d8fb91SRichard Smith << "Expected comment \"" << Message 11787d8fb91SRichard Smith << "\" at line " << Line << ", column " << Col 11887d8fb91SRichard Smith << "\nActual comment \"" << C.Message 11987d8fb91SRichard Smith << "\" at line " << C.Line << ", column " << C.Col; 12087d8fb91SRichard Smith 12187d8fb91SRichard Smith ++Current; 12287d8fb91SRichard Smith } 12387d8fb91SRichard Smith }; 12487d8fb91SRichard Smith 12587d8fb91SRichard Smith CommentVerifier CommentHandlerVisitor::GetVerifier() { 12687d8fb91SRichard Smith Verified = true; 12787d8fb91SRichard Smith return CommentVerifier(Comments, PP); 12887d8fb91SRichard Smith } 12987d8fb91SRichard Smith 13087d8fb91SRichard Smith 13187d8fb91SRichard Smith TEST(CommentHandlerTest, BasicTest1) { 13287d8fb91SRichard Smith CommentHandlerVisitor Visitor; 13387d8fb91SRichard Smith EXPECT_TRUE(Visitor.runOver("class X {}; int main() { return 0; }")); 13487d8fb91SRichard Smith CommentVerifier Verifier = Visitor.GetVerifier(); 13587d8fb91SRichard Smith } 13687d8fb91SRichard Smith 13787d8fb91SRichard Smith TEST(CommentHandlerTest, BasicTest2) { 13887d8fb91SRichard Smith CommentHandlerVisitor Visitor; 13987d8fb91SRichard Smith EXPECT_TRUE(Visitor.runOver( 14087d8fb91SRichard Smith "class X {}; int main() { /* comment */ return 0; }")); 14187d8fb91SRichard Smith CommentVerifier Verifier = Visitor.GetVerifier(); 14287d8fb91SRichard Smith Verifier.Match("/* comment */", 1, 26); 14387d8fb91SRichard Smith } 14487d8fb91SRichard Smith 14587d8fb91SRichard Smith TEST(CommentHandlerTest, BasicTest3) { 14687d8fb91SRichard Smith CommentHandlerVisitor Visitor; 14787d8fb91SRichard Smith EXPECT_TRUE(Visitor.runOver( 14887d8fb91SRichard Smith "class X {}; // comment 1\n" 14987d8fb91SRichard Smith "int main() {\n" 15087d8fb91SRichard Smith " // comment 2\n" 15187d8fb91SRichard Smith " return 0;\n" 15287d8fb91SRichard Smith "}")); 15387d8fb91SRichard Smith CommentVerifier Verifier = Visitor.GetVerifier(); 15487d8fb91SRichard Smith Verifier.Match("// comment 1", 1, 13); 15587d8fb91SRichard Smith Verifier.Match("// comment 2", 3, 3); 15687d8fb91SRichard Smith } 15787d8fb91SRichard Smith 15887d8fb91SRichard Smith TEST(CommentHandlerTest, IfBlock1) { 15987d8fb91SRichard Smith CommentHandlerVisitor Visitor; 16087d8fb91SRichard Smith EXPECT_TRUE(Visitor.runOver( 16187d8fb91SRichard Smith "#if 0\n" 16287d8fb91SRichard Smith "// ignored comment\n" 16387d8fb91SRichard Smith "#endif\n" 16487d8fb91SRichard Smith "// visible comment\n")); 16587d8fb91SRichard Smith CommentVerifier Verifier = Visitor.GetVerifier(); 16687d8fb91SRichard Smith Verifier.Match("// visible comment", 4, 1); 16787d8fb91SRichard Smith } 16887d8fb91SRichard Smith 16987d8fb91SRichard Smith TEST(CommentHandlerTest, IfBlock2) { 17087d8fb91SRichard Smith CommentHandlerVisitor Visitor; 17187d8fb91SRichard Smith EXPECT_TRUE(Visitor.runOver( 17287d8fb91SRichard Smith "#define TEST // visible_1\n" 17387d8fb91SRichard Smith "#ifndef TEST // visible_2\n" 17487d8fb91SRichard Smith " // ignored_3\n" 17587d8fb91SRichard Smith "# ifdef UNDEFINED // ignored_4\n" 17687d8fb91SRichard Smith "# endif // ignored_5\n" 17787d8fb91SRichard Smith "#elif defined(TEST) // visible_6\n" 17887d8fb91SRichard Smith "# if 1 // visible_7\n" 17987d8fb91SRichard Smith " // visible_8\n" 18087d8fb91SRichard Smith "# else // visible_9\n" 18187d8fb91SRichard Smith " // ignored_10\n" 18287d8fb91SRichard Smith "# ifndef TEST // ignored_11\n" 18387d8fb91SRichard Smith "# endif // ignored_12\n" 18487d8fb91SRichard Smith "# endif // visible_13\n" 18587d8fb91SRichard Smith "#endif // visible_14\n")); 18687d8fb91SRichard Smith 18787d8fb91SRichard Smith CommentVerifier Verifier = Visitor.GetVerifier(); 18887d8fb91SRichard Smith Verifier.Match("// visible_1", 1, 21); 18987d8fb91SRichard Smith Verifier.Match("// visible_2", 2, 21); 19087d8fb91SRichard Smith Verifier.Match("// visible_6", 6, 21); 19187d8fb91SRichard Smith Verifier.Match("// visible_7", 7, 21); 19287d8fb91SRichard Smith Verifier.Match("// visible_8", 8, 21); 19387d8fb91SRichard Smith Verifier.Match("// visible_9", 9, 21); 19487d8fb91SRichard Smith Verifier.Match("// visible_13", 13, 21); 19587d8fb91SRichard Smith Verifier.Match("// visible_14", 14, 21); 19687d8fb91SRichard Smith } 19787d8fb91SRichard Smith 19887d8fb91SRichard Smith TEST(CommentHandlerTest, IfBlock3) { 19987d8fb91SRichard Smith const char *Source = 20087d8fb91SRichard Smith "/* commented out ...\n" 20187d8fb91SRichard Smith "#if 0\n" 20287d8fb91SRichard Smith "// enclosed\n" 20387d8fb91SRichard Smith "#endif */"; 20487d8fb91SRichard Smith 20587d8fb91SRichard Smith CommentHandlerVisitor Visitor; 20687d8fb91SRichard Smith EXPECT_TRUE(Visitor.runOver(Source)); 20787d8fb91SRichard Smith CommentVerifier Verifier = Visitor.GetVerifier(); 20887d8fb91SRichard Smith Verifier.Match(Source, 1, 1); 20987d8fb91SRichard Smith } 21087d8fb91SRichard Smith 21187d8fb91SRichard Smith TEST(CommentHandlerTest, PPDirectives) { 21287d8fb91SRichard Smith CommentHandlerVisitor Visitor; 21387d8fb91SRichard Smith EXPECT_TRUE(Visitor.runOver( 21487d8fb91SRichard Smith "#warning Y // ignored_1\n" // #warning takes whole line as message 21587d8fb91SRichard Smith "#undef MACRO // visible_2\n" 21687d8fb91SRichard Smith "#line 1 // visible_3\n")); 21787d8fb91SRichard Smith 21887d8fb91SRichard Smith CommentVerifier Verifier = Visitor.GetVerifier(); 21987d8fb91SRichard Smith Verifier.Match("// visible_2", 2, 14); 22087d8fb91SRichard Smith Verifier.Match("// visible_3", 3, 14); 22187d8fb91SRichard Smith } 22287d8fb91SRichard Smith 22387d8fb91SRichard Smith } // end namespace clang 224