njames93 created this revision.
njames93 added reviewers: klimek, aaron.ballman, steveire.
njames93 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add `deletes` traveral matcher which matches on the expression being delete
Extend `CXXNewExpr::isArray` matcher to work for `CXXDeleteExpr`. Currently 
this only matches array delete expressions as written.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D97681

Files:
  clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp
  clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
  clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp
  clang/docs/LibASTMatchersReference.html
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ 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
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ 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) {
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ 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);
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ 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:
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ 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<Expr>,
+                       InnerMatcher, 1) {
+  return InnerMatcher.matches(*Node.getArgument(), Finder, Builder);
+}
+
 /// Matches a class declaration that is defined.
 ///
 /// Example matches x (matcher = cxxRecordDecl(hasDefinition()))
Index: clang/docs/LibASTMatchersReference.html
===================================================================
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -3075,6 +3075,19 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDeleteExpr.html";>CXXDeleteExpr</a>&gt;</td><td class="name" onclick="toggle('isArray1')"><a name="isArray1Anchor">isArray</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isArray1"><pre>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'.
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDependentScopeMemberExpr.html";>CXXDependentScopeMemberExpr</a>&gt;</td><td class="name" onclick="toggle('hasMemberName0')"><a name="hasMemberName0Anchor">hasMemberName</a></td><td>std::string N</td></tr>
 <tr><td colspan="4" class="doc" id="hasMemberName0"><pre>Matches template-dependent, but known, member names.
 
@@ -3296,12 +3309,15 @@
 
 
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html";>CXXNewExpr</a>&gt;</td><td class="name" onclick="toggle('isArray0')"><a name="isArray0Anchor">isArray</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isArray0"><pre>Matches array new expressions.
+<tr><td colspan="4" class="doc" id="isArray0"><pre>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'.
 </pre></td></tr>
 
 
@@ -6303,6 +6319,17 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDeleteExpr.html";>CXXDeleteExpr</a>&gt;</td><td class="name" onclick="toggle('deletes0')"><a name="deletes0Anchor">deletes</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html";>Expr</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="deletes0"><pre>Matchers the expression being deleted.
+
+Given:
+  int *Ptr = nullptr;
+  delete Ptr;
+cxxDeleteExpr(deletes(declRefExpr(ignoringImpCasts(to(varDecl(hasName("Ptr")))))))
+  matches the expression 'delete Ptr'.
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDependentScopeMemberExpr.html";>CXXDependentScopeMemberExpr</a>&gt;</td><td class="name" onclick="toggle('hasObjectExpression2')"><a name="hasObjectExpression2Anchor">hasObjectExpression</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html";>Expr</a>&gt; InnerMatcher</td></tr>
 <tr><td colspan="4" class="doc" id="hasObjectExpression2"><pre>Matches a member expression where the object expression is matched by a
 given matcher. Implicit object expressions are included; that is, it matches
Index: clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/UniqueptrDeleteReleaseCheck.cpp
+++ 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")),
Index: clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp
+++ 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");
 
Index: clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp
+++ 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;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to