221 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "TestVisitor.h"10#include "clang/Lex/Preprocessor.h"11 12namespace clang {13 14struct 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 22class CommentVerifier;23typedef std::vector<Comment> CommentList;24 25class CommentHandlerVisitor : public TestVisitor, public CommentHandler {26public: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 54protected:55 std::unique_ptr<ASTFrontendAction> CreateTestAction() override {56 return std::make_unique<CommentHandlerAction>(this);57 }58 59private: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 85class CommentVerifier {86 CommentList::const_iterator Current;87 CommentList::const_iterator End;88 Preprocessor *PP;89 90public: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 \"" << Message114 << "\" at line " << Line << ", column " << Col115 << "\nActual comment \"" << C.Message116 << "\" at line " << C.Line << ", column " << C.Col;117 118 ++Current;119 }120};121 122CommentVerifier CommentHandlerVisitor::GetVerifier() {123 Verified = true;124 return CommentVerifier(Comments, PP);125}126 127 128TEST(CommentHandlerTest, BasicTest1) {129 CommentHandlerVisitor Visitor;130 EXPECT_TRUE(Visitor.runOver("class X {}; int main() { return 0; }"));131 CommentVerifier Verifier = Visitor.GetVerifier();132}133 134TEST(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 142TEST(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 155TEST(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 166TEST(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 195TEST(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 208TEST(CommentHandlerTest, PPDirectives) {209 CommentHandlerVisitor Visitor;210 EXPECT_TRUE(Visitor.runOver(211 "#warning Y // ignored_1\n" // #warning takes whole line as message212 "#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 clang221