[clang-tidy] Add check bugprone-unique-ptr-array-mismatch.

Reviewed By: PiotrZSL

Differential Revision: https://reviews.llvm.org/D151431
This commit is contained in:
Balázs Kéri
2023-05-31 08:54:40 +02:00
parent c113cbb510
commit b0bab14b8b
8 changed files with 244 additions and 0 deletions

View File

@@ -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 @@ public:
"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");

View File

@@ -69,6 +69,7 @@ add_clang_library(clangTidyBugproneModule
UndelegatedConstructorCheck.cpp
UnhandledExceptionAtNewCheck.cpp
UnhandledSelfAssignmentCheck.cpp
UniquePtrArrayMismatchCheck.cpp
UnsafeFunctionsCheck.cpp
UnusedRaiiCheck.cpp
UnusedReturnValueCheck.cpp

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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>`_,

View File

@@ -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]
}