xref: /aosp_15_r20/external/clang/unittests/Tooling/TestVisitor.h (revision 67e74705e28f6214e480b399dd47ea732279e315)
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