aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp')
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp74
1 files changed, 74 insertions, 0 deletions
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 7a6d6ef..8f0dd56 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2369,6 +2369,80 @@ TEST_P(ASTMatchersTest, LambdaCaptureTest_BindsToCaptureOfReferenceType) {
"}", matcher));
}
+TEST_P(ASTMatchersTest, IsDerivedFromRecursion) {
+ if (!GetParam().isCXX11OrLater())
+ return;
+
+ // Check we don't crash on cycles in the traversal and inheritance hierarchy.
+ // Clang will normally enforce there are no cycles, but matchers opted to
+ // traverse primary template for dependent specializations, spuriously
+ // creating the cycles.
+ DeclarationMatcher matcher = cxxRecordDecl(isDerivedFrom("X"));
+ EXPECT_TRUE(notMatches(R"cpp(
+ template <typename T1, typename T2>
+ struct M;
+
+ template <typename T1>
+ struct M<T1, void> {};
+
+ template <typename T1, typename T2>
+ struct L : M<T1, T2> {};
+
+ template <typename T1, typename T2>
+ struct M : L<M<T1, T2>, M<T1, T2>> {};
+ )cpp",
+ matcher));
+
+ // Check the running time is not exponential. The number of subojects to
+ // traverse grows as fibonacci numbers even though the number of bases to
+ // traverse is quadratic.
+ // The test will hang if implementation of matchers traverses all subojects.
+ EXPECT_TRUE(notMatches(R"cpp(
+ template <class T> struct A0 {};
+ template <class T> struct A1 : A0<T> {};
+ template <class T> struct A2 : A1<T>, A0<T> {};
+ template <class T> struct A3 : A2<T>, A1<T> {};
+ template <class T> struct A4 : A3<T>, A2<T> {};
+ template <class T> struct A5 : A4<T>, A3<T> {};
+ template <class T> struct A6 : A5<T>, A4<T> {};
+ template <class T> struct A7 : A6<T>, A5<T> {};
+ template <class T> struct A8 : A7<T>, A6<T> {};
+ template <class T> struct A9 : A8<T>, A7<T> {};
+ template <class T> struct A10 : A9<T>, A8<T> {};
+ template <class T> struct A11 : A10<T>, A9<T> {};
+ template <class T> struct A12 : A11<T>, A10<T> {};
+ template <class T> struct A13 : A12<T>, A11<T> {};
+ template <class T> struct A14 : A13<T>, A12<T> {};
+ template <class T> struct A15 : A14<T>, A13<T> {};
+ template <class T> struct A16 : A15<T>, A14<T> {};
+ template <class T> struct A17 : A16<T>, A15<T> {};
+ template <class T> struct A18 : A17<T>, A16<T> {};
+ template <class T> struct A19 : A18<T>, A17<T> {};
+ template <class T> struct A20 : A19<T>, A18<T> {};
+ template <class T> struct A21 : A20<T>, A19<T> {};
+ template <class T> struct A22 : A21<T>, A20<T> {};
+ template <class T> struct A23 : A22<T>, A21<T> {};
+ template <class T> struct A24 : A23<T>, A22<T> {};
+ template <class T> struct A25 : A24<T>, A23<T> {};
+ template <class T> struct A26 : A25<T>, A24<T> {};
+ template <class T> struct A27 : A26<T>, A25<T> {};
+ template <class T> struct A28 : A27<T>, A26<T> {};
+ template <class T> struct A29 : A28<T>, A27<T> {};
+ template <class T> struct A30 : A29<T>, A28<T> {};
+ template <class T> struct A31 : A30<T>, A29<T> {};
+ template <class T> struct A32 : A31<T>, A30<T> {};
+ template <class T> struct A33 : A32<T>, A31<T> {};
+ template <class T> struct A34 : A33<T>, A32<T> {};
+ template <class T> struct A35 : A34<T>, A33<T> {};
+ template <class T> struct A36 : A35<T>, A34<T> {};
+ template <class T> struct A37 : A36<T>, A35<T> {};
+ template <class T> struct A38 : A37<T>, A36<T> {};
+ template <class T> struct A39 : A38<T>, A37<T> {};
+ template <class T> struct A40 : A39<T>, A38<T> {};
+)cpp",
+ matcher));
+}
+
TEST(ASTMatchersTestObjC, ObjCMessageCalees) {
StatementMatcher MessagingFoo =
objcMessageExpr(callee(objcMethodDecl(hasName("foo"))));