Clang Project

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