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