diff --git a/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp @@ -59,9 +59,9 @@ findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(RefMatcher)))), *If, *Result.Context) .empty() || - !match( - findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(RefMatcher))))), - *If, *Result.Context) + !match(findAll(cxxDeleteExpr( + deletes(ignoringParenImpCasts(expr(RefMatcher))))), + *If, *Result.Context) .empty()) return; diff --git a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp @@ -21,11 +21,11 @@ void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) { const auto DeleteExpr = cxxDeleteExpr( - has(declRefExpr(to(decl(equalsBoundNode("deletedPointer")))))) + deletes(declRefExpr(to(decl(equalsBoundNode("deletedPointer")))))) .bind("deleteExpr"); const auto DeleteMemberExpr = - cxxDeleteExpr(has(memberExpr(hasDeclaration( + cxxDeleteExpr(deletes(memberExpr(hasDeclaration( fieldDecl(equalsBoundNode("deletedMemberPointer")))))) .bind("deleteMemberExpr"); diff --git a/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp b/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp @@ -27,7 +27,7 @@ hasName("std::default_delete"))))))); Finder->addMatcher( - cxxDeleteExpr(has(ignoringParenImpCasts(cxxMemberCallExpr( + cxxDeleteExpr(deletes(ignoringParenImpCasts(cxxMemberCallExpr( on(expr(hasType(UniquePtrWithDefaultDelete), unless(hasType(IsSusbstituted))) .bind("uptr")), diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -3075,6 +3075,19 @@ +Matcher<CXXDeleteExpr>isArray +
Matches array new and delete expressions.
+
+Given:
+  MyClass *p1 = new MyClass[10];
+  delete[] p1;
+cxxNewExpr(isArray())
+  matches the expression 'new MyClass[10]'.
+cxxDeleteExpr(isArray())
+  matches the expression 'delete[] p1'.
+
+ + Matcher<CXXDependentScopeMemberExpr>hasMemberNamestd::string N
Matches template-dependent, but known, member names.
 
@@ -3296,12 +3309,15 @@
 
 
 Matcher<CXXNewExpr>isArray
-
Matches array new expressions.
+
Matches array new and delete expressions.
 
 Given:
   MyClass *p1 = new MyClass[10];
+  delete[] p1;
 cxxNewExpr(isArray())
   matches the expression 'new MyClass[10]'.
+cxxDeleteExpr(isArray())
+  matches the expression 'delete[] p1'.
 
@@ -6303,6 +6319,17 @@
+Matcher<CXXDeleteExpr>deletesMatcher<Expr> InnerMatcher +
Matchers the expression being deleted.
+
+Given:
+  int *Ptr = nullptr;
+  delete Ptr;
+cxxDeleteExpr(deletes(declRefExpr(ignoringImpCasts(to(varDecl(hasName("Ptr")))))))
+  matches the expression 'delete Ptr'.
+
+ + Matcher<CXXDependentScopeMemberExpr>hasObjectExpressionMatcher<Expr> InnerMatcher
Matches a member expression where the object expression is matched by a
 given matcher. Implicit object expressions are included; that is, it matches
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7550,16 +7550,21 @@
   return Node.hasDefaultArg();
 }
 
-/// Matches array new expressions.
+/// Matches array new and delete expressions.
 ///
 /// Given:
 /// \code
 ///   MyClass *p1 = new MyClass[10];
+///   delete[] p1;
 /// \endcode
 /// cxxNewExpr(isArray())
 ///   matches the expression 'new MyClass[10]'.
-AST_MATCHER(CXXNewExpr, isArray) {
-  return Node.isArray();
+/// cxxDeleteExpr(isArray())
+///   matches the expression 'delete[] p1'.
+AST_POLYMORPHIC_MATCHER(isArray,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(CXXNewExpr,
+                                                        CXXDeleteExpr)) {
+  return isArrayOperator(Node);
 }
 
 /// Matches placement new expression arguments.
@@ -7604,6 +7609,20 @@
          InnerMatcher.matches(**Node.getArraySize(), Finder, Builder);
 }
 
+/// Matchers the expression being deleted.
+///
+/// Given:
+/// \code
+///   int *Ptr = nullptr;
+///   delete Ptr;
+/// \endcode
+/// cxxDeleteExpr(deletes(declRefExpr(ignoringImpCasts(to(varDecl(hasName("Ptr")))))))
+///   matches the expression 'delete Ptr'.
+AST_MATCHER_P_OVERLOAD(CXXDeleteExpr, deletes, internal::Matcher,
+                       InnerMatcher, 1) {
+  return InnerMatcher.matches(*Node.getArgument(), Finder, Builder);
+}
+
 /// Matches a class declaration that is defined.
 ///
 /// Example matches x (matcher = cxxRecordDecl(hasDefinition()))
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -155,6 +155,14 @@
   return Node.getAccessSpecifier();
 }
 
+/// Unifies obtaining the whether as new or delete operator operates on an
+/// array.
+inline bool isArrayOperator(const CXXNewExpr &Node) { return Node.isArray(); }
+
+inline bool isArrayOperator(const CXXDeleteExpr &Node) {
+  return Node.isArrayFormAsWritten();
+}
+
 /// Internal version of BoundNodes. Holds all the bound nodes.
 class BoundNodesMap {
 public:
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -214,6 +214,7 @@
   REGISTER_MATCHER(decltypeType);
   REGISTER_MATCHER(deducedTemplateSpecializationType);
   REGISTER_MATCHER(defaultStmt);
+  REGISTER_MATCHER(deletes);
   REGISTER_MATCHER(dependentSizedArrayType);
   REGISTER_MATCHER(designatedInitExpr);
   REGISTER_MATCHER(designatorCountIs);
@@ -266,7 +267,6 @@
   REGISTER_MATCHER(hasAnySubstatement);
   REGISTER_MATCHER(hasAnyTemplateArgument);
   REGISTER_MATCHER(hasAnyUsingShadowDecl);
-  REGISTER_MATCHER(hasArgument);
   REGISTER_MATCHER(hasArgumentOfType);
   REGISTER_MATCHER(hasArraySize);
   REGISTER_MATCHER(hasAttr);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -3779,6 +3779,12 @@
 
   EXPECT_TRUE(matches("struct MyClass {}; MyClass *p1 = new MyClass[10];",
                       cxxNewExpr(isArray())));
+
+  EXPECT_TRUE(
+      matches("void foo(int* p) { delete[] p; }", cxxDeleteExpr(isArray())));
+
+  EXPECT_TRUE(
+      notMatches("void foo(int* p) { delete p; }", cxxDeleteExpr(isArray())));
 }
 
 TEST_P(ASTMatchersTest, HasArraySize) {
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -5466,5 +5466,31 @@
                          IsPlacementNew));
 }
 
+TEST(CXXDeleteExpr, Deletes) {
+  StatementMatcher IsDeletingPtrVar = cxxDeleteExpr(
+      deletes(ignoringImpCasts(declRefExpr(to(varDecl(hasName("Ptr")))))));
+
+  EXPECT_TRUE(matches("void foo(int* Ptr) { delete Ptr; }", IsDeletingPtrVar));
+  EXPECT_TRUE(notMatches(R"(
+    struct Foo{
+      int* Address;
+    };
+    void Bar(Foo& Ptr) {
+      delete Ptr.Address;
+    }
+  )",
+                         IsDeletingPtrVar));
+
+  EXPECT_TRUE(notMatches(R"(
+    struct Foo{
+      int* Ptr;
+    };
+    void Bar(Foo& Ptr) {
+      delete Ptr.Ptr;
+    }
+  )",
+                         IsDeletingPtrVar));
+}
+
 } // namespace ast_matchers
 } // namespace clang