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