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 18namespace clang { 19namespace ast_matchers { 20 21using clang::tooling::buildASTFromCodeWithArgs; 22using clang::tooling::newFrontendActionFactory; 23using clang::tooling::runToolOnCodeWithArgs; 24using clang::tooling::FrontendActionFactory; 25 26class BoundNodesCallback { 27public: 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. 37class VerifyMatch : public MatchFinder::MatchCallback { 38public: 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 55private: 56 bool *const Verified; 57 BoundNodesCallback *const FindResultReviewer; 58}; 59 60template <typename T> 61testing::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 95template <typename T> 96testing::AssertionResult matches(const std::string &Code, const T &AMatcher) { 97 return matchesConditionally(Code, AMatcher, true, "-std=c++11"); 98} 99 100template <typename T> 101testing::AssertionResult notMatches(const std::string &Code, 102 const T &AMatcher) { 103 return matchesConditionally(Code, AMatcher, false, "-std=c++11"); 104} 105 106template <typename T> 107testing::AssertionResult 108matchAndVerifyResultConditionally(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). 150template <typename T> 151testing::AssertionResult 152matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher, 153 BoundNodesCallback *FindResultVerifier) { 154 return matchAndVerifyResultConditionally( 155 Code, AMatcher, FindResultVerifier, true); 156} 157 158template <typename T> 159testing::AssertionResult 160matchAndVerifyResultFalse(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