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