224 lines
6.6 KiB
C++
224 lines
6.6 KiB
C++
//===- unittest/Tooling/CommentHandlerTest.cpp -----------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TestVisitor.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
|
|
namespace clang {
|
|
|
|
struct Comment {
|
|
Comment(const std::string &Message, unsigned Line, unsigned Col)
|
|
: Message(Message), Line(Line), Col(Col) { }
|
|
|
|
std::string Message;
|
|
unsigned Line, Col;
|
|
};
|
|
|
|
class CommentVerifier;
|
|
typedef std::vector<Comment> CommentList;
|
|
|
|
class CommentHandlerVisitor : public TestVisitor<CommentHandlerVisitor>,
|
|
public CommentHandler {
|
|
typedef TestVisitor<CommentHandlerVisitor> base;
|
|
|
|
public:
|
|
CommentHandlerVisitor() : base(), PP(nullptr), Verified(false) {}
|
|
|
|
~CommentHandlerVisitor() override {
|
|
EXPECT_TRUE(Verified) << "CommentVerifier not accessed";
|
|
}
|
|
|
|
bool HandleComment(Preprocessor &PP, SourceRange Loc) override {
|
|
assert(&PP == this->PP && "Preprocessor changed!");
|
|
|
|
SourceLocation Start = Loc.getBegin();
|
|
SourceManager &SM = PP.getSourceManager();
|
|
std::string C(SM.getCharacterData(Start),
|
|
SM.getCharacterData(Loc.getEnd()));
|
|
|
|
bool Invalid;
|
|
unsigned CLine = SM.getSpellingLineNumber(Start, &Invalid);
|
|
EXPECT_TRUE(!Invalid) << "Invalid line number on comment " << C;
|
|
|
|
unsigned CCol = SM.getSpellingColumnNumber(Start, &Invalid);
|
|
EXPECT_TRUE(!Invalid) << "Invalid column number on comment " << C;
|
|
|
|
Comments.push_back(Comment(C, CLine, CCol));
|
|
return false;
|
|
}
|
|
|
|
CommentVerifier GetVerifier();
|
|
|
|
protected:
|
|
std::unique_ptr<ASTFrontendAction> CreateTestAction() override {
|
|
return std::make_unique<CommentHandlerAction>(this);
|
|
}
|
|
|
|
private:
|
|
Preprocessor *PP;
|
|
CommentList Comments;
|
|
bool Verified;
|
|
|
|
class CommentHandlerAction : public base::TestAction {
|
|
public:
|
|
CommentHandlerAction(CommentHandlerVisitor *Visitor)
|
|
: TestAction(Visitor) { }
|
|
|
|
bool BeginSourceFileAction(CompilerInstance &CI) override {
|
|
CommentHandlerVisitor *V =
|
|
static_cast<CommentHandlerVisitor*>(this->Visitor);
|
|
V->PP = &CI.getPreprocessor();
|
|
V->PP->addCommentHandler(V);
|
|
return true;
|
|
}
|
|
|
|
void EndSourceFileAction() override {
|
|
CommentHandlerVisitor *V =
|
|
static_cast<CommentHandlerVisitor*>(this->Visitor);
|
|
V->PP->removeCommentHandler(V);
|
|
}
|
|
};
|
|
};
|
|
|
|
class CommentVerifier {
|
|
CommentList::const_iterator Current;
|
|
CommentList::const_iterator End;
|
|
Preprocessor *PP;
|
|
|
|
public:
|
|
CommentVerifier(const CommentList &Comments, Preprocessor *PP)
|
|
: Current(Comments.begin()), End(Comments.end()), PP(PP)
|
|
{ }
|
|
|
|
CommentVerifier(CommentVerifier &&C) : Current(C.Current), End(C.End), PP(C.PP) {
|
|
C.Current = C.End;
|
|
}
|
|
|
|
~CommentVerifier() {
|
|
if (Current != End) {
|
|
EXPECT_TRUE(Current == End) << "Unexpected comment \""
|
|
<< Current->Message << "\" at line " << Current->Line << ", column "
|
|
<< Current->Col;
|
|
}
|
|
}
|
|
|
|
void Match(const char *Message, unsigned Line, unsigned Col) {
|
|
EXPECT_TRUE(Current != End) << "Comment " << Message << " not found";
|
|
if (Current == End) return;
|
|
|
|
const Comment &C = *Current;
|
|
EXPECT_TRUE(C.Message == Message && C.Line == Line && C.Col == Col)
|
|
<< "Expected comment \"" << Message
|
|
<< "\" at line " << Line << ", column " << Col
|
|
<< "\nActual comment \"" << C.Message
|
|
<< "\" at line " << C.Line << ", column " << C.Col;
|
|
|
|
++Current;
|
|
}
|
|
};
|
|
|
|
CommentVerifier CommentHandlerVisitor::GetVerifier() {
|
|
Verified = true;
|
|
return CommentVerifier(Comments, PP);
|
|
}
|
|
|
|
|
|
TEST(CommentHandlerTest, BasicTest1) {
|
|
CommentHandlerVisitor Visitor;
|
|
EXPECT_TRUE(Visitor.runOver("class X {}; int main() { return 0; }"));
|
|
CommentVerifier Verifier = Visitor.GetVerifier();
|
|
}
|
|
|
|
TEST(CommentHandlerTest, BasicTest2) {
|
|
CommentHandlerVisitor Visitor;
|
|
EXPECT_TRUE(Visitor.runOver(
|
|
"class X {}; int main() { /* comment */ return 0; }"));
|
|
CommentVerifier Verifier = Visitor.GetVerifier();
|
|
Verifier.Match("/* comment */", 1, 26);
|
|
}
|
|
|
|
TEST(CommentHandlerTest, BasicTest3) {
|
|
CommentHandlerVisitor Visitor;
|
|
EXPECT_TRUE(Visitor.runOver(
|
|
"class X {}; // comment 1\n"
|
|
"int main() {\n"
|
|
" // comment 2\n"
|
|
" return 0;\n"
|
|
"}"));
|
|
CommentVerifier Verifier = Visitor.GetVerifier();
|
|
Verifier.Match("// comment 1", 1, 13);
|
|
Verifier.Match("// comment 2", 3, 3);
|
|
}
|
|
|
|
TEST(CommentHandlerTest, IfBlock1) {
|
|
CommentHandlerVisitor Visitor;
|
|
EXPECT_TRUE(Visitor.runOver(
|
|
"#if 0\n"
|
|
"// ignored comment\n"
|
|
"#endif\n"
|
|
"// visible comment\n"));
|
|
CommentVerifier Verifier = Visitor.GetVerifier();
|
|
Verifier.Match("// visible comment", 4, 1);
|
|
}
|
|
|
|
TEST(CommentHandlerTest, IfBlock2) {
|
|
CommentHandlerVisitor Visitor;
|
|
EXPECT_TRUE(Visitor.runOver(
|
|
"#define TEST // visible_1\n"
|
|
"#ifndef TEST // visible_2\n"
|
|
" // ignored_3\n"
|
|
"# ifdef UNDEFINED // ignored_4\n"
|
|
"# endif // ignored_5\n"
|
|
"#elif defined(TEST) // visible_6\n"
|
|
"# if 1 // visible_7\n"
|
|
" // visible_8\n"
|
|
"# else // visible_9\n"
|
|
" // ignored_10\n"
|
|
"# ifndef TEST // ignored_11\n"
|
|
"# endif // ignored_12\n"
|
|
"# endif // visible_13\n"
|
|
"#endif // visible_14\n"));
|
|
|
|
CommentVerifier Verifier = Visitor.GetVerifier();
|
|
Verifier.Match("// visible_1", 1, 21);
|
|
Verifier.Match("// visible_2", 2, 21);
|
|
Verifier.Match("// visible_6", 6, 21);
|
|
Verifier.Match("// visible_7", 7, 21);
|
|
Verifier.Match("// visible_8", 8, 21);
|
|
Verifier.Match("// visible_9", 9, 21);
|
|
Verifier.Match("// visible_13", 13, 21);
|
|
Verifier.Match("// visible_14", 14, 21);
|
|
}
|
|
|
|
TEST(CommentHandlerTest, IfBlock3) {
|
|
const char *Source =
|
|
"/* commented out ...\n"
|
|
"#if 0\n"
|
|
"// enclosed\n"
|
|
"#endif */";
|
|
|
|
CommentHandlerVisitor Visitor;
|
|
EXPECT_TRUE(Visitor.runOver(Source));
|
|
CommentVerifier Verifier = Visitor.GetVerifier();
|
|
Verifier.Match(Source, 1, 1);
|
|
}
|
|
|
|
TEST(CommentHandlerTest, PPDirectives) {
|
|
CommentHandlerVisitor Visitor;
|
|
EXPECT_TRUE(Visitor.runOver(
|
|
"#warning Y // ignored_1\n" // #warning takes whole line as message
|
|
"#undef MACRO // visible_2\n"
|
|
"#line 1 // visible_3\n"));
|
|
|
|
CommentVerifier Verifier = Visitor.GetVerifier();
|
|
Verifier.Match("// visible_2", 2, 14);
|
|
Verifier.Match("// visible_3", 3, 14);
|
|
}
|
|
|
|
} // end namespace clang
|