1*67e74705SXin Li //===- unittest/AST/MatchVerifier.h - AST unit test support ---------------===//
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 // Provides MatchVerifier, a base class to implement gtest matchers that
11*67e74705SXin Li // verify things that can be matched on the AST.
12*67e74705SXin Li //
13*67e74705SXin Li // Also implements matchers based on MatchVerifier:
14*67e74705SXin Li // LocationVerifier and RangeVerifier to verify whether a matched node has
15*67e74705SXin Li // the expected source location or source range.
16*67e74705SXin Li //
17*67e74705SXin Li //===----------------------------------------------------------------------===//
18*67e74705SXin Li
19*67e74705SXin Li #ifndef LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
20*67e74705SXin Li #define LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
21*67e74705SXin Li
22*67e74705SXin Li #include "clang/AST/ASTContext.h"
23*67e74705SXin Li #include "clang/ASTMatchers/ASTMatchFinder.h"
24*67e74705SXin Li #include "clang/ASTMatchers/ASTMatchers.h"
25*67e74705SXin Li #include "clang/Tooling/Tooling.h"
26*67e74705SXin Li #include "gtest/gtest.h"
27*67e74705SXin Li
28*67e74705SXin Li namespace clang {
29*67e74705SXin Li namespace ast_matchers {
30*67e74705SXin Li
31*67e74705SXin Li enum Language {
32*67e74705SXin Li Lang_C,
33*67e74705SXin Li Lang_C89,
34*67e74705SXin Li Lang_CXX,
35*67e74705SXin Li Lang_CXX11,
36*67e74705SXin Li Lang_OpenCL,
37*67e74705SXin Li Lang_OBJCXX
38*67e74705SXin Li };
39*67e74705SXin Li
40*67e74705SXin Li /// \brief Base class for verifying some property of nodes found by a matcher.
41*67e74705SXin Li template <typename NodeType>
42*67e74705SXin Li class MatchVerifier : public MatchFinder::MatchCallback {
43*67e74705SXin Li public:
44*67e74705SXin Li template <typename MatcherType>
match(const std::string & Code,const MatcherType & AMatcher)45*67e74705SXin Li testing::AssertionResult match(const std::string &Code,
46*67e74705SXin Li const MatcherType &AMatcher) {
47*67e74705SXin Li std::vector<std::string> Args;
48*67e74705SXin Li return match(Code, AMatcher, Args, Lang_CXX);
49*67e74705SXin Li }
50*67e74705SXin Li
51*67e74705SXin Li template <typename MatcherType>
match(const std::string & Code,const MatcherType & AMatcher,Language L)52*67e74705SXin Li testing::AssertionResult match(const std::string &Code,
53*67e74705SXin Li const MatcherType &AMatcher,
54*67e74705SXin Li Language L) {
55*67e74705SXin Li std::vector<std::string> Args;
56*67e74705SXin Li return match(Code, AMatcher, Args, L);
57*67e74705SXin Li }
58*67e74705SXin Li
59*67e74705SXin Li template <typename MatcherType>
60*67e74705SXin Li testing::AssertionResult match(const std::string &Code,
61*67e74705SXin Li const MatcherType &AMatcher,
62*67e74705SXin Li std::vector<std::string>& Args,
63*67e74705SXin Li Language L);
64*67e74705SXin Li
65*67e74705SXin Li template <typename MatcherType>
66*67e74705SXin Li testing::AssertionResult match(const Decl *D, const MatcherType &AMatcher);
67*67e74705SXin Li
68*67e74705SXin Li protected:
69*67e74705SXin Li void run(const MatchFinder::MatchResult &Result) override;
verify(const MatchFinder::MatchResult & Result,const NodeType & Node)70*67e74705SXin Li virtual void verify(const MatchFinder::MatchResult &Result,
71*67e74705SXin Li const NodeType &Node) {}
72*67e74705SXin Li
setFailure(const Twine & Result)73*67e74705SXin Li void setFailure(const Twine &Result) {
74*67e74705SXin Li Verified = false;
75*67e74705SXin Li VerifyResult = Result.str();
76*67e74705SXin Li }
77*67e74705SXin Li
setSuccess()78*67e74705SXin Li void setSuccess() {
79*67e74705SXin Li Verified = true;
80*67e74705SXin Li }
81*67e74705SXin Li
82*67e74705SXin Li private:
83*67e74705SXin Li bool Verified;
84*67e74705SXin Li std::string VerifyResult;
85*67e74705SXin Li };
86*67e74705SXin Li
87*67e74705SXin Li /// \brief Runs a matcher over some code, and returns the result of the
88*67e74705SXin Li /// verifier for the matched node.
89*67e74705SXin Li template <typename NodeType> template <typename MatcherType>
match(const std::string & Code,const MatcherType & AMatcher,std::vector<std::string> & Args,Language L)90*67e74705SXin Li testing::AssertionResult MatchVerifier<NodeType>::match(
91*67e74705SXin Li const std::string &Code, const MatcherType &AMatcher,
92*67e74705SXin Li std::vector<std::string>& Args, Language L) {
93*67e74705SXin Li MatchFinder Finder;
94*67e74705SXin Li Finder.addMatcher(AMatcher.bind(""), this);
95*67e74705SXin Li std::unique_ptr<tooling::FrontendActionFactory> Factory(
96*67e74705SXin Li tooling::newFrontendActionFactory(&Finder));
97*67e74705SXin Li
98*67e74705SXin Li StringRef FileName;
99*67e74705SXin Li switch (L) {
100*67e74705SXin Li case Lang_C:
101*67e74705SXin Li Args.push_back("-std=c99");
102*67e74705SXin Li FileName = "input.c";
103*67e74705SXin Li break;
104*67e74705SXin Li case Lang_C89:
105*67e74705SXin Li Args.push_back("-std=c89");
106*67e74705SXin Li FileName = "input.c";
107*67e74705SXin Li break;
108*67e74705SXin Li case Lang_CXX:
109*67e74705SXin Li Args.push_back("-std=c++98");
110*67e74705SXin Li FileName = "input.cc";
111*67e74705SXin Li break;
112*67e74705SXin Li case Lang_CXX11:
113*67e74705SXin Li Args.push_back("-std=c++11");
114*67e74705SXin Li FileName = "input.cc";
115*67e74705SXin Li break;
116*67e74705SXin Li case Lang_OpenCL:
117*67e74705SXin Li FileName = "input.cl";
118*67e74705SXin Li break;
119*67e74705SXin Li case Lang_OBJCXX:
120*67e74705SXin Li FileName = "input.mm";
121*67e74705SXin Li break;
122*67e74705SXin Li }
123*67e74705SXin Li
124*67e74705SXin Li // Default to failure in case callback is never called
125*67e74705SXin Li setFailure("Could not find match");
126*67e74705SXin Li if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
127*67e74705SXin Li return testing::AssertionFailure() << "Parsing error";
128*67e74705SXin Li if (!Verified)
129*67e74705SXin Li return testing::AssertionFailure() << VerifyResult;
130*67e74705SXin Li return testing::AssertionSuccess();
131*67e74705SXin Li }
132*67e74705SXin Li
133*67e74705SXin Li /// \brief Runs a matcher over some AST, and returns the result of the
134*67e74705SXin Li /// verifier for the matched node.
135*67e74705SXin Li template <typename NodeType> template <typename MatcherType>
match(const Decl * D,const MatcherType & AMatcher)136*67e74705SXin Li testing::AssertionResult MatchVerifier<NodeType>::match(
137*67e74705SXin Li const Decl *D, const MatcherType &AMatcher) {
138*67e74705SXin Li MatchFinder Finder;
139*67e74705SXin Li Finder.addMatcher(AMatcher.bind(""), this);
140*67e74705SXin Li
141*67e74705SXin Li setFailure("Could not find match");
142*67e74705SXin Li Finder.match(*D, D->getASTContext());
143*67e74705SXin Li
144*67e74705SXin Li if (!Verified)
145*67e74705SXin Li return testing::AssertionFailure() << VerifyResult;
146*67e74705SXin Li return testing::AssertionSuccess();
147*67e74705SXin Li }
148*67e74705SXin Li
149*67e74705SXin Li template <typename NodeType>
run(const MatchFinder::MatchResult & Result)150*67e74705SXin Li void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
151*67e74705SXin Li const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
152*67e74705SXin Li if (!Node) {
153*67e74705SXin Li setFailure("Matched node has wrong type");
154*67e74705SXin Li } else {
155*67e74705SXin Li // Callback has been called, default to success.
156*67e74705SXin Li setSuccess();
157*67e74705SXin Li verify(Result, *Node);
158*67e74705SXin Li }
159*67e74705SXin Li }
160*67e74705SXin Li
161*67e74705SXin Li template <>
run(const MatchFinder::MatchResult & Result)162*67e74705SXin Li inline void MatchVerifier<ast_type_traits::DynTypedNode>::run(
163*67e74705SXin Li const MatchFinder::MatchResult &Result) {
164*67e74705SXin Li BoundNodes::IDToNodeMap M = Result.Nodes.getMap();
165*67e74705SXin Li BoundNodes::IDToNodeMap::const_iterator I = M.find("");
166*67e74705SXin Li if (I == M.end()) {
167*67e74705SXin Li setFailure("Node was not bound");
168*67e74705SXin Li } else {
169*67e74705SXin Li // Callback has been called, default to success.
170*67e74705SXin Li setSuccess();
171*67e74705SXin Li verify(Result, I->second);
172*67e74705SXin Li }
173*67e74705SXin Li }
174*67e74705SXin Li
175*67e74705SXin Li /// \brief Verify whether a node has the correct source location.
176*67e74705SXin Li ///
177*67e74705SXin Li /// By default, Node.getSourceLocation() is checked. This can be changed
178*67e74705SXin Li /// by overriding getLocation().
179*67e74705SXin Li template <typename NodeType>
180*67e74705SXin Li class LocationVerifier : public MatchVerifier<NodeType> {
181*67e74705SXin Li public:
expectLocation(unsigned Line,unsigned Column)182*67e74705SXin Li void expectLocation(unsigned Line, unsigned Column) {
183*67e74705SXin Li ExpectLine = Line;
184*67e74705SXin Li ExpectColumn = Column;
185*67e74705SXin Li }
186*67e74705SXin Li
187*67e74705SXin Li protected:
verify(const MatchFinder::MatchResult & Result,const NodeType & Node)188*67e74705SXin Li void verify(const MatchFinder::MatchResult &Result,
189*67e74705SXin Li const NodeType &Node) override {
190*67e74705SXin Li SourceLocation Loc = getLocation(Node);
191*67e74705SXin Li unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
192*67e74705SXin Li unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
193*67e74705SXin Li if (Line != ExpectLine || Column != ExpectColumn) {
194*67e74705SXin Li std::string MsgStr;
195*67e74705SXin Li llvm::raw_string_ostream Msg(MsgStr);
196*67e74705SXin Li Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
197*67e74705SXin Li << ">, found <";
198*67e74705SXin Li Loc.print(Msg, *Result.SourceManager);
199*67e74705SXin Li Msg << '>';
200*67e74705SXin Li this->setFailure(Msg.str());
201*67e74705SXin Li }
202*67e74705SXin Li }
203*67e74705SXin Li
getLocation(const NodeType & Node)204*67e74705SXin Li virtual SourceLocation getLocation(const NodeType &Node) {
205*67e74705SXin Li return Node.getLocation();
206*67e74705SXin Li }
207*67e74705SXin Li
208*67e74705SXin Li private:
209*67e74705SXin Li unsigned ExpectLine, ExpectColumn;
210*67e74705SXin Li };
211*67e74705SXin Li
212*67e74705SXin Li /// \brief Verify whether a node has the correct source range.
213*67e74705SXin Li ///
214*67e74705SXin Li /// By default, Node.getSourceRange() is checked. This can be changed
215*67e74705SXin Li /// by overriding getRange().
216*67e74705SXin Li template <typename NodeType>
217*67e74705SXin Li class RangeVerifier : public MatchVerifier<NodeType> {
218*67e74705SXin Li public:
expectRange(unsigned BeginLine,unsigned BeginColumn,unsigned EndLine,unsigned EndColumn)219*67e74705SXin Li void expectRange(unsigned BeginLine, unsigned BeginColumn,
220*67e74705SXin Li unsigned EndLine, unsigned EndColumn) {
221*67e74705SXin Li ExpectBeginLine = BeginLine;
222*67e74705SXin Li ExpectBeginColumn = BeginColumn;
223*67e74705SXin Li ExpectEndLine = EndLine;
224*67e74705SXin Li ExpectEndColumn = EndColumn;
225*67e74705SXin Li }
226*67e74705SXin Li
227*67e74705SXin Li protected:
verify(const MatchFinder::MatchResult & Result,const NodeType & Node)228*67e74705SXin Li void verify(const MatchFinder::MatchResult &Result,
229*67e74705SXin Li const NodeType &Node) override {
230*67e74705SXin Li SourceRange R = getRange(Node);
231*67e74705SXin Li SourceLocation Begin = R.getBegin();
232*67e74705SXin Li SourceLocation End = R.getEnd();
233*67e74705SXin Li unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
234*67e74705SXin Li unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
235*67e74705SXin Li unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
236*67e74705SXin Li unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
237*67e74705SXin Li if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
238*67e74705SXin Li EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
239*67e74705SXin Li std::string MsgStr;
240*67e74705SXin Li llvm::raw_string_ostream Msg(MsgStr);
241*67e74705SXin Li Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
242*67e74705SXin Li << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
243*67e74705SXin Li Begin.print(Msg, *Result.SourceManager);
244*67e74705SXin Li Msg << '-';
245*67e74705SXin Li End.print(Msg, *Result.SourceManager);
246*67e74705SXin Li Msg << '>';
247*67e74705SXin Li this->setFailure(Msg.str());
248*67e74705SXin Li }
249*67e74705SXin Li }
250*67e74705SXin Li
getRange(const NodeType & Node)251*67e74705SXin Li virtual SourceRange getRange(const NodeType &Node) {
252*67e74705SXin Li return Node.getSourceRange();
253*67e74705SXin Li }
254*67e74705SXin Li
255*67e74705SXin Li private:
256*67e74705SXin Li unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
257*67e74705SXin Li };
258*67e74705SXin Li
259*67e74705SXin Li /// \brief Verify whether a node's dump contains a given substring.
260*67e74705SXin Li class DumpVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
261*67e74705SXin Li public:
expectSubstring(const std::string & Str)262*67e74705SXin Li void expectSubstring(const std::string &Str) {
263*67e74705SXin Li ExpectSubstring = Str;
264*67e74705SXin Li }
265*67e74705SXin Li
266*67e74705SXin Li protected:
verify(const MatchFinder::MatchResult & Result,const ast_type_traits::DynTypedNode & Node)267*67e74705SXin Li void verify(const MatchFinder::MatchResult &Result,
268*67e74705SXin Li const ast_type_traits::DynTypedNode &Node) override {
269*67e74705SXin Li std::string DumpStr;
270*67e74705SXin Li llvm::raw_string_ostream Dump(DumpStr);
271*67e74705SXin Li Node.dump(Dump, *Result.SourceManager);
272*67e74705SXin Li
273*67e74705SXin Li if (Dump.str().find(ExpectSubstring) == std::string::npos) {
274*67e74705SXin Li std::string MsgStr;
275*67e74705SXin Li llvm::raw_string_ostream Msg(MsgStr);
276*67e74705SXin Li Msg << "Expected dump substring <" << ExpectSubstring << ">, found <"
277*67e74705SXin Li << Dump.str() << '>';
278*67e74705SXin Li this->setFailure(Msg.str());
279*67e74705SXin Li }
280*67e74705SXin Li }
281*67e74705SXin Li
282*67e74705SXin Li private:
283*67e74705SXin Li std::string ExpectSubstring;
284*67e74705SXin Li };
285*67e74705SXin Li
286*67e74705SXin Li /// \brief Verify whether a node's pretty print matches a given string.
287*67e74705SXin Li class PrintVerifier : public MatchVerifier<ast_type_traits::DynTypedNode> {
288*67e74705SXin Li public:
expectString(const std::string & Str)289*67e74705SXin Li void expectString(const std::string &Str) {
290*67e74705SXin Li ExpectString = Str;
291*67e74705SXin Li }
292*67e74705SXin Li
293*67e74705SXin Li protected:
verify(const MatchFinder::MatchResult & Result,const ast_type_traits::DynTypedNode & Node)294*67e74705SXin Li void verify(const MatchFinder::MatchResult &Result,
295*67e74705SXin Li const ast_type_traits::DynTypedNode &Node) override {
296*67e74705SXin Li std::string PrintStr;
297*67e74705SXin Li llvm::raw_string_ostream Print(PrintStr);
298*67e74705SXin Li Node.print(Print, Result.Context->getPrintingPolicy());
299*67e74705SXin Li
300*67e74705SXin Li if (Print.str() != ExpectString) {
301*67e74705SXin Li std::string MsgStr;
302*67e74705SXin Li llvm::raw_string_ostream Msg(MsgStr);
303*67e74705SXin Li Msg << "Expected pretty print <" << ExpectString << ">, found <"
304*67e74705SXin Li << Print.str() << '>';
305*67e74705SXin Li this->setFailure(Msg.str());
306*67e74705SXin Li }
307*67e74705SXin Li }
308*67e74705SXin Li
309*67e74705SXin Li private:
310*67e74705SXin Li std::string ExpectString;
311*67e74705SXin Li };
312*67e74705SXin Li
313*67e74705SXin Li } // end namespace ast_matchers
314*67e74705SXin Li } // end namespace clang
315*67e74705SXin Li
316*67e74705SXin Li #endif
317