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(BoundNodesCallback *FindResultVerifier, bool *Verified) 41 : Verified(Verified), FindResultReviewer(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 BoundNodesCallback *const FindResultReviewer; 59 }; 60 61 template <typename T> 62 testing::AssertionResult matchesConditionally( 63 const std::string &Code, const T &AMatcher, bool ExpectMatch, 64 llvm::StringRef CompileArg, 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 use typeof, which is a gnu extension. 77 std::vector<std::string> Args; 78 Args.push_back(CompileArg); 79 // Some tests need rtti/exceptions on 80 Args.push_back("-frtti"); 81 Args.push_back("-fexceptions"); 82 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, Filename, 83 std::make_shared<PCHContainerOperations>(), 84 VirtualMappedFiles)) { 85 return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; 86 } 87 if (Found != DynamicFound) { 88 return testing::AssertionFailure() << "Dynamic match result (" 89 << DynamicFound 90 << ") does not match static result (" 91 << Found << ")"; 92 } 93 if (!Found && ExpectMatch) { 94 return testing::AssertionFailure() 95 << "Could not find match in \"" << Code << "\""; 96 } else if (Found && !ExpectMatch) { 97 return testing::AssertionFailure() 98 << "Found unexpected match in \"" << Code << "\""; 99 } 100 return testing::AssertionSuccess(); 101 } 102 103 template <typename T> 104 testing::AssertionResult matches(const std::string &Code, const T &AMatcher) { 105 return matchesConditionally(Code, AMatcher, true, "-std=c++11"); 106 } 107 108 template <typename T> 109 testing::AssertionResult notMatches(const std::string &Code, 110 const T &AMatcher) { 111 return matchesConditionally(Code, AMatcher, false, "-std=c++11"); 112 } 113 114 template <typename T> 115 testing::AssertionResult matchesObjC(const std::string &Code, 116 const T &AMatcher) { 117 return matchesConditionally( 118 Code, AMatcher, true, 119 "", FileContentMappings(), "input.m"); 120 } 121 122 template <typename T> 123 testing::AssertionResult matchesC(const std::string &Code, const T &AMatcher) { 124 return matchesConditionally(Code, AMatcher, true, "", FileContentMappings(), 125 "input.c"); 126 } 127 128 template <typename T> 129 testing::AssertionResult notMatchesC(const std::string &Code, 130 const T &AMatcher) { 131 return matchesConditionally(Code, AMatcher, false, "", FileContentMappings(), 132 "input.c"); 133 } 134 135 template <typename T> 136 testing::AssertionResult notMatchesObjC(const std::string &Code, 137 const T &AMatcher) { 138 return matchesConditionally( 139 Code, AMatcher, false, 140 "", FileContentMappings(), "input.m"); 141 } 142 143 144 // Function based on matchesConditionally with "-x cuda" argument added and 145 // small CUDA header prepended to the code string. 146 template <typename T> 147 testing::AssertionResult matchesConditionallyWithCuda( 148 const std::string &Code, const T &AMatcher, bool ExpectMatch, 149 llvm::StringRef CompileArg) { 150 const std::string CudaHeader = 151 "typedef unsigned int size_t;\n" 152 "#define __constant__ __attribute__((constant))\n" 153 "#define __device__ __attribute__((device))\n" 154 "#define __global__ __attribute__((global))\n" 155 "#define __host__ __attribute__((host))\n" 156 "#define __shared__ __attribute__((shared))\n" 157 "struct dim3 {" 158 " unsigned x, y, z;" 159 " __host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1)" 160 " : x(x), y(y), z(z) {}" 161 "};" 162 "typedef struct cudaStream *cudaStream_t;" 163 "int cudaConfigureCall(dim3 gridSize, dim3 blockSize," 164 " size_t sharedSize = 0," 165 " cudaStream_t stream = 0);"; 166 167 bool Found = false, DynamicFound = false; 168 MatchFinder Finder; 169 VerifyMatch VerifyFound(nullptr, &Found); 170 Finder.addMatcher(AMatcher, &VerifyFound); 171 VerifyMatch VerifyDynamicFound(nullptr, &DynamicFound); 172 if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound)) 173 return testing::AssertionFailure() << "Could not add dynamic matcher"; 174 std::unique_ptr<FrontendActionFactory> Factory( 175 newFrontendActionFactory(&Finder)); 176 // Some tests use typeof, which is a gnu extension. 177 std::vector<std::string> Args; 178 Args.push_back("-xcuda"); 179 Args.push_back("-fno-ms-extensions"); 180 Args.push_back("--cuda-host-only"); 181 Args.push_back("-nocudainc"); 182 Args.push_back(CompileArg); 183 if (!runToolOnCodeWithArgs(Factory->create(), 184 CudaHeader + Code, Args)) { 185 return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; 186 } 187 if (Found != DynamicFound) { 188 return testing::AssertionFailure() << "Dynamic match result (" 189 << DynamicFound 190 << ") does not match static result (" 191 << Found << ")"; 192 } 193 if (!Found && ExpectMatch) { 194 return testing::AssertionFailure() 195 << "Could not find match in \"" << Code << "\""; 196 } else if (Found && !ExpectMatch) { 197 return testing::AssertionFailure() 198 << "Found unexpected match in \"" << Code << "\""; 199 } 200 return testing::AssertionSuccess(); 201 } 202 203 template <typename T> 204 testing::AssertionResult matchesWithCuda(const std::string &Code, 205 const T &AMatcher) { 206 return matchesConditionallyWithCuda(Code, AMatcher, true, "-std=c++11"); 207 } 208 209 template <typename T> 210 testing::AssertionResult notMatchesWithCuda(const std::string &Code, 211 const T &AMatcher) { 212 return matchesConditionallyWithCuda(Code, AMatcher, false, "-std=c++11"); 213 } 214 215 template <typename T> 216 testing::AssertionResult 217 matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher, 218 BoundNodesCallback *FindResultVerifier, 219 bool ExpectResult) { 220 std::unique_ptr<BoundNodesCallback> ScopedVerifier(FindResultVerifier); 221 bool VerifiedResult = false; 222 MatchFinder Finder; 223 VerifyMatch VerifyVerifiedResult(FindResultVerifier, &VerifiedResult); 224 Finder.addMatcher(AMatcher, &VerifyVerifiedResult); 225 std::unique_ptr<FrontendActionFactory> Factory( 226 newFrontendActionFactory(&Finder)); 227 // Some tests use typeof, which is a gnu extension. 228 std::vector<std::string> Args(1, "-std=gnu++98"); 229 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) { 230 return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; 231 } 232 if (!VerifiedResult && ExpectResult) { 233 return testing::AssertionFailure() 234 << "Could not verify result in \"" << Code << "\""; 235 } else if (VerifiedResult && !ExpectResult) { 236 return testing::AssertionFailure() 237 << "Verified unexpected result in \"" << Code << "\""; 238 } 239 240 VerifiedResult = false; 241 std::unique_ptr<ASTUnit> AST(buildASTFromCodeWithArgs(Code, Args)); 242 if (!AST.get()) 243 return testing::AssertionFailure() << "Parsing error in \"" << Code 244 << "\" while building AST"; 245 Finder.matchAST(AST->getASTContext()); 246 if (!VerifiedResult && ExpectResult) { 247 return testing::AssertionFailure() 248 << "Could not verify result in \"" << Code << "\" with AST"; 249 } else if (VerifiedResult && !ExpectResult) { 250 return testing::AssertionFailure() 251 << "Verified unexpected result in \"" << Code << "\" with AST"; 252 } 253 254 return testing::AssertionSuccess(); 255 } 256 257 // FIXME: Find better names for these functions (or document what they 258 // do more precisely). 259 template <typename T> 260 testing::AssertionResult 261 matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher, 262 BoundNodesCallback *FindResultVerifier) { 263 return matchAndVerifyResultConditionally( 264 Code, AMatcher, FindResultVerifier, true); 265 } 266 267 template <typename T> 268 testing::AssertionResult 269 matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher, 270 BoundNodesCallback *FindResultVerifier) { 271 return matchAndVerifyResultConditionally( 272 Code, AMatcher, FindResultVerifier, false); 273 } 274 275 } // end namespace ast_matchers 276 } // end namespace clang 277 278 #endif // LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H 279