1*67e74705SXin Li //===--- TestVisitor.h ------------------------------------------*- C++ -*-===// 2*67e74705SXin Li // 3*67e74705SXin Li // The LLVM Compiler Infrastructure 4*67e74705SXin Li // 5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source 6*67e74705SXin Li // License. See LICENSE.TXT for details. 7*67e74705SXin Li // 8*67e74705SXin Li //===----------------------------------------------------------------------===// 9*67e74705SXin Li /// 10*67e74705SXin Li /// \file 11*67e74705SXin Li /// \brief Defines utility templates for RecursiveASTVisitor related tests. 12*67e74705SXin Li /// 13*67e74705SXin Li //===----------------------------------------------------------------------===// 14*67e74705SXin Li 15*67e74705SXin Li #ifndef LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H 16*67e74705SXin Li #define LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H 17*67e74705SXin Li 18*67e74705SXin Li #include "clang/AST/ASTConsumer.h" 19*67e74705SXin Li #include "clang/AST/ASTContext.h" 20*67e74705SXin Li #include "clang/AST/RecursiveASTVisitor.h" 21*67e74705SXin Li #include "clang/Frontend/CompilerInstance.h" 22*67e74705SXin Li #include "clang/Frontend/FrontendAction.h" 23*67e74705SXin Li #include "clang/Tooling/Tooling.h" 24*67e74705SXin Li #include "gtest/gtest.h" 25*67e74705SXin Li #include <vector> 26*67e74705SXin Li 27*67e74705SXin Li namespace clang { 28*67e74705SXin Li 29*67e74705SXin Li /// \brief Base class for simple RecursiveASTVisitor based tests. 30*67e74705SXin Li /// 31*67e74705SXin Li /// This is a drop-in replacement for RecursiveASTVisitor itself, with the 32*67e74705SXin Li /// additional capability of running it over a snippet of code. 33*67e74705SXin Li /// 34*67e74705SXin Li /// Visits template instantiations and implicit code by default. 35*67e74705SXin Li template <typename T> 36*67e74705SXin Li class TestVisitor : public RecursiveASTVisitor<T> { 37*67e74705SXin Li public: TestVisitor()38*67e74705SXin Li TestVisitor() { } 39*67e74705SXin Li ~TestVisitor()40*67e74705SXin Li virtual ~TestVisitor() { } 41*67e74705SXin Li 42*67e74705SXin Li enum Language { 43*67e74705SXin Li Lang_C, 44*67e74705SXin Li Lang_CXX98, 45*67e74705SXin Li Lang_CXX11, 46*67e74705SXin Li Lang_OBJC, 47*67e74705SXin Li Lang_OBJCXX11, 48*67e74705SXin Li Lang_CXX = Lang_CXX98 49*67e74705SXin Li }; 50*67e74705SXin Li 51*67e74705SXin Li /// \brief Runs the current AST visitor over the given code. 52*67e74705SXin Li bool runOver(StringRef Code, Language L = Lang_CXX) { 53*67e74705SXin Li std::vector<std::string> Args; 54*67e74705SXin Li switch (L) { 55*67e74705SXin Li case Lang_C: Args.push_back("-std=c99"); break; 56*67e74705SXin Li case Lang_CXX98: Args.push_back("-std=c++98"); break; 57*67e74705SXin Li case Lang_CXX11: Args.push_back("-std=c++11"); break; 58*67e74705SXin Li case Lang_OBJC: Args.push_back("-ObjC"); break; 59*67e74705SXin Li case Lang_OBJCXX11: 60*67e74705SXin Li Args.push_back("-ObjC++"); 61*67e74705SXin Li Args.push_back("-std=c++11"); 62*67e74705SXin Li Args.push_back("-fblocks"); 63*67e74705SXin Li break; 64*67e74705SXin Li } 65*67e74705SXin Li return tooling::runToolOnCodeWithArgs(CreateTestAction(), Code, Args); 66*67e74705SXin Li } 67*67e74705SXin Li shouldVisitTemplateInstantiations()68*67e74705SXin Li bool shouldVisitTemplateInstantiations() const { 69*67e74705SXin Li return true; 70*67e74705SXin Li } 71*67e74705SXin Li shouldVisitImplicitCode()72*67e74705SXin Li bool shouldVisitImplicitCode() const { 73*67e74705SXin Li return true; 74*67e74705SXin Li } 75*67e74705SXin Li 76*67e74705SXin Li protected: CreateTestAction()77*67e74705SXin Li virtual ASTFrontendAction* CreateTestAction() { 78*67e74705SXin Li return new TestAction(this); 79*67e74705SXin Li } 80*67e74705SXin Li 81*67e74705SXin Li class FindConsumer : public ASTConsumer { 82*67e74705SXin Li public: FindConsumer(TestVisitor * Visitor)83*67e74705SXin Li FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {} 84*67e74705SXin Li HandleTranslationUnit(clang::ASTContext & Context)85*67e74705SXin Li void HandleTranslationUnit(clang::ASTContext &Context) override { 86*67e74705SXin Li Visitor->Context = &Context; 87*67e74705SXin Li Visitor->TraverseDecl(Context.getTranslationUnitDecl()); 88*67e74705SXin Li } 89*67e74705SXin Li 90*67e74705SXin Li private: 91*67e74705SXin Li TestVisitor *Visitor; 92*67e74705SXin Li }; 93*67e74705SXin Li 94*67e74705SXin Li class TestAction : public ASTFrontendAction { 95*67e74705SXin Li public: TestAction(TestVisitor * Visitor)96*67e74705SXin Li TestAction(TestVisitor *Visitor) : Visitor(Visitor) {} 97*67e74705SXin Li 98*67e74705SXin Li std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(CompilerInstance &,llvm::StringRef dummy)99*67e74705SXin Li CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) override { 100*67e74705SXin Li /// TestConsumer will be deleted by the framework calling us. 101*67e74705SXin Li return llvm::make_unique<FindConsumer>(Visitor); 102*67e74705SXin Li } 103*67e74705SXin Li 104*67e74705SXin Li protected: 105*67e74705SXin Li TestVisitor *Visitor; 106*67e74705SXin Li }; 107*67e74705SXin Li 108*67e74705SXin Li ASTContext *Context; 109*67e74705SXin Li }; 110*67e74705SXin Li 111*67e74705SXin Li /// \brief A RecursiveASTVisitor to check that certain matches are (or are 112*67e74705SXin Li /// not) observed during visitation. 113*67e74705SXin Li /// 114*67e74705SXin Li /// This is a RecursiveASTVisitor for testing the RecursiveASTVisitor itself, 115*67e74705SXin Li /// and allows simple creation of test visitors running matches on only a small 116*67e74705SXin Li /// subset of the Visit* methods. 117*67e74705SXin Li template <typename T, template <typename> class Visitor = TestVisitor> 118*67e74705SXin Li class ExpectedLocationVisitor : public Visitor<T> { 119*67e74705SXin Li public: 120*67e74705SXin Li /// \brief Expect 'Match' *not* to occur at the given 'Line' and 'Column'. 121*67e74705SXin Li /// 122*67e74705SXin Li /// Any number of matches can be disallowed. DisallowMatch(Twine Match,unsigned Line,unsigned Column)123*67e74705SXin Li void DisallowMatch(Twine Match, unsigned Line, unsigned Column) { 124*67e74705SXin Li DisallowedMatches.push_back(MatchCandidate(Match, Line, Column)); 125*67e74705SXin Li } 126*67e74705SXin Li 127*67e74705SXin Li /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'. 128*67e74705SXin Li /// 129*67e74705SXin Li /// Any number of expected matches can be set by calling this repeatedly. 130*67e74705SXin Li /// Each is expected to be matched exactly once. ExpectMatch(Twine Match,unsigned Line,unsigned Column)131*67e74705SXin Li void ExpectMatch(Twine Match, unsigned Line, unsigned Column) { 132*67e74705SXin Li ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column)); 133*67e74705SXin Li } 134*67e74705SXin Li 135*67e74705SXin Li /// \brief Checks that all expected matches have been found. ~ExpectedLocationVisitor()136*67e74705SXin Li ~ExpectedLocationVisitor() override { 137*67e74705SXin Li for (typename std::vector<ExpectedMatch>::const_iterator 138*67e74705SXin Li It = ExpectedMatches.begin(), End = ExpectedMatches.end(); 139*67e74705SXin Li It != End; ++It) { 140*67e74705SXin Li It->ExpectFound(); 141*67e74705SXin Li } 142*67e74705SXin Li } 143*67e74705SXin Li 144*67e74705SXin Li protected: 145*67e74705SXin Li /// \brief Checks an actual match against expected and disallowed matches. 146*67e74705SXin Li /// 147*67e74705SXin Li /// Implementations are required to call this with appropriate values 148*67e74705SXin Li /// for 'Name' during visitation. Match(StringRef Name,SourceLocation Location)149*67e74705SXin Li void Match(StringRef Name, SourceLocation Location) { 150*67e74705SXin Li const FullSourceLoc FullLocation = this->Context->getFullLoc(Location); 151*67e74705SXin Li 152*67e74705SXin Li for (typename std::vector<MatchCandidate>::const_iterator 153*67e74705SXin Li It = DisallowedMatches.begin(), End = DisallowedMatches.end(); 154*67e74705SXin Li It != End; ++It) { 155*67e74705SXin Li EXPECT_FALSE(It->Matches(Name, FullLocation)) 156*67e74705SXin Li << "Matched disallowed " << *It; 157*67e74705SXin Li } 158*67e74705SXin Li 159*67e74705SXin Li for (typename std::vector<ExpectedMatch>::iterator 160*67e74705SXin Li It = ExpectedMatches.begin(), End = ExpectedMatches.end(); 161*67e74705SXin Li It != End; ++It) { 162*67e74705SXin Li It->UpdateFor(Name, FullLocation, this->Context->getSourceManager()); 163*67e74705SXin Li } 164*67e74705SXin Li } 165*67e74705SXin Li 166*67e74705SXin Li private: 167*67e74705SXin Li struct MatchCandidate { 168*67e74705SXin Li std::string ExpectedName; 169*67e74705SXin Li unsigned LineNumber; 170*67e74705SXin Li unsigned ColumnNumber; 171*67e74705SXin Li MatchCandidateMatchCandidate172*67e74705SXin Li MatchCandidate(Twine Name, unsigned LineNumber, unsigned ColumnNumber) 173*67e74705SXin Li : ExpectedName(Name.str()), LineNumber(LineNumber), 174*67e74705SXin Li ColumnNumber(ColumnNumber) { 175*67e74705SXin Li } 176*67e74705SXin Li MatchesMatchCandidate177*67e74705SXin Li bool Matches(StringRef Name, FullSourceLoc const &Location) const { 178*67e74705SXin Li return MatchesName(Name) && MatchesLocation(Location); 179*67e74705SXin Li } 180*67e74705SXin Li PartiallyMatchesMatchCandidate181*67e74705SXin Li bool PartiallyMatches(StringRef Name, FullSourceLoc const &Location) const { 182*67e74705SXin Li return MatchesName(Name) || MatchesLocation(Location); 183*67e74705SXin Li } 184*67e74705SXin Li MatchesNameMatchCandidate185*67e74705SXin Li bool MatchesName(StringRef Name) const { 186*67e74705SXin Li return Name == ExpectedName; 187*67e74705SXin Li } 188*67e74705SXin Li MatchesLocationMatchCandidate189*67e74705SXin Li bool MatchesLocation(FullSourceLoc const &Location) const { 190*67e74705SXin Li return Location.isValid() && 191*67e74705SXin Li Location.getSpellingLineNumber() == LineNumber && 192*67e74705SXin Li Location.getSpellingColumnNumber() == ColumnNumber; 193*67e74705SXin Li } 194*67e74705SXin Li 195*67e74705SXin Li friend std::ostream &operator<<(std::ostream &Stream, 196*67e74705SXin Li MatchCandidate const &Match) { 197*67e74705SXin Li return Stream << Match.ExpectedName 198*67e74705SXin Li << " at " << Match.LineNumber << ":" << Match.ColumnNumber; 199*67e74705SXin Li } 200*67e74705SXin Li }; 201*67e74705SXin Li 202*67e74705SXin Li struct ExpectedMatch { ExpectedMatchExpectedMatch203*67e74705SXin Li ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber) 204*67e74705SXin Li : Candidate(Name, LineNumber, ColumnNumber), Found(false) {} 205*67e74705SXin Li UpdateForExpectedMatch206*67e74705SXin Li void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) { 207*67e74705SXin Li if (Candidate.Matches(Name, Location)) { 208*67e74705SXin Li EXPECT_TRUE(!Found); 209*67e74705SXin Li Found = true; 210*67e74705SXin Li } else if (!Found && Candidate.PartiallyMatches(Name, Location)) { 211*67e74705SXin Li llvm::raw_string_ostream Stream(PartialMatches); 212*67e74705SXin Li Stream << ", partial match: \"" << Name << "\" at "; 213*67e74705SXin Li Location.print(Stream, SM); 214*67e74705SXin Li } 215*67e74705SXin Li } 216*67e74705SXin Li ExpectFoundExpectedMatch217*67e74705SXin Li void ExpectFound() const { 218*67e74705SXin Li EXPECT_TRUE(Found) 219*67e74705SXin Li << "Expected \"" << Candidate.ExpectedName 220*67e74705SXin Li << "\" at " << Candidate.LineNumber 221*67e74705SXin Li << ":" << Candidate.ColumnNumber << PartialMatches; 222*67e74705SXin Li } 223*67e74705SXin Li 224*67e74705SXin Li MatchCandidate Candidate; 225*67e74705SXin Li std::string PartialMatches; 226*67e74705SXin Li bool Found; 227*67e74705SXin Li }; 228*67e74705SXin Li 229*67e74705SXin Li std::vector<MatchCandidate> DisallowedMatches; 230*67e74705SXin Li std::vector<ExpectedMatch> ExpectedMatches; 231*67e74705SXin Li }; 232*67e74705SXin Li } 233*67e74705SXin Li 234*67e74705SXin Li #endif 235