diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 5e34d65f2ff9..c977872f3832 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1488,6 +1488,25 @@ methodDecl(isConst()) matches A::foo() but not A::bar() +
Matches if the given method declaration is final. + +Given: + +struct A { + virtual void foo(); + virtual void bar(); +}; + +struct B : A { + void foo() final; + void bar(); +}; + +methodDecl(isFinal()) matches B::foo() but not B::bar(), A::foo(), or A::bar() +
Matches if the given method declaration overrides another method. @@ -1573,6 +1592,18 @@ isSameOrDerivedFrom(hasName(...)).
Matches if the given class declaration is final. + +Given: + +struct A {}; + +struct B final : A {}; + +recordDecl(isFinal()) matches B but not A. +
Matches template instantiations of function, class, or static member variable template instantiations. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 88f9f0788523..0cd90d929ee5 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -3147,6 +3147,27 @@ AST_MATCHER(CXXMethodDecl, isVirtual) { return Node.isVirtual(); } +/// \brief Matches if the given method or class declaration is final. +/// +/// Given: +/// \code +/// class A final {}; +/// +/// struct B { +/// virtual void f(); +/// }; +/// +/// struct C : B { +/// void f() final; +/// }; +/// \endcode +/// matches A and C::f, but not B, C, or B::f +AST_POLYMORPHIC_MATCHER(isFinal, + AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, + CXXMethodDecl)) { + return Node.hasAttr(); +} + /// \brief Matches if the given method declaration is pure. /// /// Given diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 2af4f0002b26..8c0832d16936 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -249,6 +249,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isExplicitTemplateSpecialization); REGISTER_MATCHER(isExpr); REGISTER_MATCHER(isExternC); + REGISTER_MATCHER(isFinal); REGISTER_MATCHER(isImplicit); REGISTER_MATCHER(isExpansionInFileMatching); REGISTER_MATCHER(isExpansionInMainFile); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index 5ac28e5d3e03..edeebde81ed7 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -1784,6 +1784,15 @@ TEST(Matcher, MatchesAccessSpecDecls) { EXPECT_TRUE(notMatches("class C { int i; };", accessSpecDecl())); } +TEST(Matcher, MatchesFinal) { + EXPECT_TRUE(matches("class X final {};", recordDecl(isFinal()))); + EXPECT_TRUE(matches("class X { virtual void f() final; };", + methodDecl(isFinal()))); + EXPECT_TRUE(notMatches("class X {};", recordDecl(isFinal()))); + EXPECT_TRUE(notMatches("class X { virtual void f(); };", + methodDecl(isFinal()))); +} + TEST(Matcher, MatchesVirtualMethod) { EXPECT_TRUE(matches("class X { virtual int f(); };", methodDecl(isVirtual(), hasName("::X::f"))));