blob: 63571d35adfb3004ed500c5033136f75522f9a69 [file] [log] [blame]
Richard Smithbc9e5582012-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//===----------------------------------------------------------------------===//
9//
10// This file defines a utility class for RecursiveASTVisitor related tests.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_TEST_VISITOR_H
15#define LLVM_CLANG_TEST_VISITOR_H
16
Benjamin Kramera13d2bc2012-07-04 20:33:53 +000017#include "clang/AST/ASTContext.h"
Richard Smithbc9e5582012-06-24 23:56:26 +000018#include "clang/AST/ASTConsumer.h"
19#include "clang/AST/RecursiveASTVisitor.h"
20#include "clang/Frontend/FrontendAction.h"
21#include "clang/Frontend/CompilerInstance.h"
22#include "clang/Tooling/Tooling.h"
23#include "gtest/gtest.h"
24
25namespace clang {
26
Matt Beaumont-Gay8f35d232012-06-25 18:27:11 +000027/// \brief Base class for simple RecursiveASTVisitor based tests.
Richard Smithbc9e5582012-06-24 23:56:26 +000028///
29/// This is a drop-in replacement for RecursiveASTVisitor itself, with the
30/// additional capability of running it over a snippet of code.
31///
32/// Visits template instantiations by default.
33template <typename T>
34class TestVisitor : public RecursiveASTVisitor<T> {
35public:
36 TestVisitor() { }
37
Matt Beaumont-Gay8f35d232012-06-25 18:27:11 +000038 virtual ~TestVisitor() { }
39
Richard Smith82b45502012-08-17 21:23:17 +000040 enum Language { Lang_C, Lang_CXX };
41
Richard Smithbc9e5582012-06-24 23:56:26 +000042 /// \brief Runs the current AST visitor over the given code.
Richard Smith82b45502012-08-17 21:23:17 +000043 bool runOver(StringRef Code, Language L = Lang_CXX) {
44 // FIXME: The input language is determined based on the provided filename.
45 static const StringRef Filenames[] = { "input.c", "input.cc" };
46 return tooling::runToolOnCode(CreateTestAction(), Code, Filenames[L]);
Richard Smithbc9e5582012-06-24 23:56:26 +000047 }
48
49 bool shouldVisitTemplateInstantiations() const {
50 return true;
51 }
52
53protected:
54 virtual ASTFrontendAction* CreateTestAction() {
55 return new TestAction(this);
56 }
57
58 class FindConsumer : public ASTConsumer {
59 public:
60 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
61
62 virtual void HandleTranslationUnit(clang::ASTContext &Context) {
Manuel Klimeke6df0ce2012-07-05 18:13:01 +000063 Visitor->Context = &Context;
Richard Smithbc9e5582012-06-24 23:56:26 +000064 Visitor->TraverseDecl(Context.getTranslationUnitDecl());
65 }
66
67 private:
68 TestVisitor *Visitor;
69 };
70
71 class TestAction : public ASTFrontendAction {
72 public:
73 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
74
75 virtual clang::ASTConsumer* CreateASTConsumer(
Manuel Klimeke6df0ce2012-07-05 18:13:01 +000076 CompilerInstance&, llvm::StringRef dummy) {
Richard Smithbc9e5582012-06-24 23:56:26 +000077 /// TestConsumer will be deleted by the framework calling us.
78 return new FindConsumer(Visitor);
79 }
80
81 protected:
82 TestVisitor *Visitor;
83 };
84
85 ASTContext *Context;
86};
87
88
89/// \brief A RecursiveASTVisitor for testing the RecursiveASTVisitor itself.
90///
91/// Allows simple creation of test visitors running matches on only a small
92/// subset of the Visit* methods.
93template <typename T, template <typename> class Visitor = TestVisitor>
94class ExpectedLocationVisitor : public Visitor<T> {
95public:
96 ExpectedLocationVisitor()
97 : ExpectedLine(0), ExpectedColumn(0), Found(false) {}
98
Matt Beaumont-Gay8f35d232012-06-25 18:27:11 +000099 virtual ~ExpectedLocationVisitor() {
Richard Smithbc9e5582012-06-24 23:56:26 +0000100 EXPECT_TRUE(Found)
101 << "Expected \"" << ExpectedMatch << "\" at " << ExpectedLine
102 << ":" << ExpectedColumn << PartialMatches;
103 }
104
105 /// \brief Expect 'Match' to occur at the given 'Line' and 'Column'.
106 void ExpectMatch(Twine Match, unsigned Line, unsigned Column) {
107 ExpectedMatch = Match.str();
108 ExpectedLine = Line;
109 ExpectedColumn = Column;
110 }
111
112protected:
113 /// \brief Convenience method to simplify writing test visitors.
114 ///
115 /// Sets 'Found' to true if 'Name' and 'Location' match the expected
116 /// values. If only a partial match is found, record the information
117 /// to produce nice error output when a test fails.
118 ///
119 /// Implementations are required to call this with appropriate values
120 /// for 'Name' during visitation.
121 void Match(StringRef Name, SourceLocation Location) {
122 FullSourceLoc FullLocation = this->Context->getFullLoc(Location);
123 if (Name == ExpectedMatch &&
124 FullLocation.isValid() &&
125 FullLocation.getSpellingLineNumber() == ExpectedLine &&
126 FullLocation.getSpellingColumnNumber() == ExpectedColumn) {
127 EXPECT_TRUE(!Found);
128 Found = true;
129 } else if (Name == ExpectedMatch ||
130 (FullLocation.isValid() &&
131 FullLocation.getSpellingLineNumber() == ExpectedLine &&
132 FullLocation.getSpellingColumnNumber() == ExpectedColumn)) {
133 // If we did not match, record information about partial matches.
134 llvm::raw_string_ostream Stream(PartialMatches);
135 Stream << ", partial match: \"" << Name << "\" at ";
136 Location.print(Stream, this->Context->getSourceManager());
137 }
138 }
139
140 std::string ExpectedMatch;
141 unsigned ExpectedLine;
142 unsigned ExpectedColumn;
143 std::string PartialMatches;
144 bool Found;
145};
146}
147
148#endif /* LLVM_CLANG_TEST_VISITOR_H */