summaryrefslogtreecommitdiffstats
path: root/unittests/ASTMatchers
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/ASTMatchers')
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp273
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h87
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp75
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp60
4 files changed, 444 insertions, 51 deletions
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index bd7a5a6..d2e9ee1 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -375,6 +375,13 @@ TEST(DeclarationMatcher, hasDeclContext) {
"}",
recordDecl(hasDeclContext(namespaceDecl(
hasName("M"), hasDeclContext(namespaceDecl()))))));
+
+ EXPECT_TRUE(matches("class D{};", decl(hasDeclContext(decl()))));
+}
+
+TEST(DeclarationMatcher, LinkageSpecification) {
+ EXPECT_TRUE(matches("extern \"C\" { void foo() {}; }", linkageSpecDecl()));
+ EXPECT_TRUE(notMatches("void foo() {};", linkageSpecDecl()));
}
TEST(ClassTemplate, DoesNotMatchClass) {
@@ -455,6 +462,11 @@ TEST(DeclarationMatcher, MatchAnyOf) {
EXPECT_TRUE(matches("class U {};", XOrYOrZOrUOrV));
EXPECT_TRUE(matches("class V {};", XOrYOrZOrUOrV));
EXPECT_TRUE(notMatches("class A {};", XOrYOrZOrUOrV));
+
+ StatementMatcher MixedTypes = stmt(anyOf(ifStmt(), binaryOperator()));
+ EXPECT_TRUE(matches("int F() { return 1 + 2; }", MixedTypes));
+ EXPECT_TRUE(matches("int F() { if (true) return 1; }", MixedTypes));
+ EXPECT_TRUE(notMatches("int F() { return 1; }", MixedTypes));
}
TEST(DeclarationMatcher, MatchHas) {
@@ -581,6 +593,11 @@ TEST(DeclarationMatcher, MatchNot) {
EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY));
EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };",
ClassXHasNotClassY));
+
+ DeclarationMatcher NamedNotRecord =
+ namedDecl(hasName("Foo"), unless(recordDecl()));
+ EXPECT_TRUE(matches("void Foo(){}", NamedNotRecord));
+ EXPECT_TRUE(notMatches("struct Foo {};", NamedNotRecord));
}
TEST(DeclarationMatcher, HasDescendant) {
@@ -643,6 +660,45 @@ TEST(DeclarationMatcher, HasDescendant) {
"};", ZDescendantClassXDescendantClassY));
}
+TEST(DeclarationMatcher, HasDescendantMemoization) {
+ DeclarationMatcher CannotMemoize =
+ decl(hasDescendant(typeLoc().bind("x")), has(decl()));
+ EXPECT_TRUE(matches("void f() { int i; }", CannotMemoize));
+}
+
+TEST(DeclarationMatcher, HasDescendantMemoizationUsesRestrictKind) {
+ auto Name = hasName("i");
+ auto VD = internal::Matcher<VarDecl>(Name).dynCastTo<Decl>();
+ auto RD = internal::Matcher<RecordDecl>(Name).dynCastTo<Decl>();
+ // Matching VD first should not make a cache hit for RD.
+ EXPECT_TRUE(notMatches("void f() { int i; }",
+ decl(hasDescendant(VD), hasDescendant(RD))));
+ EXPECT_TRUE(notMatches("void f() { int i; }",
+ decl(hasDescendant(RD), hasDescendant(VD))));
+ // Not matching RD first should not make a cache hit for VD either.
+ EXPECT_TRUE(matches("void f() { int i; }",
+ decl(anyOf(hasDescendant(RD), hasDescendant(VD)))));
+}
+
+TEST(DeclarationMatcher, HasAttr) {
+ EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};",
+ decl(hasAttr(clang::attr::WarnUnused))));
+ EXPECT_FALSE(matches("struct X {};",
+ decl(hasAttr(clang::attr::WarnUnused))));
+}
+
+TEST(DeclarationMatcher, MatchCudaDecl) {
+ EXPECT_TRUE(matchesWithCuda("__global__ void f() { }"
+ "void g() { f<<<1, 2>>>(); }",
+ CUDAKernelCallExpr()));
+ EXPECT_TRUE(matchesWithCuda("__attribute__((device)) void f() {}",
+ hasAttr(clang::attr::CUDADevice)));
+ EXPECT_TRUE(notMatchesWithCuda("void f() {}",
+ CUDAKernelCallExpr()));
+ EXPECT_FALSE(notMatchesWithCuda("__attribute__((global)) void f() {}",
+ hasAttr(clang::attr::CUDAGlobal)));
+}
+
// 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.
@@ -681,7 +737,7 @@ public:
EXPECT_EQ("", Name);
}
- virtual bool run(const BoundNodes *Nodes) {
+ virtual bool run(const BoundNodes *Nodes) override {
const BoundNodes::IDToNodeMap &M = Nodes->getMap();
if (Nodes->getNodeAs<T>(Id)) {
++Count;
@@ -703,7 +759,7 @@ public:
return false;
}
- virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) override {
return run(Nodes);
}
@@ -771,6 +827,13 @@ TEST(Has, MatchesChildTypes) {
varDecl(hasName("i"), hasType(qualType(has(pointerType()))))));
}
+TEST(ValueDecl, Matches) {
+ EXPECT_TRUE(matches("enum EnumType { EnumValue };",
+ valueDecl(hasType(asString("enum EnumType")))));
+ EXPECT_TRUE(matches("void FunctionDecl();",
+ valueDecl(hasType(asString("void (void)")))));
+}
+
TEST(Enum, DoesNotMatchClasses) {
EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X"))));
}
@@ -1504,6 +1567,13 @@ TEST(IsExternC, MatchesExternCFunctionDeclarations) {
EXPECT_TRUE(notMatches("void f() {}", functionDecl(isExternC())));
}
+TEST(IsDeleted, MatchesDeletedFunctionDeclarations) {
+ EXPECT_TRUE(
+ notMatches("void Func();", functionDecl(hasName("Func"), isDeleted())));
+ EXPECT_TRUE(matches("void Func() = delete;",
+ functionDecl(hasName("Func"), isDeleted())));
+}
+
TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) {
EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
methodDecl(hasAnyParameter(hasType(recordDecl(hasName("X")))))));
@@ -1602,6 +1672,64 @@ TEST(Matcher, MatchesSpecificArgument) {
1, refersToType(asString("int"))))));
}
+TEST(TemplateArgument, Matches) {
+ EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(templateArgument()))));
+ EXPECT_TRUE(matches(
+ "template<typename T> struct C {}; C<int> c;",
+ templateSpecializationType(hasAnyTemplateArgument(templateArgument()))));
+}
+
+TEST(TemplateArgumentCountIs, Matches) {
+ EXPECT_TRUE(
+ matches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(templateArgumentCountIs(1))));
+ EXPECT_TRUE(
+ notMatches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(templateArgumentCountIs(2))));
+
+ EXPECT_TRUE(matches("template<typename T> struct C {}; C<int> c;",
+ templateSpecializationType(templateArgumentCountIs(1))));
+ EXPECT_TRUE(
+ notMatches("template<typename T> struct C {}; C<int> c;",
+ templateSpecializationType(templateArgumentCountIs(2))));
+}
+
+TEST(IsIntegral, Matches) {
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(isIntegral()))));
+ EXPECT_TRUE(notMatches("template<typename T> struct C {}; C<int> c;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ templateArgument(isIntegral())))));
+}
+
+TEST(RefersToIntegralType, Matches) {
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(refersToIntegralType(
+ asString("int"))))));
+ EXPECT_TRUE(notMatches("template<unsigned T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ refersToIntegralType(asString("int"))))));
+}
+
+TEST(EqualsIntegralValue, Matches) {
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("42")))));
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<-42> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("-42")))));
+ EXPECT_TRUE(matches("template<int T> struct C {}; C<-0042> c;",
+ classTemplateSpecializationDecl(
+ hasAnyTemplateArgument(equalsIntegralValue("-34")))));
+ EXPECT_TRUE(notMatches("template<int T> struct C {}; C<42> c;",
+ classTemplateSpecializationDecl(hasAnyTemplateArgument(
+ equalsIntegralValue("0042")))));
+}
+
TEST(Matcher, MatchesAccessSpecDecls) {
EXPECT_TRUE(matches("class C { public: int i; };", accessSpecDecl()));
EXPECT_TRUE(
@@ -3472,6 +3600,62 @@ TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) {
recordDecl(isTemplateInstantiation())));
}
+TEST(IsInstantiated, MatchesInstantiation) {
+ EXPECT_TRUE(
+ matches("template<typename T> class A { T i; }; class Y { A<int> a; };",
+ recordDecl(isInstantiated())));
+}
+
+TEST(IsInstantiated, NotMatchesDefinition) {
+ EXPECT_TRUE(notMatches("template<typename T> class A { T i; };",
+ recordDecl(isInstantiated())));
+}
+
+TEST(IsInTemplateInstantiation, MatchesInstantiationStmt) {
+ EXPECT_TRUE(matches("template<typename T> struct A { A() { T i; } };"
+ "class Y { A<int> a; }; Y y;",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInTemplateInstantiation, NotMatchesDefinitionStmt) {
+ EXPECT_TRUE(notMatches("template<typename T> struct A { void x() { T i; } };",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInstantiated, MatchesFunctionInstantiation) {
+ EXPECT_TRUE(
+ matches("template<typename T> void A(T t) { T i; } void x() { A(0); }",
+ functionDecl(isInstantiated())));
+}
+
+TEST(IsInstantiated, NotMatchesFunctionDefinition) {
+ EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }",
+ varDecl(isInstantiated())));
+}
+
+TEST(IsInTemplateInstantiation, MatchesFunctionInstantiationStmt) {
+ EXPECT_TRUE(
+ matches("template<typename T> void A(T t) { T i; } void x() { A(0); }",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInTemplateInstantiation, NotMatchesFunctionDefinitionStmt) {
+ EXPECT_TRUE(notMatches("template<typename T> void A(T t) { T i; }",
+ declStmt(isInTemplateInstantiation())));
+}
+
+TEST(IsInTemplateInstantiation, Sharing) {
+ auto Matcher = binaryOperator(unless(isInTemplateInstantiation()));
+ // FIXME: Node sharing is an implementation detail, exposing it is ugly
+ // and makes the matcher behave in non-obvious ways.
+ EXPECT_TRUE(notMatches(
+ "int j; template<typename T> void A(T t) { j += 42; } void x() { A(0); }",
+ Matcher));
+ EXPECT_TRUE(matches(
+ "int j; template<typename T> void A(T t) { j += t; } void x() { A(0); }",
+ Matcher));
+}
+
TEST(IsExplicitTemplateSpecialization,
DoesNotMatchPrimaryTemplate) {
EXPECT_TRUE(notMatches(
@@ -3673,6 +3857,11 @@ TEST(TypeMatching, MatchesTypes) {
EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
}
+TEST(TypeMatching, MatchesVoid) {
+ EXPECT_TRUE(
+ matches("struct S { void func(); };", methodDecl(returns(voidType()))));
+}
+
TEST(TypeMatching, MatchesArrayTypes) {
EXPECT_TRUE(matches("int a[] = {2,3};", arrayType()));
EXPECT_TRUE(matches("int a[42];", arrayType()));
@@ -4163,8 +4352,8 @@ public:
virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
const T *Node = Nodes->getNodeAs<T>(Id);
- return selectFirst<const T>(InnerId,
- match(InnerMatcher, *Node, *Context)) !=nullptr;
+ return selectFirst<T>(InnerId, match(InnerMatcher, *Node, *Context)) !=
+ nullptr;
}
private:
std::string Id;
@@ -4221,7 +4410,7 @@ public:
// Use the original typed pointer to verify we can pass pointers to subtypes
// to equalsNode.
const T *TypedNode = cast<T>(Node);
- return selectFirst<const T>(
+ return selectFirst<T>(
"", match(stmt(hasParent(
stmt(has(stmt(equalsNode(TypedNode)))).bind(""))),
*Node, Context)) != nullptr;
@@ -4230,7 +4419,7 @@ public:
// Use the original typed pointer to verify we can pass pointers to subtypes
// to equalsNode.
const T *TypedNode = cast<T>(Node);
- return selectFirst<const T>(
+ return selectFirst<T>(
"", match(decl(hasParent(
decl(has(decl(equalsNode(TypedNode)))).bind(""))),
*Node, Context)) != nullptr;
@@ -4246,6 +4435,25 @@ TEST(IsEqualTo, MatchesNodesByIdentity) {
new VerifyAncestorHasChildIsEqual<IfStmt>()));
}
+TEST(MatchFinder, CheckProfiling) {
+ MatchFinder::MatchFinderOptions Options;
+ llvm::StringMap<llvm::TimeRecord> Records;
+ Options.CheckProfiling.emplace(Records);
+ MatchFinder Finder(std::move(Options));
+
+ struct NamedCallback : public MatchFinder::MatchCallback {
+ void run(const MatchFinder::MatchResult &Result) override {}
+ StringRef getID() const override { return "MyID"; }
+ } Callback;
+ Finder.addMatcher(decl(), &Callback);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+
+ EXPECT_EQ(1u, Records.size());
+ EXPECT_EQ("MyID", Records.begin()->getKey());
+}
+
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
public:
VerifyStartOfTranslationUnit() : Called(false) {}
@@ -4422,5 +4630,58 @@ TEST(EqualsBoundNodeMatcher, UnlessDescendantsOfAncestorsMatch) {
.bind("data")));
}
+TEST(TypeDefDeclMatcher, Match) {
+ EXPECT_TRUE(matches("typedef int typedefDeclTest;",
+ typedefDecl(hasName("typedefDeclTest"))));
+}
+
+// FIXME: Figure out how to specify paths so the following tests pass on Windows.
+#ifndef LLVM_ON_WIN32
+
+TEST(Matcher, IsExpansionInMainFileMatcher) {
+ EXPECT_TRUE(matches("class X {};",
+ recordDecl(hasName("X"), isExpansionInMainFile())));
+ EXPECT_TRUE(notMatches("", recordDecl(isExpansionInMainFile())));
+ FileContentMappings M;
+ M.push_back(std::make_pair("/other", "class X {};"));
+ EXPECT_TRUE(matchesConditionally("#include <other>\n",
+ recordDecl(isExpansionInMainFile()), false,
+ "-isystem/", M));
+}
+
+TEST(Matcher, IsExpansionInSystemHeader) {
+ FileContentMappings M;
+ M.push_back(std::make_pair("/other", "class X {};"));
+ EXPECT_TRUE(matchesConditionally(
+ "#include \"other\"\n", recordDecl(isExpansionInSystemHeader()), true,
+ "-isystem/", M));
+ EXPECT_TRUE(matchesConditionally("#include \"other\"\n",
+ recordDecl(isExpansionInSystemHeader()),
+ false, "-I/", M));
+ EXPECT_TRUE(notMatches("class X {};",
+ recordDecl(isExpansionInSystemHeader())));
+ EXPECT_TRUE(notMatches("", recordDecl(isExpansionInSystemHeader())));
+}
+
+TEST(Matcher, IsExpansionInFileMatching) {
+ FileContentMappings M;
+ M.push_back(std::make_pair("/foo", "class A {};"));
+ M.push_back(std::make_pair("/bar", "class B {};"));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("b.*"), hasName("B")), true,
+ "-isystem/", M));
+ EXPECT_TRUE(matchesConditionally(
+ "#include <foo>\n"
+ "#include <bar>\n"
+ "class X {};",
+ recordDecl(isExpansionInFileMatching("f.*"), hasName("X")), false,
+ "-isystem/", M));
+}
+
+#endif // LLVM_ON_WIN32
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 2e4ee2c..a2ab9fe 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
-#define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
+#ifndef LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
+#define LLVM_CLANG_UNITTESTS_ASTMATCHERS_ASTMATCHERSTEST_H
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/ASTUnit.h"
@@ -22,6 +22,7 @@ using clang::tooling::buildASTFromCodeWithArgs;
using clang::tooling::newFrontendActionFactory;
using clang::tooling::runToolOnCodeWithArgs;
using clang::tooling::FrontendActionFactory;
+using clang::tooling::FileContentMappings;
class BoundNodesCallback {
public:
@@ -39,7 +40,7 @@ public:
VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
: Verified(Verified), FindResultReviewer(FindResultVerifier) {}
- virtual void run(const MatchFinder::MatchResult &Result) {
+ virtual void run(const MatchFinder::MatchResult &Result) override {
if (FindResultReviewer != nullptr) {
*Verified |= FindResultReviewer->run(&Result.Nodes, Result.Context);
} else {
@@ -58,10 +59,10 @@ private:
};
template <typename T>
-testing::AssertionResult matchesConditionally(const std::string &Code,
- const T &AMatcher,
- bool ExpectMatch,
- llvm::StringRef CompileArg) {
+testing::AssertionResult matchesConditionally(
+ const std::string &Code, const T &AMatcher, bool ExpectMatch,
+ llvm::StringRef CompileArg,
+ const FileContentMappings &VirtualMappedFiles = FileContentMappings()) {
bool Found = false, DynamicFound = false;
MatchFinder Finder;
VerifyMatch VerifyFound(nullptr, &Found);
@@ -73,7 +74,8 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
newFrontendActionFactory(&Finder));
// Some tests use typeof, which is a gnu extension.
std::vector<std::string> Args(1, CompileArg);
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
+ if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, "input.cc",
+ VirtualMappedFiles)) {
return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
}
if (Found != DynamicFound) {
@@ -103,6 +105,75 @@ testing::AssertionResult notMatches(const std::string &Code,
return matchesConditionally(Code, AMatcher, false, "-std=c++11");
}
+// Function based on matchesConditionally with "-x cuda" argument added and
+// small CUDA header prepended to the code string.
+template <typename T>
+testing::AssertionResult matchesConditionallyWithCuda(
+ const std::string &Code, const T &AMatcher, bool ExpectMatch,
+ llvm::StringRef CompileArg) {
+ const std::string CudaHeader =
+ "typedef unsigned int size_t;\n"
+ "#define __constant__ __attribute__((constant))\n"
+ "#define __device__ __attribute__((device))\n"
+ "#define __global__ __attribute__((global))\n"
+ "#define __host__ __attribute__((host))\n"
+ "#define __shared__ __attribute__((shared))\n"
+ "struct dim3 {"
+ " unsigned x, y, z;"
+ " __host__ __device__ dim3(unsigned x, unsigned y = 1, unsigned z = 1)"
+ " : x(x), y(y), z(z) {}"
+ "};"
+ "typedef struct cudaStream *cudaStream_t;"
+ "int cudaConfigureCall(dim3 gridSize, dim3 blockSize,"
+ " size_t sharedSize = 0,"
+ " cudaStream_t stream = 0);";
+
+ bool Found = false, DynamicFound = false;
+ MatchFinder Finder;
+ VerifyMatch VerifyFound(nullptr, &Found);
+ Finder.addMatcher(AMatcher, &VerifyFound);
+ VerifyMatch VerifyDynamicFound(nullptr, &DynamicFound);
+ if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound))
+ 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(CompileArg);
+ if (!runToolOnCodeWithArgs(Factory->create(),
+ CudaHeader + Code, Args)) {
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ }
+ if (Found != DynamicFound) {
+ return testing::AssertionFailure() << "Dynamic match result ("
+ << DynamicFound
+ << ") does not match static result ("
+ << Found << ")";
+ }
+ if (!Found && ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Could not find match in \"" << Code << "\"";
+ } else if (Found && !ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Found unexpected match in \"" << Code << "\"";
+ }
+ return testing::AssertionSuccess();
+}
+
+template <typename T>
+testing::AssertionResult matchesWithCuda(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionallyWithCuda(Code, AMatcher, true, "-std=c++11");
+}
+
+template <typename T>
+testing::AssertionResult notMatchesWithCuda(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionallyWithCuda(Code, AMatcher, false, "-std=c++11");
+}
+
template <typename T>
testing::AssertionResult
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 4e3239f..2a9a61b 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -26,9 +26,12 @@ public:
virtual ~MockSema() {}
uint64_t expectMatcher(StringRef MatcherName) {
- ast_matchers::internal::Matcher<Stmt> M = stmt();
+ // Optimizations on the matcher framework make simple matchers like
+ // 'stmt()' to be all the same matcher.
+ // Use a more complex expression to prevent that.
+ ast_matchers::internal::Matcher<Stmt> M = stmt(stmt(), stmt());
ExpectedMatchers.insert(std::make_pair(MatcherName, M));
- return M.getID();
+ return M.getID().second;
}
void parse(StringRef Code) {
@@ -125,8 +128,12 @@ TEST(ParserTest, ParseMatcher) {
EXPECT_EQ("", Sema.Errors[i]);
}
+ EXPECT_NE(ExpectedFoo, ExpectedBar);
+ EXPECT_NE(ExpectedFoo, ExpectedBaz);
+ EXPECT_NE(ExpectedBar, ExpectedBaz);
+
EXPECT_EQ(1ULL, Sema.Values.size());
- EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID());
+ EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID().second);
EXPECT_EQ(3ULL, Sema.Matchers.size());
const MockSema::MatcherInfo Bar = Sema.Matchers[0];
@@ -145,13 +152,21 @@ TEST(ParserTest, ParseMatcher) {
EXPECT_EQ("Foo", Foo.MatcherName);
EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
EXPECT_EQ(2ULL, Foo.Args.size());
- EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID());
- EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID());
+ EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID().second);
+ EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID().second);
EXPECT_EQ("Yo!", Foo.BoundID);
}
using ast_matchers::internal::Matcher;
+Parser::NamedValueMap getTestNamedValues() {
+ Parser::NamedValueMap Values;
+ Values["nameX"] = std::string("x");
+ Values["hasParamA"] =
+ VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
+ return Values;
+}
+
TEST(ParserTest, FullParserTest) {
Diagnostics Error;
llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
@@ -174,21 +189,11 @@ TEST(ParserTest, FullParserTest) {
EXPECT_FALSE(matches("void f(int x, int a);", M));
// Test named values.
- struct NamedSema : public Parser::RegistrySema {
- public:
- virtual VariantValue getNamedValue(StringRef Name) {
- if (Name == "nameX")
- return std::string("x");
- if (Name == "param0")
- return VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
- return VariantValue();
- }
- };
- NamedSema Sema;
+ auto NamedValues = getTestNamedValues();
llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues(
Parser::parseMatcherExpression(
- "functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema,
- &Error));
+ "functionDecl(hasParamA, hasParameter(1, hasName(nameX)))",
+ nullptr, &NamedValues, &Error));
EXPECT_EQ("", Error.toStringFull());
M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>();
@@ -270,7 +275,7 @@ TEST(ParserTest, OverloadErrors) {
ParseWithError("callee(\"A\")"));
}
-TEST(ParserTest, Completion) {
+TEST(ParserTest, CompletionRegistry) {
std::vector<MatcherCompletion> Comps =
Parser::completeExpression("while", 5);
ASSERT_EQ(1u, Comps.size());
@@ -284,6 +289,38 @@ TEST(ParserTest, Completion) {
EXPECT_EQ("bind", Comps[0].MatcherDecl);
}
+TEST(ParserTest, CompletionNamedValues) {
+ // Can complete non-matcher types.
+ auto NamedValues = getTestNamedValues();
+ StringRef Code = "functionDecl(hasName(";
+ std::vector<MatcherCompletion> Comps =
+ Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
+ ASSERT_EQ(1u, Comps.size());
+ EXPECT_EQ("nameX", Comps[0].TypedText);
+ EXPECT_EQ("String nameX", Comps[0].MatcherDecl);
+
+ // Can complete if there are names in the expression.
+ Code = "methodDecl(hasName(nameX), ";
+ Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
+ EXPECT_LT(0u, Comps.size());
+
+ // Can complete names and registry together.
+ Code = "methodDecl(hasP";
+ Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues);
+ ASSERT_EQ(3u, Comps.size());
+ EXPECT_EQ("aramA", Comps[0].TypedText);
+ EXPECT_EQ("Matcher<FunctionDecl> hasParamA", Comps[0].MatcherDecl);
+
+ EXPECT_EQ("arameter(", Comps[1].TypedText);
+ EXPECT_EQ(
+ "Matcher<FunctionDecl> hasParameter(unsigned, Matcher<ParmVarDecl>)",
+ Comps[1].MatcherDecl);
+
+ EXPECT_EQ("arent(", Comps[2].TypedText);
+ EXPECT_EQ("Matcher<Decl> hasParent(Matcher<Decl|Stmt>)",
+ Comps[2].MatcherDecl);
+}
+
} // end anonymous namespace
} // end namespace dynamic
} // end namespace ast_matchers
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index e659b3a..5483f8f 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -82,8 +82,9 @@ public:
typedef std::vector<MatcherCompletion> CompVector;
CompVector getCompletions() {
- return Registry::getCompletions(
- ArrayRef<std::pair<MatcherCtor, unsigned> >());
+ std::vector<std::pair<MatcherCtor, unsigned> > Context;
+ return Registry::getMatcherCompletions(
+ Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
@@ -92,7 +93,8 @@ public:
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo1));
- return Registry::getCompletions(Context);
+ return Registry::getMatcherCompletions(
+ Registry::getAcceptedCompletionTypes(Context));
}
CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
@@ -106,18 +108,16 @@ public:
if (!Ctor)
return CompVector();
Context.push_back(std::make_pair(*Ctor, ArgNo2));
- return Registry::getCompletions(Context);
+ return Registry::getMatcherCompletions(
+ Registry::getAcceptedCompletionTypes(Context));
}
bool hasCompletion(const CompVector &Comps, StringRef TypedText,
- StringRef MatcherDecl = StringRef(),
- unsigned *Index = nullptr) {
+ StringRef MatcherDecl = StringRef()) {
for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
++I) {
if (I->TypedText == TypedText &&
(MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
- if (Index)
- *Index = I - Comps.begin();
return true;
}
}
@@ -347,7 +347,7 @@ TEST_F(RegistryTest, VariadicOp) {
"anyOf",
constructMatcher("recordDecl",
constructMatcher("hasName", std::string("Foo"))),
- constructMatcher("namedDecl",
+ constructMatcher("functionDecl",
constructMatcher("hasName", std::string("foo"))))
.getTypedMatcher<Decl>();
@@ -380,6 +380,13 @@ TEST_F(RegistryTest, VariadicOp) {
EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
+
+ D = constructMatcher(
+ "namedDecl", constructMatcher("hasName", std::string("Foo")),
+ constructMatcher("unless", constructMatcher("recordDecl")))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("void Foo(){}", D));
+ EXPECT_TRUE(notMatches("struct Foo {};", D));
}
TEST_F(RegistryTest, Errors) {
@@ -438,24 +445,27 @@ TEST_F(RegistryTest, Errors) {
TEST_F(RegistryTest, Completion) {
CompVector Comps = getCompletions();
+ // Overloaded
EXPECT_TRUE(hasCompletion(
Comps, "hasParent(", "Matcher<Decl|Stmt> hasParent(Matcher<Decl|Stmt>)"));
+ // Variadic.
EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
"Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
+ // Polymorphic.
+ EXPECT_TRUE(hasCompletion(
+ Comps, "hasDescendant(",
+ "Matcher<NestedNameSpecifier|NestedNameSpecifierLoc|QualType|...> "
+ "hasDescendant(Matcher<CXXCtorInitializer|NestedNameSpecifier|"
+ "NestedNameSpecifierLoc|...>)"));
CompVector WhileComps = getCompletions("whileStmt", 0);
- unsigned HasBodyIndex, HasParentIndex, AllOfIndex;
EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
- "Matcher<WhileStmt> hasBody(Matcher<Stmt>)",
- &HasBodyIndex));
+ "Matcher<WhileStmt> hasBody(Matcher<Stmt>)"));
EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(",
- "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)",
- &HasParentIndex));
- EXPECT_TRUE(hasCompletion(WhileComps, "allOf(",
- "Matcher<T> allOf(Matcher<T>...)", &AllOfIndex));
- EXPECT_GT(HasParentIndex, HasBodyIndex);
- EXPECT_GT(AllOfIndex, HasParentIndex);
+ "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)"));
+ EXPECT_TRUE(
+ hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)"));
EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
@@ -475,6 +485,20 @@ TEST_F(RegistryTest, Completion) {
hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
"Matcher<NamedDecl> hasName(string)"));
+
+ // Heterogeneous overloads.
+ Comps = getCompletions("classTemplateSpecializationDecl", 0);
+ EXPECT_TRUE(hasCompletion(
+ Comps, "isSameOrDerivedFrom(",
+ "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
+}
+
+TEST_F(RegistryTest, HasArgs) {
+ Matcher<Decl> Value = constructMatcher(
+ "decl", constructMatcher("hasAttr", std::string("attr::WarnUnused")))
+ .getTypedMatcher<Decl>();
+ EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value));
+ EXPECT_FALSE(matches("struct X {};", Value));
}
} // end anonymous namespace
OpenPOWER on IntegriCloud