xref: /minix3/external/bsd/llvm/dist/clang/unittests/Tooling/TestVisitor.h (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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