summaryrefslogtreecommitdiffstats
path: root/unittests/ASTMatchers/ASTMatchersTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/ASTMatchers/ASTMatchersTest.cpp')
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp273
1 files changed, 267 insertions, 6 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
OpenPOWER on IntegriCloud