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