[clang-tools-extra] b0bab14 - [clang-tidy] Add check bugprone-unique-ptr-array-mismatch.
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Wed May 31 00:55:57 PDT 2023
Author: Balázs Kéri
Date: 2023-05-31T09:55:01+02:00
New Revision: b0bab14b8b5305ddcb4e8b4d8a0e64004fc5425e
URL: https://github.com/llvm/llvm-project/commit/b0bab14b8b5305ddcb4e8b4d8a0e64004fc5425e
DIFF: https://github.com/llvm/llvm-project/commit/b0bab14b8b5305ddcb4e8b4d8a0e64004fc5425e.diff
LOG: [clang-tidy] Add check bugprone-unique-ptr-array-mismatch.
Reviewed By: PiotrZSL
Differential Revision: https://reviews.llvm.org/D151431
Added:
clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.cpp
clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.h
clang-tools-extra/docs/clang-tidy/checks/bugprone/unique-ptr-array-mismatch.rst
clang-tools-extra/test/clang-tidy/checkers/bugprone/unique-ptr-array-mismatch.cpp
Modified:
clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 5e9c7d0add4f8..e62e536555c29 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -73,6 +73,7 @@
#include "UndelegatedConstructorCheck.h"
#include "UnhandledExceptionAtNewCheck.h"
#include "UnhandledSelfAssignmentCheck.h"
+#include "UniquePtrArrayMismatchCheck.h"
#include "UnsafeFunctionsCheck.h"
#include "UnusedRaiiCheck.h"
#include "UnusedReturnValueCheck.h"
@@ -207,6 +208,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-unhandled-self-assignment");
CheckFactories.registerCheck<UnhandledExceptionAtNewCheck>(
"bugprone-unhandled-exception-at-new");
+ CheckFactories.registerCheck<UniquePtrArrayMismatchCheck>(
+ "bugprone-unique-ptr-array-mismatch");
CheckFactories.registerCheck<UnsafeFunctionsCheck>(
"bugprone-unsafe-functions");
CheckFactories.registerCheck<UnusedRaiiCheck>("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index e70d1b426a1c6..363d1a85b0ae5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -69,6 +69,7 @@ add_clang_library(clangTidyBugproneModule
UndelegatedConstructorCheck.cpp
UnhandledExceptionAtNewCheck.cpp
UnhandledSelfAssignmentCheck.cpp
+ UniquePtrArrayMismatchCheck.cpp
UnsafeFunctionsCheck.cpp
UnusedRaiiCheck.cpp
UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.cpp
new file mode 100644
index 0000000000000..8d09b4b320c2c
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.cpp
@@ -0,0 +1,33 @@
+//===--- UniquePtrArrayMismatchCheck.cpp - clang-tidy ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UniquePtrArrayMismatchCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UniquePtrArrayMismatchCheck::UniquePtrArrayMismatchCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : SmartPtrArrayMismatchCheck(Name, Context, "unique") {}
+
+UniquePtrArrayMismatchCheck::SmartPtrClassMatcher
+UniquePtrArrayMismatchCheck::getSmartPointerClassMatcher() const {
+ auto DeleterDecl = classTemplateSpecializationDecl(
+ hasName("::std::default_delete"), templateArgumentCountIs(1),
+ hasTemplateArgument(0, templateArgument(refersToType(
+ qualType(equalsBoundNode(PointerTypeN))))));
+ return classTemplateSpecializationDecl(
+ hasName("::std::unique_ptr"), templateArgumentCountIs(2),
+ hasTemplateArgument(
+ 0, templateArgument(refersToType(qualType().bind(PointerTypeN)))),
+ hasTemplateArgument(1, templateArgument(refersToType(
+ qualType(hasDeclaration(DeleterDecl))))));
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.h b/clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.h
new file mode 100644
index 0000000000000..fb7531ab146c6
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UniquePtrArrayMismatchCheck.h
@@ -0,0 +1,34 @@
+//===--- UniquePtrArrayMismatchCheck.h - clang-tidy -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNIQUEPTRARRAYMISMATCHCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNIQUEPTRARRAYMISMATCHCHECK_H
+
+#include "SmartPtrArrayMismatchCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Finds initializations of C++ unique pointers to non-array type that are
+/// initialized with an array.
+///
+/// Example:
+///
+/// \code
+/// std::unique_ptr<int> PtrArr{new int[10]};
+/// \endcode
+class UniquePtrArrayMismatchCheck : public SmartPtrArrayMismatchCheck {
+public:
+ UniquePtrArrayMismatchCheck(StringRef Name, ClangTidyContext *Context);
+
+protected:
+ SmartPtrClassMatcher getSmartPointerClassMatcher() const override;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNIQUEPTRARRAYMISMATCHCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index b336cd2fc0e24..5e3c46cadde9f 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -121,6 +121,12 @@ New checks
Detect implicit and explicit casts of ``enum`` type into ``bool`` where ``enum`` type
doesn't have a zero-value enumerator.
+- New :doc:`bugprone-unique-ptr-array-mismatch
+ <clang-tidy/checks/bugprone/unique-ptr-array-mismatch>` check.
+
+ Finds initializations of C++ unique pointers to non-array type that are
+ initialized with an array.
+
- New :doc:`bugprone-unsafe-functions
<clang-tidy/checks/bugprone/unsafe-functions>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/unique-ptr-array-mismatch.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unique-ptr-array-mismatch.rst
new file mode 100644
index 0000000000000..c00385954b23c
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/unique-ptr-array-mismatch.rst
@@ -0,0 +1,39 @@
+.. title:: clang-tidy - bugprone-unique-ptr-array-mismatch
+
+bugprone-unique-ptr-array-mismatch
+==================================
+
+Finds initializations of C++ unique pointers to non-array type that are
+initialized with an array.
+
+If a pointer ``std::unique_ptr<T>`` is initialized with a new-expression
+``new T[]`` the memory is not deallocated correctly. A plain ``delete`` is used
+in this case to deallocate the target memory. Instead a ``delete[]`` call is
+needed. A ``std::unique_ptr<T[]>`` uses the correct delete operator. The check
+does not emit warning if an ``unique_ptr`` with user-specified deleter type is
+used.
+
+The check offers replacement of ``unique_ptr<T>`` to ``unique_ptr<T[]>`` if it
+is used at a single variable declaration (one variable in one statement).
+
+Example:
+
+.. code-block:: c++
+
+ std::unique_ptr<Foo> x(new Foo[10]); // -> std::unique_ptr<Foo[]> x(new Foo[10]);
+ // ^ warning: unique pointer to non-array is initialized with array
+ std::unique_ptr<Foo> x1(new Foo), x2(new Foo[10]); // no replacement
+ // ^ warning: unique pointer to non-array is initialized with array
+
+ D d;
+ std::unique_ptr<Foo, D> x3(new Foo[10], d); // no warning (custom deleter used)
+
+ struct S {
+ std::unique_ptr<Foo> x(new Foo[10]); // no replacement in this case
+ // ^ warning: unique pointer to non-array is initialized with array
+ };
+
+This check partially covers the CERT C++ Coding Standard rule
+`MEM51-CPP. Properly deallocate dynamically allocated resources
+<https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM51-CPP.+Properly+deallocate+dynamically+allocated+resources>`_
+However, only the ``std::unique_ptr`` case is detected by this check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 055e6ae661f09..a13f841105f45 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -139,6 +139,7 @@ Clang-Tidy Checks
`bugprone-undelegated-constructor <bugprone/undelegated-constructor.html>`_,
`bugprone-unhandled-exception-at-new <bugprone/unhandled-exception-at-new.html>`_,
`bugprone-unhandled-self-assignment <bugprone/unhandled-self-assignment.html>`_,
+ `bugprone-unique-ptr-array-mismatch <bugprone/unique-ptr-array-mismatch.html>`_, "Yes"
`bugprone-unsafe-functions <bugprone/unsafe-functions.html>`_,
`bugprone-unused-raii <bugprone/unused-raii.html>`_, "Yes"
`bugprone-unused-return-value <bugprone/unused-return-value.html>`_,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/unique-ptr-array-mismatch.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unique-ptr-array-mismatch.cpp
new file mode 100644
index 0000000000000..494e83dce3720
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/unique-ptr-array-mismatch.cpp
@@ -0,0 +1,127 @@
+// RUN: %check_clang_tidy %s bugprone-unique-ptr-array-mismatch %t
+
+namespace std {
+
+template<class T> struct default_delete {};
+template<class T> struct default_delete<T[]> {};
+
+template<class T, class Deleter = std::default_delete<T>>
+class unique_ptr {
+public:
+ explicit unique_ptr(T* p) noexcept;
+ unique_ptr(T* p, Deleter d1 ) noexcept;
+};
+
+template <class T, class Deleter>
+class unique_ptr<T[], Deleter> {
+public:
+ template<class U>
+ explicit unique_ptr(U p) noexcept;
+ template<class U>
+ unique_ptr(U p, Deleter d1) noexcept;
+};
+
+} // namespace std
+
+struct A {};
+
+using PtrT = std::unique_ptr<A>;
+using PtrTArr = std::unique_ptr<A[]>;
+
+void f1() {
+ std::unique_ptr<int> P1{new int};
+ std::unique_ptr<int> P2{new int[10]};
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // CHECK-FIXES: std::unique_ptr<int[]> P2{new int[10]};
+ // clang-format off
+ std::unique_ptr< int > P3{new int[10]};
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // CHECK-FIXES: std::unique_ptr< int[] > P3{new int[10]};
+ // clang-format on
+ std::unique_ptr<int> P4(new int[10]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // CHECK-FIXES: std::unique_ptr<int[]> P4(new int[10]);
+ new std::unique_ptr<int>(new int[10]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ std::unique_ptr<int[]> P5(new int[10]);
+
+ A deleter;
+ std::unique_ptr<int, A> P6(new int[10], deleter);
+ std::unique_ptr<int, A> P7(new int[10]);
+ std::default_delete<int[]> def_del;
+ std::unique_ptr<int, std::default_delete<int[]>> P8(new int[10], def_del);
+
+ new PtrT(new A[10]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ new PtrTArr(new A[10]);
+}
+
+void f2() {
+ std::unique_ptr<A> P1(new A);
+ std::unique_ptr<A> P2(new A[10]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // CHECK-FIXES: std::unique_ptr<A[]> P2(new A[10]);
+ std::unique_ptr<A[]> P3(new A[10]);
+}
+
+void f3() {
+ std::unique_ptr<int> P1{new int}, P2{new int[10]}, P3{new int[10]};
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // CHECK-MESSAGES: :[[@LINE-2]]:57: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+}
+
+struct S {
+ std::unique_ptr<int> P1;
+ std::unique_ptr<int> P2{new int[10]};
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ std::unique_ptr<int> P3{new int}, P4{new int[10]};
+ // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ S() : P1{new int[10]} {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+};
+
+void f_parm(std::unique_ptr<int>);
+
+void f4() {
+ f_parm(std::unique_ptr<int>{new int[10]});
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+}
+
+std::unique_ptr<int> f_ret() {
+ return std::unique_ptr<int>(new int[10]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+}
+
+template <class T>
+void f_tmpl() {
+ std::unique_ptr<T> P1{new T[10]};
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // CHECK-FIXES: std::unique_ptr<T[]> P1{new T[10]};
+}
+
+void f5() {
+ f_tmpl<char>();
+}
+
+template <class T>
+void f_tmpl_1() {
+ std::unique_ptr<T> P1{new T[10]};
+ // FIXME_CHECK-MESSAGES: :[[@LINE-1]]:25: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // FIXME_CHECK-FIXES: std::unique_ptr<T[]> P1{new T[10]};
+}
+
+#define CHAR_PTR_TYPE std::unique_ptr<char>
+#define CHAR_PTR_VAR(X) \
+ X { new char[10] }
+#define CHAR_PTR_INIT(X, Y) \
+ std::unique_ptr<char> X { Y }
+
+void f6() {
+ CHAR_PTR_TYPE P1{new char[10]};
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ std::unique_ptr<char> CHAR_PTR_VAR(P2);
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+ // CHECK-FIXES: std::unique_ptr<char[]> CHAR_PTR_VAR(P2);
+ CHAR_PTR_INIT(P3, new char[10]);
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: unique pointer to non-array is initialized with array [bugprone-unique-ptr-array-mismatch]
+}
More information about the cfe-commits
mailing list