diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
| commit | 676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63 (patch) | |
| tree | 02a1ac369cb734d0abfa5000dd86e5b7797e6a74 /unittests/ASTMatchers | |
| parent | c7e70c433efc6953dc3888b9fbf9f3512d7da2b0 (diff) | |
Notes
Diffstat (limited to 'unittests/ASTMatchers')
| -rw-r--r-- | unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp | 99 | ||||
| -rw-r--r-- | unittests/ASTMatchers/ASTMatchersNodeTest.cpp | 70 | ||||
| -rw-r--r-- | unittests/ASTMatchers/ASTMatchersTraversalTest.cpp | 67 | ||||
| -rw-r--r-- | unittests/ASTMatchers/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | unittests/ASTMatchers/Dynamic/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | unittests/ASTMatchers/Dynamic/ParserTest.cpp | 57 | ||||
| -rw-r--r-- | unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 3 |
7 files changed, 285 insertions, 13 deletions
diff --git a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index 1e7b10e99e71..fb17d100c518 100644 --- a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -667,6 +667,14 @@ TEST(Matcher, VarDecl_Storage) { EXPECT_TRUE(matches("void f() { static int X; }", M)); } +TEST(Matcher, VarDecl_IsStaticLocal) { + auto M = varDecl(isStaticLocal()); + EXPECT_TRUE(matches("void f() { static int X; }", M)); + EXPECT_TRUE(notMatches("static int X;", M)); + EXPECT_TRUE(notMatches("void f() { int X; }", M)); + EXPECT_TRUE(notMatches("int X;", M)); +} + TEST(Matcher, VarDecl_StorageDuration) { std::string T = "void f() { int x; static int y; } int a;static int b;extern int c;"; @@ -765,6 +773,11 @@ TEST(IsArrow, MatchesMemberVariablesViaArrow) { memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };", memberExpr(isArrow()))); + EXPECT_TRUE(matches("template <class T> class Y { void x() { this->m; } };", + cxxDependentScopeMemberExpr(isArrow()))); + EXPECT_TRUE( + notMatches("template <class T> class Y { void x() { (*this).m; } };", + cxxDependentScopeMemberExpr(isArrow()))); } TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) { @@ -783,6 +796,14 @@ TEST(IsArrow, MatchesMemberCallsViaArrow) { memberExpr(isArrow()))); EXPECT_TRUE(notMatches("class Y { void x() { Y y; y.x(); } };", memberExpr(isArrow()))); + EXPECT_TRUE( + matches("class Y { template <class T> void x() { this->x<T>(); } };", + unresolvedMemberExpr(isArrow()))); + EXPECT_TRUE(matches("class Y { template <class T> void x() { x<T>(); } };", + unresolvedMemberExpr(isArrow()))); + EXPECT_TRUE( + notMatches("class Y { template <class T> void x() { (*this).x<T>(); } };", + unresolvedMemberExpr(isArrow()))); } TEST(ConversionDeclaration, IsExplicit) { @@ -1365,6 +1386,10 @@ TEST(ObjCIvarRefExprMatcher, IvarExpr) { hasDeclaration(namedDecl(hasName("y")))))); } +TEST(BlockExprMatcher, BlockExpr) { + EXPECT_TRUE(matchesObjC("void f() { ^{}(); }", blockExpr())); +} + TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) { EXPECT_TRUE(matches("void f() { }", compoundStmt(statementCountIs(0)))); @@ -1517,6 +1542,26 @@ TEST(HasObjectExpression, MatchesBaseOfVariable) { "struct X { int m; }; void f(X* x) { x->m; }", memberExpr(hasObjectExpression( hasType(pointsTo(recordDecl(hasName("X")))))))); + EXPECT_TRUE(matches("template <class T> struct X { void f() { T t; t.m; } };", + cxxDependentScopeMemberExpr(hasObjectExpression( + declRefExpr(to(namedDecl(hasName("t")))))))); + EXPECT_TRUE( + matches("template <class T> struct X { void f() { T t; t->m; } };", + cxxDependentScopeMemberExpr(hasObjectExpression( + declRefExpr(to(namedDecl(hasName("t")))))))); +} + +TEST(HasObjectExpression, MatchesBaseOfMemberFunc) { + EXPECT_TRUE(matches( + "struct X { void f(); }; void g(X x) { x.f(); }", + memberExpr(hasObjectExpression(hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches("struct X { template <class T> void f(); };" + "template <class T> void g(X x) { x.f<T>(); }", + unresolvedMemberExpr(hasObjectExpression( + hasType(recordDecl(hasName("X"))))))); + EXPECT_TRUE(matches("template <class T> void f(T t) { t.g(); }", + cxxDependentScopeMemberExpr(hasObjectExpression( + declRefExpr(to(namedDecl(hasName("t")))))))); } TEST(HasObjectExpression, @@ -1748,6 +1793,48 @@ TEST(IsInTemplateInstantiation, Sharing) { Matcher)); } +TEST(IsInstantiationDependent, MatchesNonValueTypeDependent) { + EXPECT_TRUE(matches( + "template<typename T> void f() { (void) sizeof(sizeof(T() + T())); }", + expr(isInstantiationDependent()))); +} + +TEST(IsInstantiationDependent, MatchesValueDependent) { + EXPECT_TRUE(matches("template<int T> int f() { return T; }", + expr(isInstantiationDependent()))); +} + +TEST(IsInstantiationDependent, MatchesTypeDependent) { + EXPECT_TRUE(matches("template<typename T> T f() { return T(); }", + expr(isInstantiationDependent()))); +} + +TEST(IsTypeDependent, MatchesTypeDependent) { + EXPECT_TRUE(matches("template<typename T> T f() { return T(); }", + expr(isTypeDependent()))); +} + +TEST(IsTypeDependent, NotMatchesValueDependent) { + EXPECT_TRUE(notMatches("template<int T> int f() { return T; }", + expr(isTypeDependent()))); +} + +TEST(IsValueDependent, MatchesValueDependent) { + EXPECT_TRUE(matches("template<int T> int f() { return T; }", + expr(isValueDependent()))); +} + +TEST(IsValueDependent, MatchesTypeDependent) { + EXPECT_TRUE(matches("template<typename T> T f() { return T(); }", + expr(isValueDependent()))); +} + +TEST(IsValueDependent, MatchesInstantiationDependent) { + EXPECT_TRUE(matches( + "template<typename T> void f() { (void) sizeof(sizeof(T() + T())); }", + expr(isValueDependent()))); +} + TEST(IsExplicitTemplateSpecialization, DoesNotMatchPrimaryTemplate) { EXPECT_TRUE(notMatches( @@ -2168,6 +2255,18 @@ TEST(IsAssignmentOperator, Basic) { notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator)); } +TEST(HasInit, Basic) { + EXPECT_TRUE( + matches("int x{0};", + initListExpr(hasInit(0, expr())))); + EXPECT_FALSE( + matches("int x{0};", + initListExpr(hasInit(1, expr())))); + EXPECT_FALSE( + matches("int x;", + initListExpr(hasInit(0, expr())))); +} + TEST(Matcher, isMain) { EXPECT_TRUE( matches("int main() {}", functionDecl(isMain()))); diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index e521940983b2..1bd4e09e7761 100644 --- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -27,7 +27,7 @@ TEST(Finder, DynamicOnlyAcceptsSomeMatchers) { nullptr)); // Do not accept non-toplevel matchers. - EXPECT_FALSE(Finder.addDynamicMatcher(isArrow(), nullptr)); + EXPECT_FALSE(Finder.addDynamicMatcher(isMain(), nullptr)); EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), nullptr)); } @@ -199,6 +199,40 @@ TEST(Matcher, UnresolvedLookupExpr) { "-fno-delayed-template-parsing")); } +TEST(Matcher, ADLCall) { + StatementMatcher ADLMatch = callExpr(usesADL()); + StatementMatcher ADLMatchOper = cxxOperatorCallExpr(usesADL()); + auto NS_Str = R"cpp( + namespace NS { + struct X {}; + void f(X); + void operator+(X, X); + } + struct MyX {}; + void f(...); + void operator+(MyX, MyX); +)cpp"; + + auto MkStr = [&](std::string Body) -> std::string { + std::string S = NS_Str; + S += "void test_fn() { " + Body + " }"; + return S; + }; + + EXPECT_TRUE(matches(MkStr("NS::X x; f(x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::f(x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("MyX x; f(x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("NS::X x; using NS::f; f(x);"), ADLMatch)); + + // Operator call expressions + EXPECT_TRUE(matches(MkStr("NS::X x; x + x;"), ADLMatch)); + EXPECT_TRUE(matches(MkStr("NS::X x; x + x;"), ADLMatchOper)); + EXPECT_TRUE(notMatches(MkStr("MyX x; x + x;"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("MyX x; x + x;"), ADLMatchOper)); + EXPECT_TRUE(matches(MkStr("NS::X x; operator+(x, x);"), ADLMatch)); + EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::operator+(x, x);"), ADLMatch)); +} + TEST(Matcher, Call) { // FIXME: Do we want to overload Call() to directly take // Matcher<Decl>, too? @@ -422,10 +456,17 @@ TEST(UnaryExprOrTypeTraitExpr, MatchesSizeOfAndAlignOf) { TEST(MemberExpression, DoesNotMatchClasses) { EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpr())); + EXPECT_TRUE(notMatches("class Y { void x() {} };", unresolvedMemberExpr())); + EXPECT_TRUE( + notMatches("class Y { void x() {} };", cxxDependentScopeMemberExpr())); } TEST(MemberExpression, MatchesMemberFunctionCall) { EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpr())); + EXPECT_TRUE(matches("class Y { template <class T> void x() { x<T>(); } };", + unresolvedMemberExpr())); + EXPECT_TRUE(matches("template <class T> void x() { T t; t.f(); }", + cxxDependentScopeMemberExpr())); } TEST(MemberExpression, MatchesVariable) { @@ -435,6 +476,13 @@ TEST(MemberExpression, MatchesVariable) { matches("class Y { void x() { y; } int y; };", memberExpr())); EXPECT_TRUE( matches("class Y { void x() { Y y; y.y; } int y; };", memberExpr())); + EXPECT_TRUE(matches("template <class T>" + "class X : T { void f() { this->T::v; } };", + cxxDependentScopeMemberExpr())); + EXPECT_TRUE(matches("template <class T> class X : T { void f() { T::v; } };", + cxxDependentScopeMemberExpr())); + EXPECT_TRUE(matches("template <class T> void x() { T t; t.v; }", + cxxDependentScopeMemberExpr())); } TEST(MemberExpression, MatchesStaticVariable) { @@ -746,23 +794,23 @@ TEST(Matcher, Initializers) { has( designatedInitExpr( designatorCountIs(2), - has(floatLiteral( + hasDescendant(floatLiteral( equals(1.0))), - has(integerLiteral( + hasDescendant(integerLiteral( equals(2))))), has( designatedInitExpr( designatorCountIs(2), - has(floatLiteral( + hasDescendant(floatLiteral( equals(2.0))), - has(integerLiteral( + hasDescendant(integerLiteral( equals(2))))), has( designatedInitExpr( designatorCountIs(2), - has(floatLiteral( + hasDescendant(floatLiteral( equals(1.0))), - has(integerLiteral( + hasDescendant(integerLiteral( equals(0))))) ))))); } @@ -1133,6 +1181,14 @@ TEST(ParenExpression, SimpleCases) { parenExpr())); } +TEST(ParenExpression, IgnoringParens) { + EXPECT_FALSE(matches("const char* str = (\"my-string\");", + implicitCastExpr(hasSourceExpression(stringLiteral())))); + EXPECT_TRUE(matches( + "const char* str = (\"my-string\");", + implicitCastExpr(hasSourceExpression(ignoringParens(stringLiteral()))))); +} + TEST(TypeMatching, MatchesTypes) { EXPECT_TRUE(matches("struct S {};", qualType().bind("loc"))); } diff --git a/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index 3b8f362101a6..5f6ecc0d0b8b 100644 --- a/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -406,9 +406,22 @@ TEST(Matcher, AnyArgument) { auto HasArgumentY = hasAnyArgument( ignoringParenImpCasts(declRefExpr(to(varDecl(hasName("y")))))); StatementMatcher CallArgumentY = callExpr(HasArgumentY); + StatementMatcher CtorArgumentY = cxxConstructExpr(HasArgumentY); + StatementMatcher UnresolvedCtorArgumentY = + cxxUnresolvedConstructExpr(HasArgumentY); StatementMatcher ObjCCallArgumentY = objcMessageExpr(HasArgumentY); EXPECT_TRUE(matches("void x(int, int) { int y; x(1, y); }", CallArgumentY)); EXPECT_TRUE(matches("void x(int, int) { int y; x(y, 42); }", CallArgumentY)); + EXPECT_TRUE(matches("struct Y { Y(int, int); };" + "void x() { int y; (void)Y(1, y); }", + CtorArgumentY)); + EXPECT_TRUE(matches("struct Y { Y(int, int); };" + "void x() { int y; (void)Y(y, 42); }", + CtorArgumentY)); + EXPECT_TRUE(matches("template <class Y> void x() { int y; (void)Y(1, y); }", + UnresolvedCtorArgumentY)); + EXPECT_TRUE(matches("template <class Y> void x() { int y; (void)Y(y, 42); }", + UnresolvedCtorArgumentY)); EXPECT_TRUE(matchesObjC("@interface I -(void)f:(int) y; @end " "void x(I* i) { int y; [i f:y]; }", ObjCCallArgumentY)); @@ -416,6 +429,12 @@ TEST(Matcher, AnyArgument) { "void x(I* i) { int z; [i f:z]; }", ObjCCallArgumentY)); EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY)); + EXPECT_TRUE(notMatches("struct Y { Y(int, int); };" + "void x() { int y; (void)Y(1, 2); }", + CtorArgumentY)); + EXPECT_TRUE(notMatches("template <class Y>" + "void x() { int y; (void)Y(1, 2); }", + UnresolvedCtorArgumentY)); StatementMatcher ImplicitCastedArgument = callExpr( hasAnyArgument(implicitCastExpr())); @@ -1302,6 +1321,45 @@ TEST(IgnoringImplicit, MatchesImplicit) { varDecl(has(ignoringImplicit(cxxConstructExpr()))))); } +TEST(IgnoringImplicit, MatchesNestedImplicit) { + StringRef Code = R"( + +struct OtherType; + +struct SomeType +{ + SomeType() {} + SomeType(const OtherType&) {} + SomeType& operator=(OtherType const&) { return *this; } +}; + +struct OtherType +{ + OtherType() {} + ~OtherType() {} +}; + +OtherType something() +{ + return {}; +} + +int main() +{ + SomeType i = something(); +} +)"; + EXPECT_TRUE(matches(Code, varDecl( + hasName("i"), + hasInitializer(exprWithCleanups(has( + cxxConstructExpr(has(expr(ignoringImplicit(cxxConstructExpr( + has(expr(ignoringImplicit(callExpr()))) + ))))) + ))) + ) + )); +} + TEST(IgnoringImplicit, DoesNotMatchIncorrectly) { EXPECT_TRUE( notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr())))); @@ -1516,13 +1574,16 @@ TEST(SwitchCase, MatchesEachCase) { ifStmt(has(switchStmt(forEachSwitchCase(defaultStmt())))))); EXPECT_TRUE(matches("void x() { switch(42) { case 1+1: case 4:; } }", switchStmt(forEachSwitchCase( - caseStmt(hasCaseConstant(integerLiteral())))))); + caseStmt(hasCaseConstant( + constantExpr(has(integerLiteral())))))))); EXPECT_TRUE(notMatches("void x() { switch(42) { case 1+1: case 2+2:; } }", switchStmt(forEachSwitchCase( - caseStmt(hasCaseConstant(integerLiteral())))))); + caseStmt(hasCaseConstant( + constantExpr(has(integerLiteral())))))))); EXPECT_TRUE(notMatches("void x() { switch(42) { case 1 ... 2:; } }", switchStmt(forEachSwitchCase( - caseStmt(hasCaseConstant(integerLiteral())))))); + caseStmt(hasCaseConstant( + constantExpr(has(integerLiteral())))))))); EXPECT_TRUE(matchAndVerifyResultTrue( "void x() { switch (42) { case 1: case 2: case 3: default:; } }", switchStmt(forEachSwitchCase(caseStmt().bind("x"))), diff --git a/unittests/ASTMatchers/CMakeLists.txt b/unittests/ASTMatchers/CMakeLists.txt index ae1aecf503cc..4e44c795f894 100644 --- a/unittests/ASTMatchers/CMakeLists.txt +++ b/unittests/ASTMatchers/CMakeLists.txt @@ -24,6 +24,7 @@ target_link_libraries(ASTMatchersTests clangASTMatchers clangBasic clangFrontend + clangSerialization clangTooling ) diff --git a/unittests/ASTMatchers/Dynamic/CMakeLists.txt b/unittests/ASTMatchers/Dynamic/CMakeLists.txt index 0fd96e97cff0..07742caef658 100644 --- a/unittests/ASTMatchers/Dynamic/CMakeLists.txt +++ b/unittests/ASTMatchers/Dynamic/CMakeLists.txt @@ -15,5 +15,6 @@ target_link_libraries(DynamicASTMatchersTests clangBasic clangDynamicASTMatchers clangFrontend + clangSerialization clangTooling ) diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp index d670e3129b80..9e891069c862 100644 --- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -148,8 +148,8 @@ TEST(ParserTest, ParseMatcher) { const uint64_t ExpectedBar = Sema.expectMatcher("Bar"); const uint64_t ExpectedBaz = Sema.expectMatcher("Baz"); Sema.parse(" Foo ( Bar ( 17), Baz( \n \"B A,Z\") ) .bind( \"Yo!\") "); - for (size_t i = 0, e = Sema.Errors.size(); i != e; ++i) { - EXPECT_EQ("", Sema.Errors[i]); + for (const auto &E : Sema.Errors) { + EXPECT_EQ("", E); } EXPECT_NE(ExpectedFoo, ExpectedBar); @@ -181,6 +181,21 @@ TEST(ParserTest, ParseMatcher) { EXPECT_EQ("Yo!", Foo.BoundID); } +TEST(ParserTest, ParseComment) { + MockSema Sema; + Sema.expectMatcher("Foo"); + Sema.parse(" Foo() # Bar() "); + for (const auto &E : Sema.Errors) { + EXPECT_EQ("", E); + } + + EXPECT_EQ(1ULL, Sema.Matchers.size()); + + Sema.parse("Foo(#) "); + + EXPECT_EQ("1:4: Error parsing matcher. Found end-of-code while looking for ')'.", Sema.Errors[1]); +} + using ast_matchers::internal::Matcher; Parser::NamedValueMap getTestNamedValues() { @@ -359,6 +374,44 @@ TEST(ParserTest, CompletionNamedValues) { Comps[2].MatcherDecl); } +TEST(ParserTest, ParseBindOnLet) { + + auto NamedValues = getTestNamedValues(); + + Diagnostics Error; + + { + llvm::Optional<DynTypedMatcher> TopLevelLetBinding( + Parser::parseMatcherExpression("hasParamA.bind(\"parmABinding\")", + nullptr, &NamedValues, &Error)); + EXPECT_EQ("", Error.toStringFull()); + auto M = TopLevelLetBinding->unconditionalConvertTo<Decl>(); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "void foo(int a);", M, + llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); + EXPECT_TRUE(matchAndVerifyResultFalse( + "void foo(int b);", M, + llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); + } + + { + llvm::Optional<DynTypedMatcher> NestedLetBinding( + Parser::parseMatcherExpression( + "functionDecl(hasParamA.bind(\"parmABinding\"))", nullptr, + &NamedValues, &Error)); + EXPECT_EQ("", Error.toStringFull()); + auto M = NestedLetBinding->unconditionalConvertTo<Decl>(); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "void foo(int a);", M, + llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); + EXPECT_TRUE(matchAndVerifyResultFalse( + "void foo(int b);", M, + llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); + } +} + } // 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 aae229bd045a..1ca394d8d8c3 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -440,7 +440,8 @@ TEST_F(RegistryTest, Errors) { Error.get()).isNull()); EXPECT_EQ("Incorrect type for arg 1. " "(Expected = Matcher<CXXRecordDecl>) != " - "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)", + "(Actual = Matcher<CXXRecordDecl>&Matcher" + "<MemberExpr|UnresolvedMemberExpr|CXXDependentScopeMemberExpr>)", Error->toString()); } |
