xref: /aosp_15_r20/external/clang/unittests/AST/MatchVerifier.h (revision 67e74705e28f6214e480b399dd47ea732279e315)
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