blob: fb6a76ccadd014f644eb1ca0e9919968db4d3497 [file] [log] [blame]
Richard Smith87d8fb92012-06-24 23:56:26 +00001//===--- TestVisitor.h ------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
James Dennett75c100b2012-08-24 06:59:51 +00009///
10/// \file
11/// \brief Defines utility templates for RecursiveASTVisitor related tests.
12///
Richard Smith87d8fb92012-06-24 23:56:26 +000013//===----------------------------------------------------------------------===//
14
Benjamin Kramer2f5db8b2014-08-13 16:25:19 +000015#ifndef LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H
16#define LLVM_CLANG_UNITTESTS_TOOLING_TESTVISITOR_H
Richard Smith87d8fb92012-06-24 23:56:26 +000017
18#include "clang/AST/ASTConsumer.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000019#include "clang/AST/ASTContext.h"
Richard Smith87d8fb92012-06-24 23:56:26 +000020#include "clang/AST/RecursiveASTVisitor.h"
Richard Smith87d8fb92012-06-24 23:56:26 +000021#include "clang/Frontend/CompilerInstance.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000022#include "clang/Frontend/FrontendAction.h"
Richard Smith87d8fb92012-06-24 23:56:26 +000023#include "clang/Tooling/Tooling.h"
24#include "gtest/gtest.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000025#include <vector>
Richard Smith87d8fb92012-06-24 23:56:26 +000026
27namespace clang {
28
Matt Beaumont-Gaya0e2c042012-06-25 18:27:11 +000029/// \brief Base class for simple RecursiveASTVisitor based tests.
Richard Smith87d8fb92012-06-24 23:56:26 +000030///
31/// This is a drop-in replacement for RecursiveASTVisitor itself, with the
32/// additional capability of running it over a snippet of code.
33///
Michael Hanc90d12d2013-09-11 15:53:29 +000034/// Visits template instantiations and implicit code by default.
Richard Smith87d8fb92012-06-24 23:56:26 +000035template <typename T>
36class TestVisitor : public RecursiveASTVisitor<T> {
37public:
Angel Garcia Gomez637d1e62015-10-20 13:23:58 +000038 TestVisitor() { }
Richard Smith87d8fb92012-06-24 23:56:26 +000039
Angel Garcia Gomez637d1e62015-10-20 13:23:58 +000040 virtual ~TestVisitor() { }
Matt Beaumont-Gaya0e2c042012-06-25 18:27:11 +000041
Alp Tokere3ad5312014-06-26 01:42:24 +000042 enum Language {
43 Lang_C,
44 Lang_CXX98,
45 Lang_CXX11,
Martin Bohmed5f94a62016-08-17 14:59:53 +000046 Lang_CXX14,
Alp Tokere3ad5312014-06-26 01:42:24 +000047 Lang_OBJC,
48 Lang_OBJCXX11,
49 Lang_CXX = Lang_CXX98
50 };
Richard Smith87deab32012-08-17 21:23:17 +000051
Richard Smith87d8fb92012-06-24 23:56:26 +000052 /// \brief Runs the current AST visitor over the given code.
Richard Smith87deab32012-08-17 21:23:17 +000053 bool runOver(StringRef Code, Language L = Lang_CXX) {
Nico Weber077a53e2012-08-30 02:02:19 +000054 std::vector<std::string> Args;
55 switch (L) {
Stephan Bergmann83e6a822017-06-27 07:59:56 +000056 case Lang_C:
57 Args.push_back("-x");
58 Args.push_back("c");
59 break;
James Dennetteb576c02013-06-30 03:05:49 +000060 case Lang_CXX98: Args.push_back("-std=c++98"); break;
61 case Lang_CXX11: Args.push_back("-std=c++11"); break;
Martin Bohmed5f94a62016-08-17 14:59:53 +000062 case Lang_CXX14: Args.push_back("-std=c++14"); break;
Alex Lorenz410ef382017-08-30 15:28:01 +000063 case Lang_OBJC:
64 Args.push_back("-ObjC");
65 Args.push_back("-fobjc-runtime=macosx-10.12.0");
66 break;
Alp Tokere3ad5312014-06-26 01:42:24 +000067 case Lang_OBJCXX11:
68 Args.push_back("-ObjC++");
69 Args.push_back("-std=c++11");
Alp Toker0843bff2014-06-26 02:07:06 +000070 Args.push_back("-fblocks");
Alp Tokere3ad5312014-06-26 01:42:24 +000071 break;
Nico Weber077a53e2012-08-30 02:02:19 +000072 }
73 return tooling::runToolOnCodeWithArgs(CreateTestAction(), Code, Args);
Richard Smith87d8fb92012-06-24 23:56:26 +000074 }
75
76 bool shouldVisitTemplateInstantiations() const {
77 return true;
78 }
79
Michael Hanc90d12d2013-09-11 15:53:29 +000080 bool shouldVisitImplicitCode() const {
81 return true;
82 }
83
Richard Smith87d8fb92012-06-24 23:56:26 +000084protected:
Roman Lebedev497fd982018-02-27 15:54:55 +000085 virtual ASTFrontendAction* CreateTestAction() {
86 return new TestAction(this);
Richard Smith87d8fb92012-06-24 23:56:26 +000087 }
88
89 class FindConsumer : public ASTConsumer {
90 public:
91 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
92
Alexander Kornienko34eb2072015-04-11 02:00:23 +000093 void HandleTranslationUnit(clang::ASTContext &Context) override {
Manuel Klimek5da9dcb2012-07-05 18:13:01 +000094 Visitor->Context = &Context;
Richard Smith87d8fb92012-06-24 23:56:26 +000095 Visitor->TraverseDecl(Context.getTranslationUnitDecl());
96 }
97
98 private:
99 TestVisitor *Visitor;
100 };
101
102 class TestAction : public ASTFrontendAction {
103 public:
104 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
105
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000106 std::unique_ptr<clang::ASTConsumer>
107 CreateASTConsumer(CompilerInstance &, llvm::StringRef dummy) override {
Richard Smith87d8fb92012-06-24 23:56:26 +0000108 /// TestConsumer will be deleted by the framework calling us.
David Blaikie6beb6aa2014-08-10 19:56:51 +0000109 return llvm::make_unique<FindConsumer>(Visitor);
Richard Smith87d8fb92012-06-24 23:56:26 +0000110 }
111
112 protected:
113 TestVisitor *Visitor;
114 };
115
116 ASTContext *Context;
117};
118
James Dennett75c100b2012-08-24 06:59:51 +0000119/// \brief A RecursiveASTVisitor to check that certain matches are (or are
120/// not) observed during visitation.
Richard Smith87d8fb92012-06-24 23:56:26 +0000121///
James Dennett75c100b2012-08-24 06:59:51 +0000122/// This is a RecursiveASTVisitor for testing the RecursiveASTVisitor itself,
123/// and allows simple creation of test visitors running matches on only a small
Richard Smith87d8fb92012-06-24 23:56:26 +0000124/// subset of the Visit* methods.
125template <typename T, template <typename> class Visitor = TestVisitor>
126class ExpectedLocationVisitor : public Visitor<T> {
127public:
James Dennett75c100b2012-08-24 06:59:51 +0000128 /// \brief Expect 'Match' *not* to occur at the given 'Line' and 'Column'.
129 ///
130 /// Any number of matches can be disallowed.
Zachary Turner41a9ee92017-10-11 23:54:34 +0000131 void DisallowMatch(Twine Match, unsigned Line, unsigned Column) {
James Dennett75c100b2012-08-24 06:59:51 +0000132 DisallowedMatches.push_back(MatchCandidate(Match, Line, Column));
Richard Smith87d8fb92012-06-24 23:56:26 +0000133 }
134
135 /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
James Dennett75c100b2012-08-24 06:59:51 +0000136 ///
137 /// Any number of expected matches can be set by calling this repeatedly.
Martin Bohmed5f94a62016-08-17 14:59:53 +0000138 /// Each is expected to be matched 'Times' number of times. (This is useful in
139 /// cases in which different AST nodes can match at the same source code
140 /// location.)
Zachary Turner41a9ee92017-10-11 23:54:34 +0000141 void ExpectMatch(Twine Match, unsigned Line, unsigned Column,
Martin Bohmed5f94a62016-08-17 14:59:53 +0000142 unsigned Times = 1) {
143 ExpectedMatches.push_back(ExpectedMatch(Match, Line, Column, Times));
James Dennett75c100b2012-08-24 06:59:51 +0000144 }
145
146 /// \brief Checks that all expected matches have been found.
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000147 ~ExpectedLocationVisitor() override {
James Dennett75c100b2012-08-24 06:59:51 +0000148 for (typename std::vector<ExpectedMatch>::const_iterator
149 It = ExpectedMatches.begin(), End = ExpectedMatches.end();
150 It != End; ++It) {
151 It->ExpectFound();
152 }
Richard Smith87d8fb92012-06-24 23:56:26 +0000153 }
154
155protected:
James Dennett75c100b2012-08-24 06:59:51 +0000156 /// \brief Checks an actual match against expected and disallowed matches.
Richard Smith87d8fb92012-06-24 23:56:26 +0000157 ///
158 /// Implementations are required to call this with appropriate values
159 /// for 'Name' during visitation.
160 void Match(StringRef Name, SourceLocation Location) {
James Dennett75c100b2012-08-24 06:59:51 +0000161 const FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
162
163 for (typename std::vector<MatchCandidate>::const_iterator
164 It = DisallowedMatches.begin(), End = DisallowedMatches.end();
165 It != End; ++It) {
166 EXPECT_FALSE(It->Matches(Name, FullLocation))
167 << "Matched disallowed " << *It;
168 }
169
170 for (typename std::vector<ExpectedMatch>::iterator
171 It = ExpectedMatches.begin(), End = ExpectedMatches.end();
172 It != End; ++It) {
173 It->UpdateFor(Name, FullLocation, this->Context->getSourceManager());
Richard Smith87d8fb92012-06-24 23:56:26 +0000174 }
175 }
176
James Dennett75c100b2012-08-24 06:59:51 +0000177 private:
178 struct MatchCandidate {
179 std::string ExpectedName;
180 unsigned LineNumber;
181 unsigned ColumnNumber;
182
Zachary Turner41a9ee92017-10-11 23:54:34 +0000183 MatchCandidate(Twine Name, unsigned LineNumber, unsigned ColumnNumber)
184 : ExpectedName(Name.str()), LineNumber(LineNumber),
185 ColumnNumber(ColumnNumber) {
186 }
James Dennett75c100b2012-08-24 06:59:51 +0000187
188 bool Matches(StringRef Name, FullSourceLoc const &Location) const {
189 return MatchesName(Name) && MatchesLocation(Location);
190 }
191
192 bool PartiallyMatches(StringRef Name, FullSourceLoc const &Location) const {
193 return MatchesName(Name) || MatchesLocation(Location);
194 }
195
196 bool MatchesName(StringRef Name) const {
197 return Name == ExpectedName;
198 }
199
200 bool MatchesLocation(FullSourceLoc const &Location) const {
201 return Location.isValid() &&
202 Location.getSpellingLineNumber() == LineNumber &&
203 Location.getSpellingColumnNumber() == ColumnNumber;
204 }
205
206 friend std::ostream &operator<<(std::ostream &Stream,
207 MatchCandidate const &Match) {
208 return Stream << Match.ExpectedName
209 << " at " << Match.LineNumber << ":" << Match.ColumnNumber;
210 }
211 };
212
213 struct ExpectedMatch {
Zachary Turner41a9ee92017-10-11 23:54:34 +0000214 ExpectedMatch(Twine Name, unsigned LineNumber, unsigned ColumnNumber,
Martin Bohmed5f94a62016-08-17 14:59:53 +0000215 unsigned Times)
216 : Candidate(Name, LineNumber, ColumnNumber), TimesExpected(Times),
217 TimesSeen(0) {}
James Dennett75c100b2012-08-24 06:59:51 +0000218
219 void UpdateFor(StringRef Name, FullSourceLoc Location, SourceManager &SM) {
220 if (Candidate.Matches(Name, Location)) {
Martin Bohmed5f94a62016-08-17 14:59:53 +0000221 EXPECT_LT(TimesSeen, TimesExpected);
222 ++TimesSeen;
223 } else if (TimesSeen < TimesExpected &&
224 Candidate.PartiallyMatches(Name, Location)) {
James Dennett75c100b2012-08-24 06:59:51 +0000225 llvm::raw_string_ostream Stream(PartialMatches);
226 Stream << ", partial match: \"" << Name << "\" at ";
227 Location.print(Stream, SM);
228 }
229 }
230
231 void ExpectFound() const {
Martin Bohmed5f94a62016-08-17 14:59:53 +0000232 EXPECT_EQ(TimesExpected, TimesSeen)
James Dennett75c100b2012-08-24 06:59:51 +0000233 << "Expected \"" << Candidate.ExpectedName
234 << "\" at " << Candidate.LineNumber
235 << ":" << Candidate.ColumnNumber << PartialMatches;
236 }
237
238 MatchCandidate Candidate;
239 std::string PartialMatches;
Martin Bohmed5f94a62016-08-17 14:59:53 +0000240 unsigned TimesExpected;
241 unsigned TimesSeen;
James Dennett75c100b2012-08-24 06:59:51 +0000242 };
243
244 std::vector<MatchCandidate> DisallowedMatches;
245 std::vector<ExpectedMatch> ExpectedMatches;
Richard Smith87d8fb92012-06-24 23:56:26 +0000246};
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000247}
Richard Smith87d8fb92012-06-24 23:56:26 +0000248
Manuel Klimek20c1c892014-10-09 15:02:06 +0000249#endif