summaryrefslogtreecommitdiff
path: root/unittests/ASTMatchers/ASTMatchersTest.h
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/ASTMatchers/ASTMatchersTest.h')
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h144
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