Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / AST / MatchVerifier.h
blob8bcf05642cb5bcca96fcc9a14dce13eef96f7c7b
1 //===- unittest/AST/MatchVerifier.h - AST unit test support ---------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
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"
28 namespace clang {
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 {
34 public:
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);
57 protected:
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) {
63 Verified = false;
64 VerifyResult = Result.str();
67 void setSuccess() {
68 Verified = true;
71 private:
72 bool Verified;
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) {
84 MatchFinder Finder;
85 Finder.addMatcher(AMatcher.bind(""), this);
86 std::unique_ptr<tooling::FrontendActionFactory> Factory(
87 tooling::newFrontendActionFactory(&Finder));
89 StringRef FileName;
90 switch (L) {
91 case Lang_C89:
92 Args.push_back("-std=c89");
93 FileName = "input.c";
94 break;
95 case Lang_C99:
96 Args.push_back("-std=c99");
97 FileName = "input.c";
98 break;
99 case Lang_CXX03:
100 Args.push_back("-std=c++03");
101 FileName = "input.cc";
102 break;
103 case Lang_CXX11:
104 Args.push_back("-std=c++11");
105 FileName = "input.cc";
106 break;
107 case Lang_CXX14:
108 Args.push_back("-std=c++14");
109 FileName = "input.cc";
110 break;
111 case Lang_CXX17:
112 Args.push_back("-std=c++17");
113 FileName = "input.cc";
114 break;
115 case Lang_CXX20:
116 Args.push_back("-std=c++20");
117 FileName = "input.cc";
118 break;
119 case Lang_OpenCL:
120 Args.push_back("-cl-no-stdinc");
121 FileName = "input.cl";
122 break;
123 case Lang_OBJC:
124 Args.push_back("-fobjc-nonfragile-abi");
125 FileName = "input.m";
126 break;
127 case Lang_OBJCXX:
128 FileName = "input.mm";
129 break;
132 // Default to failure in case callback is never called
133 setFailure("Could not find match");
134 if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
135 return testing::AssertionFailure() << "Parsing error";
136 if (!Verified)
137 return testing::AssertionFailure() << VerifyResult;
138 return testing::AssertionSuccess();
141 /// \brief Runs a matcher over some AST, and returns the result of the
142 /// verifier for the matched node.
143 template <typename NodeType> template <typename MatcherType>
144 testing::AssertionResult MatchVerifier<NodeType>::match(
145 const Decl *D, const MatcherType &AMatcher) {
146 MatchFinder Finder;
147 Finder.addMatcher(AMatcher.bind(""), this);
149 setFailure("Could not find match");
150 Finder.match(*D, D->getASTContext());
152 if (!Verified)
153 return testing::AssertionFailure() << VerifyResult;
154 return testing::AssertionSuccess();
157 template <typename NodeType>
158 void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
159 const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
160 if (!Node) {
161 setFailure("Matched node has wrong type");
162 } else {
163 // Callback has been called, default to success.
164 setSuccess();
165 verify(Result, *Node);
169 template <>
170 inline void
171 MatchVerifier<DynTypedNode>::run(const MatchFinder::MatchResult &Result) {
172 BoundNodes::IDToNodeMap M = Result.Nodes.getMap();
173 BoundNodes::IDToNodeMap::const_iterator I = M.find("");
174 if (I == M.end()) {
175 setFailure("Node was not bound");
176 } else {
177 // Callback has been called, default to success.
178 setSuccess();
179 verify(Result, I->second);
183 /// \brief Verify whether a node has the correct source location.
185 /// By default, Node.getSourceLocation() is checked. This can be changed
186 /// by overriding getLocation().
187 template <typename NodeType>
188 class LocationVerifier : public MatchVerifier<NodeType> {
189 public:
190 void expectLocation(unsigned Line, unsigned Column) {
191 ExpectLine = Line;
192 ExpectColumn = Column;
195 protected:
196 void verify(const MatchFinder::MatchResult &Result,
197 const NodeType &Node) override {
198 SourceLocation Loc = getLocation(Node);
199 unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
200 unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
201 if (Line != ExpectLine || Column != ExpectColumn) {
202 std::string MsgStr;
203 llvm::raw_string_ostream Msg(MsgStr);
204 Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
205 << ">, found <";
206 Loc.print(Msg, *Result.SourceManager);
207 Msg << '>';
208 this->setFailure(Msg.str());
212 virtual SourceLocation getLocation(const NodeType &Node) {
213 return Node.getLocation();
216 private:
217 unsigned ExpectLine, ExpectColumn;
220 /// \brief Verify whether a node has the correct source range.
222 /// By default, Node.getSourceRange() is checked. This can be changed
223 /// by overriding getRange().
224 template <typename NodeType>
225 class RangeVerifier : public MatchVerifier<NodeType> {
226 public:
227 void expectRange(unsigned BeginLine, unsigned BeginColumn,
228 unsigned EndLine, unsigned EndColumn) {
229 ExpectBeginLine = BeginLine;
230 ExpectBeginColumn = BeginColumn;
231 ExpectEndLine = EndLine;
232 ExpectEndColumn = EndColumn;
235 protected:
236 void verify(const MatchFinder::MatchResult &Result,
237 const NodeType &Node) override {
238 SourceRange R = getRange(Node);
239 SourceLocation Begin = R.getBegin();
240 SourceLocation End = R.getEnd();
241 unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
242 unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
243 unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
244 unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
245 if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
246 EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
247 std::string MsgStr;
248 llvm::raw_string_ostream Msg(MsgStr);
249 Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
250 << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
251 Begin.print(Msg, *Result.SourceManager);
252 Msg << '-';
253 End.print(Msg, *Result.SourceManager);
254 Msg << '>';
255 this->setFailure(Msg.str());
259 virtual SourceRange getRange(const NodeType &Node) {
260 return Node.getSourceRange();
263 private:
264 unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
267 /// \brief Verify whether a node's dump contains a given substring.
268 class DumpVerifier : public MatchVerifier<DynTypedNode> {
269 public:
270 void expectSubstring(const std::string &Str) {
271 ExpectSubstring = Str;
274 protected:
275 void verify(const MatchFinder::MatchResult &Result,
276 const DynTypedNode &Node) override {
277 std::string DumpStr;
278 llvm::raw_string_ostream Dump(DumpStr);
279 Node.dump(Dump, *Result.Context);
281 if (Dump.str().find(ExpectSubstring) == std::string::npos) {
282 std::string MsgStr;
283 llvm::raw_string_ostream Msg(MsgStr);
284 Msg << "Expected dump substring <" << ExpectSubstring << ">, found <"
285 << Dump.str() << '>';
286 this->setFailure(Msg.str());
290 private:
291 std::string ExpectSubstring;
294 /// \brief Verify whether a node's pretty print matches a given string.
295 class PrintVerifier : public MatchVerifier<DynTypedNode> {
296 public:
297 void expectString(const std::string &Str) {
298 ExpectString = Str;
301 protected:
302 void verify(const MatchFinder::MatchResult &Result,
303 const DynTypedNode &Node) override {
304 std::string PrintStr;
305 llvm::raw_string_ostream Print(PrintStr);
306 Node.print(Print, Result.Context->getPrintingPolicy());
308 if (Print.str() != ExpectString) {
309 std::string MsgStr;
310 llvm::raw_string_ostream Msg(MsgStr);
311 Msg << "Expected pretty print <" << ExpectString << ">, found <"
312 << Print.str() << '>';
313 this->setFailure(Msg.str());
317 private:
318 std::string ExpectString;
321 } // end namespace ast_matchers
322 } // end namespace clang
324 #endif