1 //===- unittest/AST/MatchVerifier.h - AST unit test support ---------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Provides MatchVerifier, a base class to implement gtest matchers that
10 // verify things that can be matched on the AST.
12 // Also implements matchers based on MatchVerifier:
13 // LocationVerifier and RangeVerifier to verify whether a matched node has
14 // the expected source location or source range.
16 //===----------------------------------------------------------------------===//
18 #ifndef LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
19 #define LLVM_CLANG_UNITTESTS_AST_MATCHVERIFIER_H
21 #include "clang/AST/ASTContext.h"
22 #include "clang/ASTMatchers/ASTMatchFinder.h"
23 #include "clang/ASTMatchers/ASTMatchers.h"
24 #include "clang/Testing/CommandLineArgs.h"
25 #include "clang/Tooling/Tooling.h"
26 #include "gtest/gtest.h"
29 namespace ast_matchers
{
31 /// \brief Base class for verifying some property of nodes found by a matcher.
32 template <typename NodeType
>
33 class MatchVerifier
: public MatchFinder::MatchCallback
{
35 template <typename MatcherType
>
36 testing::AssertionResult
match(const std::string
&Code
,
37 const MatcherType
&AMatcher
) {
38 std::vector
<std::string
> Args
;
39 return match(Code
, AMatcher
, Args
, Lang_CXX03
);
42 template <typename MatcherType
>
43 testing::AssertionResult
match(const std::string
&Code
,
44 const MatcherType
&AMatcher
, TestLanguage L
) {
45 std::vector
<std::string
> Args
;
46 return match(Code
, AMatcher
, Args
, L
);
49 template <typename MatcherType
>
50 testing::AssertionResult
51 match(const std::string
&Code
, const MatcherType
&AMatcher
,
52 std::vector
<std::string
> &Args
, TestLanguage L
);
54 template <typename MatcherType
>
55 testing::AssertionResult
match(const Decl
*D
, const MatcherType
&AMatcher
);
58 void run(const MatchFinder::MatchResult
&Result
) override
;
59 virtual void verify(const MatchFinder::MatchResult
&Result
,
60 const NodeType
&Node
) {}
62 void setFailure(const Twine
&Result
) {
64 VerifyResult
= Result
.str();
73 std::string VerifyResult
;
76 /// \brief Runs a matcher over some code, and returns the result of the
77 /// verifier for the matched node.
78 template <typename NodeType
>
79 template <typename MatcherType
>
80 testing::AssertionResult
81 MatchVerifier
<NodeType
>::match(const std::string
&Code
,
82 const MatcherType
&AMatcher
,
83 std::vector
<std::string
> &Args
, TestLanguage L
) {
85 Finder
.addMatcher(AMatcher
.bind(""), this);
86 std::unique_ptr
<tooling::FrontendActionFactory
> Factory(
87 tooling::newFrontendActionFactory(&Finder
));
91 #define TESTLANGUAGE(lang, version, std_flag, version_index) \
92 case Lang_##lang##version: \
93 Args.push_back("-std=" #std_flag); \
94 FileName = getFilenameForTesting(Lang_##lang##version); \
96 #include "clang/Testing/TestLanguage.def"
99 Args
.push_back("-cl-no-stdinc");
100 FileName
= "input.cl";
103 Args
.push_back("-fobjc-nonfragile-abi");
104 FileName
= "input.m";
107 FileName
= "input.mm";
111 // Default to failure in case callback is never called
112 setFailure("Could not find match");
113 if (!tooling::runToolOnCodeWithArgs(Factory
->create(), Code
, Args
, FileName
))
114 return testing::AssertionFailure() << "Parsing error";
116 return testing::AssertionFailure() << VerifyResult
;
117 return testing::AssertionSuccess();
120 /// \brief Runs a matcher over some AST, and returns the result of the
121 /// verifier for the matched node.
122 template <typename NodeType
> template <typename MatcherType
>
123 testing::AssertionResult MatchVerifier
<NodeType
>::match(
124 const Decl
*D
, const MatcherType
&AMatcher
) {
126 Finder
.addMatcher(AMatcher
.bind(""), this);
128 setFailure("Could not find match");
129 Finder
.match(*D
, D
->getASTContext());
132 return testing::AssertionFailure() << VerifyResult
;
133 return testing::AssertionSuccess();
136 template <typename NodeType
>
137 void MatchVerifier
<NodeType
>::run(const MatchFinder::MatchResult
&Result
) {
138 const NodeType
*Node
= Result
.Nodes
.getNodeAs
<NodeType
>("");
140 setFailure("Matched node has wrong type");
142 // Callback has been called, default to success.
144 verify(Result
, *Node
);
150 MatchVerifier
<DynTypedNode
>::run(const MatchFinder::MatchResult
&Result
) {
151 BoundNodes::IDToNodeMap M
= Result
.Nodes
.getMap();
152 BoundNodes::IDToNodeMap::const_iterator I
= M
.find("");
154 setFailure("Node was not bound");
156 // Callback has been called, default to success.
158 verify(Result
, I
->second
);
162 /// \brief Verify whether a node has the correct source location.
164 /// By default, Node.getSourceLocation() is checked. This can be changed
165 /// by overriding getLocation().
166 template <typename NodeType
>
167 class LocationVerifier
: public MatchVerifier
<NodeType
> {
169 void expectLocation(unsigned Line
, unsigned Column
) {
171 ExpectColumn
= Column
;
175 void verify(const MatchFinder::MatchResult
&Result
,
176 const NodeType
&Node
) override
{
177 SourceLocation Loc
= getLocation(Node
);
178 unsigned Line
= Result
.SourceManager
->getSpellingLineNumber(Loc
);
179 unsigned Column
= Result
.SourceManager
->getSpellingColumnNumber(Loc
);
180 if (Line
!= ExpectLine
|| Column
!= ExpectColumn
) {
182 llvm::raw_string_ostream
Msg(MsgStr
);
183 Msg
<< "Expected location <" << ExpectLine
<< ":" << ExpectColumn
185 Loc
.print(Msg
, *Result
.SourceManager
);
187 this->setFailure(MsgStr
);
191 virtual SourceLocation
getLocation(const NodeType
&Node
) {
192 return Node
.getLocation();
196 unsigned ExpectLine
, ExpectColumn
;
199 /// \brief Verify whether a node has the correct source range.
201 /// By default, Node.getSourceRange() is checked. This can be changed
202 /// by overriding getRange().
203 template <typename NodeType
>
204 class RangeVerifier
: public MatchVerifier
<NodeType
> {
206 void expectRange(unsigned BeginLine
, unsigned BeginColumn
,
207 unsigned EndLine
, unsigned EndColumn
) {
208 ExpectBeginLine
= BeginLine
;
209 ExpectBeginColumn
= BeginColumn
;
210 ExpectEndLine
= EndLine
;
211 ExpectEndColumn
= EndColumn
;
215 void verify(const MatchFinder::MatchResult
&Result
,
216 const NodeType
&Node
) override
{
217 SourceRange R
= getRange(Node
);
218 SourceLocation Begin
= R
.getBegin();
219 SourceLocation End
= R
.getEnd();
220 unsigned BeginLine
= Result
.SourceManager
->getSpellingLineNumber(Begin
);
221 unsigned BeginColumn
= Result
.SourceManager
->getSpellingColumnNumber(Begin
);
222 unsigned EndLine
= Result
.SourceManager
->getSpellingLineNumber(End
);
223 unsigned EndColumn
= Result
.SourceManager
->getSpellingColumnNumber(End
);
224 if (BeginLine
!= ExpectBeginLine
|| BeginColumn
!= ExpectBeginColumn
||
225 EndLine
!= ExpectEndLine
|| EndColumn
!= ExpectEndColumn
) {
227 llvm::raw_string_ostream
Msg(MsgStr
);
228 Msg
<< "Expected range <" << ExpectBeginLine
<< ":" << ExpectBeginColumn
229 << '-' << ExpectEndLine
<< ":" << ExpectEndColumn
<< ">, found <";
230 Begin
.print(Msg
, *Result
.SourceManager
);
232 End
.print(Msg
, *Result
.SourceManager
);
234 this->setFailure(MsgStr
);
238 virtual SourceRange
getRange(const NodeType
&Node
) {
239 return Node
.getSourceRange();
243 unsigned ExpectBeginLine
, ExpectBeginColumn
, ExpectEndLine
, ExpectEndColumn
;
246 /// \brief Verify whether a node's dump contains a given substring.
247 class DumpVerifier
: public MatchVerifier
<DynTypedNode
> {
249 void expectSubstring(const std::string
&Str
) {
250 ExpectSubstring
= Str
;
254 void verify(const MatchFinder::MatchResult
&Result
,
255 const DynTypedNode
&Node
) override
{
257 llvm::raw_string_ostream
Dump(DumpStr
);
258 Node
.dump(Dump
, *Result
.Context
);
260 if (DumpStr
.find(ExpectSubstring
) == std::string::npos
) {
262 llvm::raw_string_ostream
Msg(MsgStr
);
263 Msg
<< "Expected dump substring <" << ExpectSubstring
<< ">, found <"
265 this->setFailure(MsgStr
);
270 std::string ExpectSubstring
;
273 /// \brief Verify whether a node's pretty print matches a given string.
274 class PrintVerifier
: public MatchVerifier
<DynTypedNode
> {
276 void expectString(const std::string
&Str
) {
281 void verify(const MatchFinder::MatchResult
&Result
,
282 const DynTypedNode
&Node
) override
{
283 std::string PrintStr
;
284 llvm::raw_string_ostream
Print(PrintStr
);
285 Node
.print(Print
, Result
.Context
->getPrintingPolicy());
287 if (PrintStr
!= ExpectString
) {
289 llvm::raw_string_ostream
Msg(MsgStr
);
290 Msg
<< "Expected pretty print <" << ExpectString
<< ">, found <"
292 this->setFailure(MsgStr
);
297 std::string ExpectString
;
300 } // end namespace ast_matchers
301 } // end namespace clang