[libc++][Android] BuildKite CI: update Clang and sysroot versions (#116151)
[llvm-project.git] / clang / unittests / Tooling / TestVisitor.h
blobfdf57a946a6e2d18223ce0972473210f5bf1fefa
1 //===--- TestVisitor.h ------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// \brief Defines utility templates for RecursiveASTVisitor related tests.
11 ///
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H
15 #define LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H
17 #include "clang/AST/ASTConsumer.h"
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/DynamicRecursiveASTVisitor.h"
20 #include "clang/Frontend/CompilerInstance.h"
21 #include "clang/Frontend/FrontendAction.h"
22 #include "clang/Tooling/Tooling.h"
23 #include "gtest/gtest.h"
24 #include <vector>
26 namespace clang {
27 namespace detail {
28 // Use 'TestVisitor' or include 'CRTPTestVisitor.h' and use 'CRTPTestVisitor'
29 // instead of using this directly.
30 class TestVisitorHelper {
31 public:
32 enum Language {
33 Lang_C,
34 Lang_CXX98,
35 Lang_CXX11,
36 Lang_CXX14,
37 Lang_CXX17,
38 Lang_CXX2a,
39 Lang_OBJC,
40 Lang_OBJCXX11,
41 Lang_CXX = Lang_CXX98
44 /// \brief Runs the current AST visitor over the given code.
45 bool runOver(StringRef Code, Language L = Lang_CXX) {
46 std::vector<std::string> Args;
47 switch (L) {
48 case Lang_C:
49 Args.push_back("-x");
50 Args.push_back("c");
51 break;
52 case Lang_CXX98:
53 Args.push_back("-std=c++98");
54 break;
55 case Lang_CXX11:
56 Args.push_back("-std=c++11");
57 break;
58 case Lang_CXX14:
59 Args.push_back("-std=c++14");
60 break;
61 case Lang_CXX17:
62 Args.push_back("-std=c++17");
63 break;
64 case Lang_CXX2a:
65 Args.push_back("-std=c++2a");
66 break;
67 case Lang_OBJC:
68 Args.push_back("-ObjC");
69 Args.push_back("-fobjc-runtime=macosx-10.12.0");
70 break;
71 case Lang_OBJCXX11:
72 Args.push_back("-ObjC++");
73 Args.push_back("-std=c++11");
74 Args.push_back("-fblocks");
75 break;
77 return tooling::runToolOnCodeWithArgs(CreateTestAction(), Code, Args);
80 protected:
81 TestVisitorHelper() = default;
82 virtual ~TestVisitorHelper() = default;
83 virtual void InvokeTraverseDecl(TranslationUnitDecl *D) = 0;
85 virtual std::unique_ptr<ASTFrontendAction> CreateTestAction() {
86 return std::make_unique<TestAction>(this);
89 class FindConsumer : public ASTConsumer {
90 public:
91 FindConsumer(TestVisitorHelper *Visitor) : Visitor(Visitor) {}
93 void HandleTranslationUnit(clang::ASTContext &Context) override {
94 Visitor->Context = &Context;
95 Visitor->InvokeTraverseDecl(Context.getTranslationUnitDecl());
98 private:
99 TestVisitorHelper *Visitor;
102 class TestAction : public ASTFrontendAction {
103 public:
104 TestAction(TestVisitorHelper *Visitor) : Visitor(Visitor) {}
106 std::unique_ptr<clang::ASTConsumer>
107 CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) override {
108 /// TestConsumer will be deleted by the framework calling us.
109 return std::make_unique<FindConsumer>(Visitor);
112 protected:
113 TestVisitorHelper *Visitor;
116 ASTContext *Context;
119 class ExpectedLocationVisitorHelper {
120 public:
121 /// \brief Expect 'Match' *not* to occur at the given 'Line' and 'Column'.
123 /// Any number of matches can be disallowed.
124 void DisallowMatch(Twine Match, unsigned Line, unsigned Column) {
125 DisallowedMatches.push_back(MatchCandidate(Match, Line, Column));
128 /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
130 /// Any number of expected matches can be set by calling this repeatedly.
131 /// Each is expected to be matched 'Times' number of times. (This is useful in
132 /// cases in which different AST nodes can match at the same source code
133 /// location.)
134 void ExpectMatch(Twine Match, unsigned Line, unsigned Column,
135 unsigned Times = 1) {
136 ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column, Times));
139 /// \brief Checks that all expected matches have been found.
140 virtual ~ExpectedLocationVisitorHelper() {
141 // FIXME: Range-based for loop.
142 for (std::vector<ExpectedMatch>::const_iterator
143 It = ExpectedMatches.begin(),
144 End = ExpectedMatches.end();
145 It != End; ++It) {
146 It->ExpectFound();
150 protected:
151 virtual ASTContext *getASTContext() = 0;
153 /// \brief Checks an actual match against expected and disallowed matches.
155 /// Implementations are required to call this with appropriate values
156 /// for 'Name' during visitation.
157 void Match(StringRef Name, SourceLocation Location) {
158 const FullSourceLoc FullLocation = getASTContext()->getFullLoc(Location);
160 // FIXME: Range-based for loop.
161 for (std::vector<MatchCandidate>::const_iterator
162 It = DisallowedMatches.begin(),
163 End = DisallowedMatches.end();
164 It != End; ++It) {
165 EXPECT_FALSE(It->Matches(Name, FullLocation))
166 << "Matched disallowed " << *It;
169 // FIXME: Range-based for loop.
170 for (std::vector<ExpectedMatch>::iterator It = ExpectedMatches.begin(),
171 End = ExpectedMatches.end();
172 It != End; ++It) {
173 It->UpdateFor(Name, FullLocation, getASTContext()->getSourceManager());
177 private:
178 struct MatchCandidate {
179 std::string ExpectedName;
180 unsigned LineNumber;
181 unsigned ColumnNumber;
183 MatchCandidate(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
184 : ExpectedName(Name.str()), LineNumber(LineNumber),
185 ColumnNumber(ColumnNumber) {
188 bool Matches(StringRef Name, FullSourceLoc const &Location) const {
189 return MatchesName(Name) && MatchesLocation(Location);
192 bool PartiallyMatches(StringRef Name, FullSourceLoc const &Location) const {
193 return MatchesName(Name) || MatchesLocation(Location);
196 bool MatchesName(StringRef Name) const {
197 return Name == ExpectedName;
200 bool MatchesLocation(FullSourceLoc const &Location) const {
201 return Location.isValid() &&
202 Location.getSpellingLineNumber() == LineNumber &&
203 Location.getSpellingColumnNumber() == ColumnNumber;
206 friend std::ostream &operator<<(std::ostream &Stream,
207 MatchCandidate const &Match) {
208 return Stream << Match.ExpectedName
209 << " at " << Match.LineNumber << ":" << Match.ColumnNumber;
213 struct ExpectedMatch {
214 ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber,
215 unsigned Times)
216 : Candidate(Name, LineNumber, ColumnNumber), TimesExpected(Times),
217 TimesSeen(0) {}
219 void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
220 if (Candidate.Matches(Name, Location)) {
221 EXPECT_LT(TimesSeen, TimesExpected);
222 ++TimesSeen;
223 } else if (TimesSeen < TimesExpected &&
224 Candidate.PartiallyMatches(Name, Location)) {
225 llvm::raw_string_ostream Stream(PartialMatches);
226 Stream << ", partial match: \"" << Name << "\" at ";
227 Location.print(Stream, SM);
231 void ExpectFound() const {
232 EXPECT_EQ(TimesExpected, TimesSeen)
233 << "Expected \"" << Candidate.ExpectedName
234 << "\" at " << Candidate.LineNumber
235 << ":" << Candidate.ColumnNumber << PartialMatches;
238 MatchCandidate Candidate;
239 std::string PartialMatches;
240 unsigned TimesExpected;
241 unsigned TimesSeen;
244 std::vector<MatchCandidate> DisallowedMatches;
245 std::vector<ExpectedMatch> ExpectedMatches;
247 } // namespace detail
249 /// \brief Base class for simple (Dynamic)RecursiveASTVisitor based tests.
251 /// This is a drop-in replacement for DynamicRecursiveASTVisitor itself, with
252 /// the additional capability of running it over a snippet of code.
254 /// Visits template instantiations and implicit code by default.
256 /// For post-order traversal etc. use CTRPTestVisitor from
257 /// CTRPTestVisitor.h instead.
258 class TestVisitor : public DynamicRecursiveASTVisitor,
259 public detail::TestVisitorHelper {
260 public:
261 TestVisitor() {
262 ShouldVisitTemplateInstantiations = true;
263 ShouldVisitImplicitCode = true;
266 void InvokeTraverseDecl(TranslationUnitDecl *D) override { TraverseDecl(D); }
269 /// \brief A RecursiveASTVisitor to check that certain matches are (or are
270 /// not) observed during visitation.
272 /// This is a RecursiveASTVisitor for testing the RecursiveASTVisitor itself,
273 /// and allows simple creation of test visitors running matches on only a small
274 /// subset of the Visit* methods.
276 /// For post-order traversal etc. use CTRPExpectedLocationVisitor from
277 /// CTRPTestVisitor.h instead.
278 class ExpectedLocationVisitor : public TestVisitor,
279 public detail::ExpectedLocationVisitorHelper {
280 ASTContext *getASTContext() override { return Context; }
282 } // namespace clang
284 #endif