diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 5e34d65f2ff9b73bd463c00f77d9f94d1304f583..c977872f383214a7a148f1bb563fe6553fce8629 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -1488,6 +1488,25 @@ methodDecl(isConst()) matches A::foo() but not A::bar() </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isFinal0')"><a name="isFinal0Anchor">isFinal</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isFinal0"><pre>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() +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isOverride0')"><a name="isOverride0Anchor">isOverride</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isOverride0"><pre>Matches if the given method declaration overrides another method. @@ -1573,6 +1592,18 @@ isSameOrDerivedFrom(hasName(...)). </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isFinal1')"><a name="isFinal1Anchor">isFinal</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isFinal1"><pre>Matches if the given class declaration is final. + +Given: + +struct A {}; + +struct B final : A {}; + +recordDecl(isFinal()) matches B but not A. +</pre></td></tr> + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation2')"><a name="isTemplateInstantiation2Anchor">isTemplateInstantiation</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isTemplateInstantiation2"><pre>Matches template instantiations of function, class, or static member variable template instantiations. diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 88f9f07885237d1c92f090716d8854d121fbae55..0cd90d929ee59e861a9117f5bccf16748f47e9f3 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/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<FinalAttr>(); +} + /// \brief Matches if the given method declaration is pure. /// /// Given diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 2af4f0002b268224d4ee071cd508978cafc7f340..8c0832d16936a20937e97e8c8ee2aac749acdb0f 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/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/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 5ac28e5d3e0303a84d09206e7b646cfe76e6177e..edeebde81ed774c482fba094e46055dc5e56e830 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/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"))));