diff options
Diffstat (limited to 'unittests/ASTMatchers/ASTMatchersTest.h')
-rw-r--r-- | unittests/ASTMatchers/ASTMatchersTest.h | 144 |
1 files changed, 114 insertions, 30 deletions
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h index 68824e61ac69..4b3387c0ba72 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.h +++ b/unittests/ASTMatchers/ASTMatchersTest.h @@ -37,8 +37,8 @@ public: // If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called. class VerifyMatch : public MatchFinder::MatchCallback { public: - VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified) - : Verified(Verified), FindResultReviewer(FindResultVerifier) {} + VerifyMatch(std::unique_ptr<BoundNodesCallback> FindResultVerifier, bool *Verified) + : Verified(Verified), FindResultReviewer(std::move(FindResultVerifier)) {} void run(const MatchFinder::MatchResult &Result) override { if (FindResultReviewer != nullptr) { @@ -55,7 +55,7 @@ public: private: bool *const Verified; - BoundNodesCallback *const FindResultReviewer; + const std::unique_ptr<BoundNodesCallback> FindResultReviewer; }; template <typename T> @@ -73,15 +73,19 @@ testing::AssertionResult matchesConditionally( return testing::AssertionFailure() << "Could not add dynamic matcher"; std::unique_ptr<FrontendActionFactory> Factory( newFrontendActionFactory(&Finder)); - // Some tests use typeof, which is a gnu extension. - std::vector<std::string> Args; - Args.push_back(CompileArg); - // Some tests need rtti/exceptions on - Args.push_back("-frtti"); - Args.push_back("-fexceptions"); - if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, Filename, - std::make_shared<PCHContainerOperations>(), - VirtualMappedFiles)) { + // Some tests need rtti/exceptions on. Use an unknown-unknown triple so we + // don't instantiate the full system toolchain. On Linux, instantiating the + // toolchain involves stat'ing large portions of /usr/lib, and this slows down + // not only this test, but all other tests, via contention in the kernel. + // + // FIXME: This is a hack to work around the fact that there's no way to do the + // equivalent of runToolOnCodeWithArgs without instantiating a full Driver. + // We should consider having a function, at least for tests, that invokes cc1. + std::vector<std::string> Args = {CompileArg, "-frtti", "-fexceptions", + "-target", "i386-unknown-unknown"}; + if (!runToolOnCodeWithArgs( + Factory->create(), Code, Args, Filename, "clang-tool", + std::make_shared<PCHContainerOperations>(), VirtualMappedFiles)) { return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; } if (Found != DynamicFound) { @@ -126,6 +130,13 @@ testing::AssertionResult matchesC(const std::string &Code, const T &AMatcher) { } template <typename T> +testing::AssertionResult matchesC99(const std::string &Code, + const T &AMatcher) { + return matchesConditionally(Code, AMatcher, true, "-std=c99", + FileContentMappings(), "input.c"); +} + +template <typename T> testing::AssertionResult notMatchesC(const std::string &Code, const T &AMatcher) { return matchesConditionally(Code, AMatcher, false, "", FileContentMappings(), @@ -173,13 +184,12 @@ testing::AssertionResult matchesConditionallyWithCuda( return testing::AssertionFailure() << "Could not add dynamic matcher"; std::unique_ptr<FrontendActionFactory> Factory( newFrontendActionFactory(&Finder)); - // Some tests use typeof, which is a gnu extension. - std::vector<std::string> Args; - Args.push_back("-xcuda"); - Args.push_back("-fno-ms-extensions"); - Args.push_back("--cuda-host-only"); - Args.push_back("-nocudainc"); - Args.push_back(CompileArg); + // Some tests use typeof, which is a gnu extension. Using an explicit + // unknown-unknown triple is good for a large speedup, because it lets us + // avoid constructing a full system triple. + std::vector<std::string> Args = { + "-xcuda", "-fno-ms-extensions", "--cuda-host-only", "-nocudainc", + "-target", "nvptx64-unknown-unknown", CompileArg}; if (!runToolOnCodeWithArgs(Factory->create(), CudaHeader + Code, Args)) { return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; @@ -215,17 +225,19 @@ testing::AssertionResult notMatchesWithCuda(const std::string &Code, template <typename T> testing::AssertionResult matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher, - BoundNodesCallback *FindResultVerifier, + std::unique_ptr<BoundNodesCallback> FindResultVerifier, bool ExpectResult) { - std::unique_ptr<BoundNodesCallback> ScopedVerifier(FindResultVerifier); bool VerifiedResult = false; MatchFinder Finder; - VerifyMatch VerifyVerifiedResult(FindResultVerifier, &VerifiedResult); + VerifyMatch VerifyVerifiedResult(std::move(FindResultVerifier), &VerifiedResult); Finder.addMatcher(AMatcher, &VerifyVerifiedResult); std::unique_ptr<FrontendActionFactory> Factory( newFrontendActionFactory(&Finder)); - // Some tests use typeof, which is a gnu extension. - std::vector<std::string> Args(1, "-std=gnu++98"); + // Some tests use typeof, which is a gnu extension. Using an explicit + // unknown-unknown triple is good for a large speedup, because it lets us + // avoid constructing a full system triple. + std::vector<std::string> Args = {"-std=gnu++98", "-target", + "i386-unknown-unknown"}; if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) { return testing::AssertionFailure() << "Parsing error in \"" << Code << "\""; } @@ -259,20 +271,92 @@ matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher, template <typename T> testing::AssertionResult matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher, - BoundNodesCallback *FindResultVerifier) { + std::unique_ptr<BoundNodesCallback> FindResultVerifier) { return matchAndVerifyResultConditionally( - Code, AMatcher, FindResultVerifier, true); + Code, AMatcher, std::move(FindResultVerifier), true); } template <typename T> testing::AssertionResult matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher, - BoundNodesCallback *FindResultVerifier) { + std::unique_ptr<BoundNodesCallback> FindResultVerifier) { return matchAndVerifyResultConditionally( - Code, AMatcher, FindResultVerifier, false); + Code, AMatcher, std::move(FindResultVerifier), false); } -} // end namespace ast_matchers -} // end namespace clang +// Implements a run method that returns whether BoundNodes contains a +// Decl bound to Id that can be dynamically cast to T. +// Optionally checks that the check succeeded a specific number of times. +template <typename T> +class VerifyIdIsBoundTo : public BoundNodesCallback { +public: + // Create an object that checks that a node of type \c T was bound to \c Id. + // Does not check for a certain number of matches. + explicit VerifyIdIsBoundTo(llvm::StringRef Id) + : Id(Id), ExpectedCount(-1), Count(0) {} + + // Create an object that checks that a node of type \c T was bound to \c Id. + // Checks that there were exactly \c ExpectedCount matches. + VerifyIdIsBoundTo(llvm::StringRef Id, int ExpectedCount) + : Id(Id), ExpectedCount(ExpectedCount), Count(0) {} + + // Create an object that checks that a node of type \c T was bound to \c Id. + // Checks that there was exactly one match with the name \c ExpectedName. + // Note that \c T must be a NamedDecl for this to work. + VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName, + int ExpectedCount = 1) + : Id(Id), ExpectedCount(ExpectedCount), Count(0), + ExpectedName(ExpectedName) {} + + void onEndOfTranslationUnit() override { + if (ExpectedCount != -1) + EXPECT_EQ(ExpectedCount, Count); + if (!ExpectedName.empty()) + EXPECT_EQ(ExpectedName, Name); + Count = 0; + Name.clear(); + } + + ~VerifyIdIsBoundTo() override { + EXPECT_EQ(0, Count); + EXPECT_EQ("", Name); + } + + bool run(const BoundNodes *Nodes) override { + const BoundNodes::IDToNodeMap &M = Nodes->getMap(); + if (Nodes->getNodeAs<T>(Id)) { + ++Count; + if (const NamedDecl *Named = Nodes->getNodeAs<NamedDecl>(Id)) { + Name = Named->getNameAsString(); + } else if (const NestedNameSpecifier *NNS = + Nodes->getNodeAs<NestedNameSpecifier>(Id)) { + llvm::raw_string_ostream OS(Name); + NNS->print(OS, PrintingPolicy(LangOptions())); + } + BoundNodes::IDToNodeMap::const_iterator I = M.find(Id); + EXPECT_NE(M.end(), I); + if (I != M.end()) + EXPECT_EQ(Nodes->getNodeAs<T>(Id), I->second.get<T>()); + return true; + } + EXPECT_TRUE(M.count(Id) == 0 || + M.find(Id)->second.template get<T>() == nullptr); + return false; + } + + bool run(const BoundNodes *Nodes, ASTContext *Context) override { + return run(Nodes); + } + +private: + const std::string Id; + const int ExpectedCount; + int Count; + const std::string ExpectedName; + std::string Name; +}; + +} // namespace ast_matchers +} // namespace clang #endif // LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H |