]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - unittests/ASTMatchers/ASTMatchersTest.h
Vendor import of clang trunk r338150:
[FreeBSD/FreeBSD.git] / unittests / ASTMatchers / ASTMatchersTest.h
1 //===- unittest/Tooling/ASTMatchersTest.h - Matcher tests helpers ------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
11 #define LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
12
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/Frontend/ASTUnit.h"
15 #include "clang/Tooling/Tooling.h"
16 #include "gtest/gtest.h"
17
18 namespace clang {
19 namespace ast_matchers {
20
21 using clang::tooling::buildASTFromCodeWithArgs;
22 using clang::tooling::newFrontendActionFactory;
23 using clang::tooling::runToolOnCodeWithArgs;
24 using clang::tooling::FrontendActionFactory;
25 using clang::tooling::FileContentMappings;
26
27 class BoundNodesCallback {
28 public:
29   virtual ~BoundNodesCallback() {}
30   virtual bool run(const BoundNodes *BoundNodes) = 0;
31   virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0;
32   virtual void onEndOfTranslationUnit() {}
33 };
34
35 // If 'FindResultVerifier' is not NULL, sets *Verified to the result of
36 // running 'FindResultVerifier' with the bound nodes as argument.
37 // If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called.
38 class VerifyMatch : public MatchFinder::MatchCallback {
39 public:
40   VerifyMatch(std::unique_ptr<BoundNodesCallback> FindResultVerifier, bool *Verified)
41       : Verified(Verified), FindResultReviewer(std::move(FindResultVerifier)) {}
42
43   void run(const MatchFinder::MatchResult &Result) override {
44     if (FindResultReviewer != nullptr) {
45       *Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context);
46     } else {
47       *Verified = true;
48     }
49   }
50
51   void onEndOfTranslationUnit() override {
52     if (FindResultReviewer)
53       FindResultReviewer->onEndOfTranslationUnit();
54   }
55
56 private:
57   bool *const Verified;
58   const std::unique_ptr<BoundNodesCallback> FindResultReviewer;
59 };
60
61 template <typename T>
62 testing::AssertionResult matchesConditionally(
63     const std::string &Code, const T &AMatcher, bool ExpectMatch,
64     llvm::ArrayRef<llvm::StringRef> CompileArgs,
65     const FileContentMappings &VirtualMappedFiles = FileContentMappings(),
66     const std::string &Filename = "input.cc") {
67   bool Found = false, DynamicFound = false;
68   MatchFinder Finder;
69   VerifyMatch VerifyFound(nullptr, &Found);
70   Finder.addMatcher(AMatcher, &VerifyFound);
71   VerifyMatch VerifyDynamicFound(nullptr, &DynamicFound);
72   if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound))
73     return testing::AssertionFailure() << "Could not add dynamic matcher";
74   std::unique_ptr<FrontendActionFactory> Factory(
75       newFrontendActionFactory(&Finder));
76   // Some tests need rtti/exceptions on.  Use an unknown-unknown triple so we
77   // don't instantiate the full system toolchain.  On Linux, instantiating the
78   // toolchain involves stat'ing large portions of /usr/lib, and this slows down
79   // not only this test, but all other tests, via contention in the kernel.
80   //
81   // FIXME: This is a hack to work around the fact that there's no way to do the
82   // equivalent of runToolOnCodeWithArgs without instantiating a full Driver.
83   // We should consider having a function, at least for tests, that invokes cc1.
84   std::vector<std::string> Args(CompileArgs.begin(), CompileArgs.end());
85   Args.insert(Args.end(), {"-frtti", "-fexceptions",
86                            "-target", "i386-unknown-unknown"});
87   if (!runToolOnCodeWithArgs(
88           Factory->create(), Code, Args, Filename, "clang-tool",
89           std::make_shared<PCHContainerOperations>(), VirtualMappedFiles)) {
90     return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
91   }
92   if (Found != DynamicFound) {
93     return testing::AssertionFailure() << "Dynamic match result ("
94                                        << DynamicFound
95                                        << ") does not match static result ("
96                                        << Found << ")";
97   }
98   if (!Found && ExpectMatch) {
99     return testing::AssertionFailure()
100       << "Could not find match in \"" << Code << "\"";
101   } else if (Found && !ExpectMatch) {
102     return testing::AssertionFailure()
103       << "Found unexpected match in \"" << Code << "\"";
104   }
105   return testing::AssertionSuccess();
106 }
107
108 template <typename T>
109 testing::AssertionResult matchesConditionally(
110     const std::string &Code, const T &AMatcher, bool ExpectMatch,
111     llvm::StringRef CompileArg,
112     const FileContentMappings &VirtualMappedFiles = FileContentMappings(),
113     const std::string &Filename = "input.cc") {
114   return matchesConditionally(Code, AMatcher, ExpectMatch,
115                               llvm::makeArrayRef(CompileArg),
116                               VirtualMappedFiles, Filename);
117 }
118
119 template <typename T>
120 testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
121   return matchesConditionally(Code, AMatcher, true, "-std=c++11");
122 }
123
124 template <typename T>
125 testing::AssertionResult notMatches(const std::string &Code,
126                                     const T &AMatcher) {
127   return matchesConditionally(Code, AMatcher, false, "-std=c++11");
128 }
129
130 template <typename T>
131 testing::AssertionResult matchesObjC(const std::string &Code, const T &AMatcher,
132                                      bool ExpectMatch = true) {
133   return matchesConditionally(Code, AMatcher, ExpectMatch,
134                               {"-fobjc-nonfragile-abi", "-Wno-objc-root-class",
135                                "-fblocks", "-Wno-incomplete-implementation"},
136                               FileContentMappings(), "input.m");
137 }
138
139 template <typename T>
140 testing::AssertionResult matchesC(const std::string &Code, const T &AMatcher) {
141   return matchesConditionally(Code, AMatcher, true, "", FileContentMappings(),
142                               "input.c");
143 }
144
145 template <typename T>
146 testing::AssertionResult matchesC99(const std::string &Code,
147                                     const T &AMatcher) {
148   return matchesConditionally(Code, AMatcher, true, "-std=c99",
149                               FileContentMappings(), "input.c");
150 }
151
152 template <typename T>
153 testing::AssertionResult notMatchesC(const std::string &Code,
154                                      const T &AMatcher) {
155   return matchesConditionally(Code, AMatcher, false, "", FileContentMappings(),
156                               "input.c");
157 }
158
159 template <typename T>
160 testing::AssertionResult notMatchesObjC(const std::string &Code,
161                                         const T &AMatcher) {
162   return matchesObjC(Code, AMatcher, false);
163 }
164
165
166 // Function based on matchesConditionally with "-x cuda" argument added and
167 // small CUDA header prepended to the code string.
168 template <typename T>
169 testing::AssertionResult matchesConditionallyWithCuda(
170     const std::string &Code, const T &AMatcher, bool ExpectMatch,
171     llvm::StringRef CompileArg) {
172   const std::string CudaHeader =
173       "typedef unsigned int size_t;\n"
174       "#define __constant__ __attribute__((constant))\n"
175       "#define __device__ __attribute__((device))\n"
176       "#define __global__ __attribute__((global))\n"
177       "#define __host__ __attribute__((host))\n"
178       "#define __shared__ __attribute__((shared))\n"
179       "struct dim3 {"
180       "  unsigned x, y, z;"
181       "  __host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1)"
182       "      : x(x), y(y), z(z) {}"
183       "};"
184       "typedef struct cudaStream *cudaStream_t;"
185       "int cudaConfigureCall(dim3 gridSize, dim3 blockSize,"
186       "                      size_t sharedSize = 0,"
187       "                      cudaStream_t stream = 0);";
188
189   bool Found = false, DynamicFound = false;
190   MatchFinder Finder;
191   VerifyMatch VerifyFound(nullptr, &Found);
192   Finder.addMatcher(AMatcher, &VerifyFound);
193   VerifyMatch VerifyDynamicFound(nullptr, &DynamicFound);
194   if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound))
195     return testing::AssertionFailure() << "Could not add dynamic matcher";
196   std::unique_ptr<FrontendActionFactory> Factory(
197       newFrontendActionFactory(&Finder));
198   // Some tests use typeof, which is a gnu extension.  Using an explicit
199   // unknown-unknown triple is good for a large speedup, because it lets us
200   // avoid constructing a full system triple.
201   std::vector<std::string> Args = {
202       "-xcuda",  "-fno-ms-extensions",      "--cuda-host-only", "-nocudainc",
203       "-target", "x86_64-unknown-unknown", CompileArg};
204   if (!runToolOnCodeWithArgs(Factory->create(),
205                              CudaHeader + Code, Args)) {
206     return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
207   }
208   if (Found != DynamicFound) {
209     return testing::AssertionFailure() << "Dynamic match result ("
210                                        << DynamicFound
211                                        << ") does not match static result ("
212                                        << Found << ")";
213   }
214   if (!Found && ExpectMatch) {
215     return testing::AssertionFailure()
216       << "Could not find match in \"" << Code << "\"";
217   } else if (Found && !ExpectMatch) {
218     return testing::AssertionFailure()
219       << "Found unexpected match in \"" << Code << "\"";
220   }
221   return testing::AssertionSuccess();
222 }
223
224 template <typename T>
225 testing::AssertionResult matchesWithCuda(const std::string &Code,
226                                          const T &AMatcher) {
227   return matchesConditionallyWithCuda(Code, AMatcher, true, "-std=c++11");
228 }
229
230 template <typename T>
231 testing::AssertionResult notMatchesWithCuda(const std::string &Code,
232                                     const T &AMatcher) {
233   return matchesConditionallyWithCuda(Code, AMatcher, false, "-std=c++11");
234 }
235
236 template <typename T>
237 testing::AssertionResult
238 matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
239                                   std::unique_ptr<BoundNodesCallback> FindResultVerifier,
240                                   bool ExpectResult) {
241   bool VerifiedResult = false;
242   MatchFinder Finder;
243   VerifyMatch VerifyVerifiedResult(std::move(FindResultVerifier), &VerifiedResult);
244   Finder.addMatcher(AMatcher, &VerifyVerifiedResult);
245   std::unique_ptr<FrontendActionFactory> Factory(
246       newFrontendActionFactory(&Finder));
247   // Some tests use typeof, which is a gnu extension.  Using an explicit
248   // unknown-unknown triple is good for a large speedup, because it lets us
249   // avoid constructing a full system triple.
250   std::vector<std::string> Args = {"-std=gnu++98", "-target",
251                                    "i386-unknown-unknown"};
252   if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
253     return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
254   }
255   if (!VerifiedResult && ExpectResult) {
256     return testing::AssertionFailure()
257       << "Could not verify result in \"" << Code << "\"";
258   } else if (VerifiedResult && !ExpectResult) {
259     return testing::AssertionFailure()
260       << "Verified unexpected result in \"" << Code << "\"";
261   }
262
263   VerifiedResult = false;
264   std::unique_ptr<ASTUnit> AST(buildASTFromCodeWithArgs(Code, Args));
265   if (!AST.get())
266     return testing::AssertionFailure() << "Parsing error in \"" << Code
267                                        << "\" while building AST";
268   Finder.matchAST(AST->getASTContext());
269   if (!VerifiedResult && ExpectResult) {
270     return testing::AssertionFailure()
271       << "Could not verify result in \"" << Code << "\" with AST";
272   } else if (VerifiedResult && !ExpectResult) {
273     return testing::AssertionFailure()
274       << "Verified unexpected result in \"" << Code << "\" with AST";
275   }
276
277   return testing::AssertionSuccess();
278 }
279
280 // FIXME: Find better names for these functions (or document what they
281 // do more precisely).
282 template <typename T>
283 testing::AssertionResult
284 matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher,
285                          std::unique_ptr<BoundNodesCallback> FindResultVerifier) {
286   return matchAndVerifyResultConditionally(
287       Code, AMatcher, std::move(FindResultVerifier), true);
288 }
289
290 template <typename T>
291 testing::AssertionResult
292 matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher,
293                           std::unique_ptr<BoundNodesCallback> FindResultVerifier) {
294   return matchAndVerifyResultConditionally(
295       Code, AMatcher, std::move(FindResultVerifier), false);
296 }
297
298 // Implements a run method that returns whether BoundNodes contains a
299 // Decl bound to Id that can be dynamically cast to T.
300 // Optionally checks that the check succeeded a specific number of times.
301 template <typename T>
302 class VerifyIdIsBoundTo : public BoundNodesCallback {
303 public:
304   // Create an object that checks that a node of type \c T was bound to \c Id.
305   // Does not check for a certain number of matches.
306   explicit VerifyIdIsBoundTo(llvm::StringRef Id)
307     : Id(Id), ExpectedCount(-1), Count(0) {}
308
309   // Create an object that checks that a node of type \c T was bound to \c Id.
310   // Checks that there were exactly \c ExpectedCount matches.
311   VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount)
312     : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
313
314   // Create an object that checks that a node of type \c T was bound to \c Id.
315   // Checks that there was exactly one match with the name \c ExpectedName.
316   // Note that \c T must be a NamedDecl for this to work.
317   VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName,
318                     int ExpectedCount = 1)
319     : Id(Id), ExpectedCount(ExpectedCount), Count(0),
320       ExpectedName(ExpectedName) {}
321
322   void onEndOfTranslationUnit() override {
323     if (ExpectedCount != -1) {
324       EXPECT_EQ(ExpectedCount, Count);
325     }
326     if (!ExpectedName.empty()) {
327       EXPECT_EQ(ExpectedName, Name);
328     }
329     Count = 0;
330     Name.clear();
331   }
332
333   ~VerifyIdIsBoundTo() override {
334     EXPECT_EQ(0, Count);
335     EXPECT_EQ("", Name);
336   }
337
338   bool run(const BoundNodes *Nodes) override {
339     const BoundNodes::IDToNodeMap &M = Nodes->getMap();
340     if (Nodes->getNodeAs<T>(Id)) {
341       ++Count;
342       if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) {
343         Name = Named->getNameAsString();
344       } else if (const NestedNameSpecifier *NNS =
345         Nodes->getNodeAs<NestedNameSpecifier>(Id)) {
346         llvm::raw_string_ostream OS(Name);
347         NNS->print(OS, PrintingPolicy(LangOptions()));
348       }
349       BoundNodes::IDToNodeMap::const_iterator I = M.find(Id);
350       EXPECT_NE(M.end(), I);
351       if (I != M.end()) {
352         EXPECT_EQ(Nodes->getNodeAs<T>(Id), I->second.get<T>());
353       }
354       return true;
355     }
356     EXPECT_TRUE(M.count(Id) == 0 ||
357       M.find(Id)->second.template get<T>() == nullptr);
358     return false;
359   }
360
361   bool run(const BoundNodes *Nodes, ASTContext *Context) override {
362     return run(Nodes);
363   }
364
365 private:
366   const std::string Id;
367   const int ExpectedCount;
368   int Count;
369   const std::string ExpectedName;
370   std::string Name;
371 };
372
373 } // namespace ast_matchers
374 } // namespace clang
375
376 #endif  // LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H