diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index ca44c3ee08565..a684026d2148e 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -5444,6 +5444,43 @@ AST_MATCHER(FunctionDecl, isDefaulted) { return Node.isDefaulted(); } +/// Matches trivial methods and types. +/// +/// Given: +/// \code +/// class A { A(); }; +/// A::A() = default; +/// class B { B() = default; }; +/// \endcode +/// cxxMethodDecl(isTrivial()) +/// matches the declaration of B, but not A. +AST_POLYMORPHIC_MATCHER(isTrivial, + AST_POLYMORPHIC_SUPPORTED_TYPES(CXXMethodDecl, + CXXRecordDecl)) { + if (const auto *E = dyn_cast(&Node)) + return E->isTrivial(); + if (const auto *E = dyn_cast(&Node)) { + const auto *Def = Node.getDefinition(); + return Def && Def->isTrivial(); + } + return false; +} + +/// Matches trivially copyable types. +/// +/// Given: +/// \code +/// class A { A(const A &); }; +/// A::A(const A &) = default; +/// class B { B(const B &) = default; }; +/// \endcode +/// cxxMethodDecl(isTriviallyCopyable()) +/// matches the declaration of B, but not A. +AST_MATCHER(CXXRecordDecl, isTriviallyCopyable) { + CXXRecordDecl *Def = Node.getDefinition(); + return Def && Def->isTriviallyCopyable(); +} + /// Matches weak function declarations. /// /// Given: diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index 611e1f9ba5327..40bce66471fe2 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1850,6 +1850,33 @@ TEST_P(ASTMatchersTest, IsDeleted) { functionDecl(hasName("Func"), isDeleted()))); } +TEST_P(ASTMatchersTest, IsTrivial) { + if (!GetParam().isCXX()) { + return; + } + + EXPECT_TRUE(notMatches("class A { A(); };", + cxxRecordDecl(hasName("A"), isTrivial()))); + EXPECT_TRUE(matches("class B { B() = default; };", + cxxRecordDecl(hasName("B"), isTrivial()))); + + EXPECT_TRUE(notMatches("class A { ~A(); }; A::~A() = default;", + cxxMethodDecl(hasName("~A"), isTrivial()))); + EXPECT_TRUE(matches("class B { ~B() = default; };", + cxxMethodDecl(hasName("~B"), isTrivial()))); +} + +TEST_P(ASTMatchersTest, IsTriviallyCopyable) { + if (!GetParam().isCXX()) { + return; + } + + EXPECT_TRUE(notMatches("class A { ~A(); }; A::~A() = default;", + cxxRecordDecl(hasName("A"), isTriviallyCopyable()))); + EXPECT_TRUE(matches("class B { ~B() = default; };", + cxxRecordDecl(hasName("B"), isTriviallyCopyable()))); +} + TEST_P(ASTMatchersTest, IsNoThrow_DynamicExceptionSpec) { if (!GetParam().supportsCXXDynamicExceptionSpecification()) { return;