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_AST_MATCHERS_AST_MATCHERS_TEST_H 11 #define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_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 26 class BoundNodesCallback { 27 public: 28 virtual ~BoundNodesCallback() {} 29 virtual bool run(const BoundNodes *BoundNodes) = 0; 30 virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0; 31 virtual void onEndOfTranslationUnit() {} 32 }; 33 34 // If 'FindResultVerifier' is not NULL, sets *Verified to the result of 35 // running 'FindResultVerifier' with the bound nodes as argument. 36 // If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called. 37 class VerifyMatch : public MatchFinder::MatchCallback { 38 public: 39 VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified) 40 : Verified(Verified), FindResultReviewer(FindResultVerifier) {} 41 42 virtual void run(const MatchFinder::MatchResult &Result) { 43 if (FindResultReviewer != nullptr) { 44 *Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context); 45 } else { 46 *Verified = true; 47 } 48 } 49 50 void onEndOfTranslationUnit() override { 51 if (FindResultReviewer) 52 FindResultReviewer->onEndOfTranslationUnit(); 53 } 54 55 private: 56 bool *const Verified; 57 BoundNodesCallback *const FindResultReviewer; 58 }; 59 60 template <typename T> 61 testing::AssertionResult matchesConditionally(const std::string &Code, 62 const T &AMatcher, 63 bool ExpectMatch, 64 llvm::StringRef CompileArg) { 65 bool Found = false, DynamicFound = false; 66 MatchFinder Finder; 67 VerifyMatch VerifyFound(nullptr, &Found); 68 Finder.addMatcher(AMatcher, &VerifyFound); 69 VerifyMatch VerifyDynamicFound(nullptr, &DynamicFound); 70 if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound)) 71 return testing::AssertionFailure() << "Could not add dynamic matcher"; 72 std::unique_ptr<FrontendActionFactory> Factory( 73 newFrontendActionFactory(&Finder)); 74 // Some tests use typeof, which is a gnu extension. 75 std::vector<std::string> Args(1, CompileArg); 76 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) { 77 return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; 78 } 79 if (Found != DynamicFound) { 80 return testing::AssertionFailure() << "Dynamic match result (" 81 << DynamicFound 82 << ") does not match static result (" 83 << Found << ")"; 84 } 85 if (!Found && ExpectMatch) { 86 return testing::AssertionFailure() 87 << "Could not find match in \"" << Code << "\""; 88 } else if (Found && !ExpectMatch) { 89 return testing::AssertionFailure() 90 << "Found unexpected match in \"" << Code << "\""; 91 } 92 return testing::AssertionSuccess(); 93 } 94 95 template <typename T> 96 testing::AssertionResult matches(const std::string &Code, const T &AMatcher) { 97 return matchesConditionally(Code, AMatcher, true, "-std=c++11"); 98 } 99 100 template <typename T> 101 testing::AssertionResult notMatches(const std::string &Code, 102 const T &AMatcher) { 103 return matchesConditionally(Code, AMatcher, false, "-std=c++11"); 104 } 105 106 template <typename T> 107 testing::AssertionResult 108 matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher, 109 BoundNodesCallback *FindResultVerifier, 110 bool ExpectResult) { 111 std::unique_ptr<BoundNodesCallback> ScopedVerifier(FindResultVerifier); 112 bool VerifiedResult = false; 113 MatchFinder Finder; 114 VerifyMatch VerifyVerifiedResult(FindResultVerifier, &VerifiedResult); 115 Finder.addMatcher(AMatcher, &VerifyVerifiedResult); 116 std::unique_ptr<FrontendActionFactory> Factory( 117 newFrontendActionFactory(&Finder)); 118 // Some tests use typeof, which is a gnu extension. 119 std::vector<std::string> Args(1, "-std=gnu++98"); 120 if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) { 121 return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; 122 } 123 if (!VerifiedResult && ExpectResult) { 124 return testing::AssertionFailure() 125 << "Could not verify result in \"" << Code << "\""; 126 } else if (VerifiedResult && !ExpectResult) { 127 return testing::AssertionFailure() 128 << "Verified unexpected result in \"" << Code << "\""; 129 } 130 131 VerifiedResult = false; 132 std::unique_ptr<ASTUnit> AST(buildASTFromCodeWithArgs(Code, Args)); 133 if (!AST.get()) 134 return testing::AssertionFailure() << "Parsing error in \"" << Code 135 << "\" while building AST"; 136 Finder.matchAST(AST->getASTContext()); 137 if (!VerifiedResult && ExpectResult) { 138 return testing::AssertionFailure() 139 << "Could not verify result in \"" << Code << "\" with AST"; 140 } else if (VerifiedResult && !ExpectResult) { 141 return testing::AssertionFailure() 142 << "Verified unexpected result in \"" << Code << "\" with AST"; 143 } 144 145 return testing::AssertionSuccess(); 146 } 147 148 // FIXME: Find better names for these functions (or document what they 149 // do more precisely). 150 template <typename T> 151 testing::AssertionResult 152 matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher, 153 BoundNodesCallback *FindResultVerifier) { 154 return matchAndVerifyResultConditionally( 155 Code, AMatcher, FindResultVerifier, true); 156 } 157 158 template <typename T> 159 testing::AssertionResult 160 matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher, 161 BoundNodesCallback *FindResultVerifier) { 162 return matchAndVerifyResultConditionally( 163 Code, AMatcher, FindResultVerifier, false); 164 } 165 166 } // end namespace ast_matchers 167 } // end namespace clang 168 169 #endif // LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H 170