[clang-tools-extra] [clang-tidy] Add bugprone-smart-ptr-initialization check (PR #181570)
Denis Mikhailov via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 12 08:34:51 PDT 2026
https://github.com/denzor200 updated https://github.com/llvm/llvm-project/pull/181570
>From ce04b6476fbb5b2e66a439f407d4e335616d4aff Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Tue, 2 Dec 2025 03:24:44 +0300
Subject: [PATCH 01/33] Initial implementation by DeepSeek
---
.../bugprone/BugproneTidyModule.cpp | 3 +
.../clang-tidy/bugprone/CMakeLists.txt | 1 +
.../bugprone/SmartPtrInitializationCheck.cpp | 219 ++++++++++++++++++
.../bugprone/SmartPtrInitializationCheck.h | 35 +++
clang-tools-extra/docs/ReleaseNotes.rst | 5 +
.../bugprone/smart-ptr-initialization.rst | 6 +
.../docs/clang-tidy/checks/list.rst | 19 +-
.../bugprone/smart-ptr-initialization.cpp | 145 ++++++++++++
8 files changed, 422 insertions(+), 11 deletions(-)
create mode 100644 clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..fcadcdf2b7625 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -75,6 +75,7 @@
#include "SignedCharMisuseCheck.h"
#include "SizeofContainerCheck.h"
#include "SizeofExpressionCheck.h"
+#include "SmartPtrInitializationCheck.h"
#include "SpuriouslyWakeUpFunctionsCheck.h"
#include "StandaloneEmptyCheck.h"
#include "StdNamespaceModificationCheck.h"
@@ -176,6 +177,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-incorrect-enable-if");
CheckFactories.registerCheck<IncorrectEnableSharedFromThisCheck>(
"bugprone-incorrect-enable-shared-from-this");
+ CheckFactories.registerCheck<SmartPtrInitializationCheck>(
+ "bugprone-smart-ptr-initialization");
CheckFactories.registerCheck<UnintendedCharOstreamOutputCheck>(
"bugprone-unintended-char-ostream-output");
CheckFactories.registerCheck<ReturnConstRefFromParameterCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..e46edc5bafea2 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -37,6 +37,7 @@ add_clang_library(clangTidyBugproneModule STATIC
IncorrectEnableIfCheck.cpp
IncorrectEnableSharedFromThisCheck.cpp
InvalidEnumDefaultInitializationCheck.cpp
+ SmartPtrInitializationCheck.cpp
UnintendedCharOstreamOutputCheck.cpp
ReturnConstRefFromParameterCheck.cpp
SuspiciousStringviewDataUsageCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
new file mode 100644
index 0000000000000..392c193918be0
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -0,0 +1,219 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "SmartPtrInitializationCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang;
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+namespace {
+
+AST_MATCHER(Expr, isNewExpression) {
+ return isa<CXXNewExpr>(Node);
+}
+
+AST_MATCHER(Expr, isReleaseCall) {
+ const auto *call = dyn_cast<CallExpr>(&Node);
+ if (!call)
+ return false;
+
+ const auto *method = dyn_cast<CXXMemberCallExpr>(call);
+ if (!method)
+ return false;
+
+ const auto *member = method->getMethodDecl();
+ if (!member)
+ return false;
+
+ return member->getName() == "release";
+}
+
+AST_MATCHER(Expr, isMakeUniqueOrSharedCall) {
+ const auto *call = dyn_cast<CallExpr>(&Node);
+ if (!call)
+ return false;
+
+ const auto *callee = call->getDirectCallee();
+ if (!callee)
+ return false;
+
+ StringRef name = callee->getName();
+ if (name != "make_unique" && name != "make_shared")
+ return false;
+
+ // Check if it's in std namespace by checking the qualified name
+ std::string qualifiedName = callee->getQualifiedNameAsString();
+ return qualifiedName == "std::make_unique" || qualifiedName == "std::make_shared";
+}
+
+AST_MATCHER(CXXConstructExpr, hasCustomDeleter) {
+ if (Node.getNumArgs() < 2)
+ return false;
+
+ // Check if the second argument is a deleter
+ const Expr *deleterArg = Node.getArg(1);
+ if (!deleterArg)
+ return false;
+
+ // Check if this is a smart pointer construction with custom deleter
+ const auto *record = Node.getConstructor()->getParent();
+ if (!record)
+ return false;
+
+ std::string typeName = record->getQualifiedNameAsString();
+ return typeName == "std::shared_ptr" || typeName == "std::unique_ptr";
+}
+
+AST_MATCHER(CallExpr, isResetWithCustomDeleter) {
+ const auto *memberCall = dyn_cast<CXXMemberCallExpr>(&Node);
+ if (!memberCall)
+ return false;
+
+ const auto *method = memberCall->getMethodDecl();
+ if (!method || method->getName() != "reset")
+ return false;
+
+ if (Node.getNumArgs() < 2)
+ return false;
+
+ const auto *record = method->getParent();
+ if (!record)
+ return false;
+
+ std::string typeName = record->getQualifiedNameAsString();
+ return typeName == "std::shared_ptr" || typeName == "std::unique_ptr";
+}
+
+} // namespace
+
+void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
+ // Matcher for smart pointer constructors
+ auto smartPtrConstructorMatcher = cxxConstructExpr(
+ hasDeclaration(
+ cxxConstructorDecl(ofClass(hasAnyName("std::shared_ptr",
+ "std::unique_ptr")))),
+ hasArgument(0, expr().bind("pointer-arg")),
+ unless(hasCustomDeleter()),
+ unless(hasArgument(0, isNewExpression())),
+ unless(hasArgument(0, isReleaseCall())),
+ unless(hasArgument(0, isMakeUniqueOrSharedCall()))
+ ).bind("constructor");
+
+ // Matcher for reset() calls
+ auto resetCallMatcher = cxxMemberCallExpr(
+ on(hasType(cxxRecordDecl(hasAnyName("std::shared_ptr", "std::unique_ptr")))),
+ callee(cxxMethodDecl(hasName("reset"))),
+ hasArgument(0, expr().bind("pointer-arg")),
+ unless(isResetWithCustomDeleter()),
+ unless(hasArgument(0, isNewExpression())),
+ unless(hasArgument(0, isReleaseCall())),
+ unless(hasArgument(0, isMakeUniqueOrSharedCall()))
+ ).bind("reset-call");
+
+ Finder->addMatcher(smartPtrConstructorMatcher, this);
+ Finder->addMatcher(resetCallMatcher, this);
+}
+
+void SmartPtrInitializationCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *pointerArg = Result.Nodes.getNodeAs<Expr>("pointer-arg");
+ if (!pointerArg)
+ return;
+
+ // Skip if the pointer is a null pointer
+ if (pointerArg->isNullPointerConstant(*Result.Context,
+ Expr::NPC_ValueDependentIsNotNull))
+ return;
+
+ // Check if the expression is a call to a function returning a pointer
+ bool isFunctionReturn = false;
+ if (const auto *call = dyn_cast<CallExpr>(pointerArg)) {
+ if (call->getDirectCallee()) {
+ isFunctionReturn = true;
+ }
+ }
+
+ // Check if it's taking address of something
+ bool isAddressOf = isa<UnaryOperator>(pointerArg) &&
+ cast<UnaryOperator>(pointerArg)->getOpcode() == UO_AddrOf;
+
+ // Check if it's getting pointer from reference
+ const Expr *innerExpr = pointerArg->IgnoreParenCasts();
+ if (const auto *unaryOp = dyn_cast<UnaryOperator>(innerExpr)) {
+ if (unaryOp->getOpcode() == UO_AddrOf) {
+ isAddressOf = true;
+ }
+ }
+
+ // Also check for member expressions that might return references
+ if (const auto *memberExpr = dyn_cast<MemberExpr>(innerExpr)) {
+ if (memberExpr->isArrow()) {
+ // arrow operator returns pointer, not reference
+ isAddressOf = false;
+ }
+ }
+
+ if (isFunctionReturn || isAddressOf) {
+ std::string message;
+ const SourceLocation loc = pointerArg->getBeginLoc();
+
+ if (const auto *constructor =
+ Result.Nodes.getNodeAs<CXXConstructExpr>("constructor")) {
+ const auto *decl = constructor->getConstructor();
+ if (decl) {
+ const auto *record = decl->getParent();
+ if (record) {
+ std::string typeName = record->getQualifiedNameAsString();
+ message = "passing a raw pointer '" +
+ getPointerDescription(pointerArg, *Result.Context) +
+ "' to " + typeName +
+ " constructor may cause double deletion";
+ }
+ }
+ } else if (const auto *resetCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset-call")) {
+ const auto *method = resetCall->getMethodDecl();
+ if (method) {
+ const auto *record = method->getParent();
+ if (record) {
+ std::string typeName = record->getQualifiedNameAsString();
+ message = "passing a raw pointer '" +
+ getPointerDescription(pointerArg, *Result.Context) +
+ "' to " + typeName +
+ "::reset() may cause double deletion";
+ }
+ }
+ }
+
+ if (!message.empty()) {
+ diag(loc, message);
+ }
+ }
+}
+
+std::string SmartPtrInitializationCheck::getPointerDescription(
+ const Expr *PointerExpr, ASTContext &Context) {
+ std::string Desc;
+ llvm::raw_string_ostream OS(Desc);
+
+ // Try to get a readable representation of the expression
+ PrintingPolicy Policy(Context.getLangOpts());
+ Policy.SuppressSpecifiers = false;
+ Policy.SuppressTagKeyword = true;
+
+ PointerExpr->printPretty(OS, nullptr, Policy);
+ return OS.str();
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
new file mode 100644
index 0000000000000..b21774b6b0806
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SMARTPTRINITIALIZATIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRINITIALIZATIONCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects dangerous initialization of smart pointers with raw pointers
+/// that are already owned elsewhere, which can lead to double deletion.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/smart-ptr-initialization.html
+class SmartPtrInitializationCheck : public ClangTidyCheck {
+public:
+ SmartPtrInitializationCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ std::string getPointerDescription(const Expr *PointerExpr,
+ ASTContext &Context);
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRINITIALIZATIONCHECK_H
\ No newline at end of file
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a6f80e3721db1..76882e0e1a251 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -202,6 +202,11 @@ New checks
Detects default initialization (to 0) of variables with ``enum`` type where
the enum has no enumerator with value of 0.
+- New :doc:`bugprone-smart-ptr-initialization
+ <clang-tidy/checks/bugprone/smart-ptr-initialization>` check.
+
+ FIXME: Write a short description.
+
- New :doc:`cppcoreguidelines-pro-bounds-avoid-unchecked-container-access
<clang-tidy/checks/cppcoreguidelines/pro-bounds-avoid-unchecked-container-access>`
check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
new file mode 100644
index 0000000000000..ed72c6b1b92b1
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
@@ -0,0 +1,6 @@
+.. title:: clang-tidy - bugprone-smart-ptr-initialization
+
+bugprone-smart-ptr-initialization
+=================================
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 8bb112f3d1832..a6cb12032b481 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -143,6 +143,7 @@ Clang-Tidy Checks
:doc:`bugprone-signed-char-misuse <bugprone/signed-char-misuse>`,
:doc:`bugprone-sizeof-container <bugprone/sizeof-container>`,
:doc:`bugprone-sizeof-expression <bugprone/sizeof-expression>`,
+ :doc:`bugprone-smart-ptr-initialization <bugprone/smart-ptr-initialization>`, "Yes"
:doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
:doc:`bugprone-standalone-empty <bugprone/standalone-empty>`, "Yes"
:doc:`bugprone-std-namespace-modification <bugprone/std-namespace-modification>`,
@@ -180,11 +181,12 @@ Clang-Tidy Checks
:doc:`bugprone-unused-return-value <bugprone/unused-return-value>`,
:doc:`bugprone-use-after-move <bugprone/use-after-move>`,
:doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes"
+ :doc:`cert-dcl58-cpp <cert/dcl58-cpp>`,
+ :doc:`cert-env33-c <cert/env33-c>`,
:doc:`cert-err33-c <cert/err33-c>`,
- :doc:`cert-err60-cpp <cert/err60-cpp>`,
+ :doc:`cert-err52-cpp <cert/err52-cpp>`,
:doc:`cert-flp30-c <cert/flp30-c>`,
- :doc:`cert-msc50-cpp <cert/msc50-cpp>`,
- :doc:`cert-oop58-cpp <cert/oop58-cpp>`,
+ :doc:`cert-mem57-cpp <cert/mem57-cpp>`,
:doc:`concurrency-mt-unsafe <concurrency/mt-unsafe>`,
:doc:`concurrency-thread-canceltype-asynchronous <concurrency/thread-canceltype-asynchronous>`,
:doc:`cppcoreguidelines-avoid-capturing-lambda-coroutines <cppcoreguidelines/avoid-capturing-lambda-coroutines>`,
@@ -376,7 +378,7 @@ Clang-Tidy Checks
:doc:`readability-avoid-nested-conditional-operator <readability/avoid-nested-conditional-operator>`,
:doc:`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>`, "Yes"
:doc:`readability-avoid-unconditional-preprocessor-if <readability/avoid-unconditional-preprocessor-if>`,
- :doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
+ :doc:`readability-braces-around-statements <readability/braces-around-statements>`,
:doc:`readability-const-return-type <readability/const-return-type>`, "Yes"
:doc:`readability-container-contains <readability/container-contains>`, "Yes"
:doc:`readability-container-data-pointer <readability/container-data-pointer>`, "Yes"
@@ -445,21 +447,16 @@ Check aliases
:doc:`cert-dcl50-cpp <cert/dcl50-cpp>`, :doc:`modernize-avoid-variadic-functions <modernize/avoid-variadic-functions>`,
:doc:`cert-dcl51-cpp <cert/dcl51-cpp>`, :doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
:doc:`cert-dcl54-cpp <cert/dcl54-cpp>`, :doc:`misc-new-delete-overloads <misc/new-delete-overloads>`,
- :doc:`cert-dcl58-cpp <cert/dcl58-cpp>`, :doc:`bugprone-std-namespace-modification <bugprone/std-namespace-modification>`,
:doc:`cert-dcl59-cpp <cert/dcl59-cpp>`, :doc:`google-build-namespaces <google/build-namespaces>`,
- :doc:`cert-env33-c <cert/env33-c>`, :doc:`bugprone-command-processor <bugprone/command-processor>`,
:doc:`cert-err09-cpp <cert/err09-cpp>`, :doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
:doc:`cert-err34-c <cert/err34-c>`, :doc:`bugprone-unchecked-string-to-number-conversion <bugprone/unchecked-string-to-number-conversion>`,
- :doc:`cert-err52-cpp <cert/err52-cpp>`, :doc:`modernize-avoid-setjmp-longjmp <modernize/avoid-setjmp-longjmp>`,
:doc:`cert-err58-cpp <cert/err58-cpp>`, :doc:`bugprone-throwing-static-initialization <bugprone/throwing-static-initialization>`,
:doc:`cert-err60-cpp <cert/err60-cpp>`, :doc:`bugprone-exception-copy-constructor-throws <bugprone/exception-copy-constructor-throws>`,
:doc:`cert-err61-cpp <cert/err61-cpp>`, :doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
:doc:`cert-exp42-c <cert/exp42-c>`, :doc:`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>`,
:doc:`cert-fio38-c <cert/fio38-c>`, :doc:`misc-non-copyable-objects <misc/non-copyable-objects>`,
- :doc:`cert-flp30-c <cert/flp30-c>`, :doc:`bugprone-float-loop-counter <bugprone/float-loop-counter>`,
:doc:`cert-flp37-c <cert/flp37-c>`, :doc:`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>`,
:doc:`cert-int09-c <cert/int09-c>`, :doc:`readability-enum-initial-value <readability/enum-initial-value>`, "Yes"
- :doc:`cert-mem57-cpp <cert/mem57-cpp>`, :doc:`bugprone-default-operator-new-on-overaligned-type <bugprone/default-operator-new-on-overaligned-type>`,
:doc:`cert-msc24-c <cert/msc24-c>`, :doc:`bugprone-unsafe-functions <bugprone/unsafe-functions>`,
:doc:`cert-msc30-c <cert/msc30-c>`, :doc:`misc-predictable-rand <misc/predictable-rand>`,
:doc:`cert-msc32-c <cert/msc32-c>`, :doc:`bugprone-random-generator-seed <bugprone/random-generator-seed>`,
@@ -584,12 +581,12 @@ Check aliases
:doc:`cppcoreguidelines-non-private-member-variables-in-classes <cppcoreguidelines/non-private-member-variables-in-classes>`, :doc:`misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
:doc:`cppcoreguidelines-use-default-member-init <cppcoreguidelines/use-default-member-init>`, :doc:`modernize-use-default-member-init <modernize/use-default-member-init>`, "Yes"
:doc:`fuchsia-header-anon-namespaces <fuchsia/header-anon-namespaces>`, :doc:`google-build-namespaces <google/build-namespaces>`,
- :doc:`google-readability-braces-around-statements <google/readability-braces-around-statements>`, :doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
+ :doc:`google-readability-braces-around-statements <google/readability-braces-around-statements>`, :doc:`readability-braces-around-statements <readability/braces-around-statements>`,
:doc:`google-readability-function-size <google/readability-function-size>`, :doc:`readability-function-size <readability/function-size>`,
:doc:`google-readability-namespace-comments <google/readability-namespace-comments>`, :doc:`llvm-namespace-comment <llvm/namespace-comment>`,
:doc:`hicpp-avoid-c-arrays <hicpp/avoid-c-arrays>`, :doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
:doc:`hicpp-avoid-goto <hicpp/avoid-goto>`, :doc:`cppcoreguidelines-avoid-goto <cppcoreguidelines/avoid-goto>`,
- :doc:`hicpp-braces-around-statements <hicpp/braces-around-statements>`, :doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
+ :doc:`hicpp-braces-around-statements <hicpp/braces-around-statements>`, :doc:`readability-braces-around-statements <readability/braces-around-statements>`,
:doc:`hicpp-deprecated-headers <hicpp/deprecated-headers>`, :doc:`modernize-deprecated-headers <modernize/deprecated-headers>`, "Yes"
:doc:`hicpp-explicit-conversions <hicpp/explicit-conversions>`, :doc:`google-explicit-constructor <google/explicit-constructor>`, "Yes"
:doc:`hicpp-function-size <hicpp/function-size>`, :doc:`readability-function-size <readability/function-size>`,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
new file mode 100644
index 0000000000000..ea7c59e25a55e
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -0,0 +1,145 @@
+// RUN: %check_clang_tidy %s bugprone-smart-ptr-initialization %t
+
+namespace std {
+
+typedef decltype(nullptr) nullptr_t;
+
+template <typename T>
+struct default_delete {
+ void operator()(T* p) const;
+};
+
+template <typename T, typename Deleter = default_delete<T>>
+class unique_ptr {
+public:
+ unique_ptr();
+ explicit unique_ptr(T* p);
+ unique_ptr(T* p, Deleter d) {}
+ unique_ptr(std::nullptr_t);
+
+ T* release();
+
+ void reset(T* p = nullptr);
+
+ template <typename D>
+ void reset(T* p, D d) {}
+};
+
+template <typename T>
+class shared_ptr {
+public:
+ shared_ptr();
+ explicit shared_ptr(T* p);
+ template <typename Deleter>
+ shared_ptr(T* p, Deleter d) {}
+ shared_ptr(std::nullptr_t);
+
+ T* release();
+
+ void reset(T* p = nullptr);
+
+ template <typename Deleter>
+ void reset(T* p, Deleter d) {}
+};
+
+template <typename T>
+shared_ptr<T> make_shared();
+
+template <typename T>
+unique_ptr<T> make_unique();
+
+} // namespace std
+
+struct A {
+ int x;
+};
+
+A& getA();
+A* getAPtr();
+
+// Should trigger the check for shared_ptr constructor
+void test_shared_ptr_constructor() {
+ std::shared_ptr<A> a(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger the check for unique_ptr constructor
+void test_unique_ptr_constructor() {
+ std::unique_ptr<A> b(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger the check for reset() method
+void test_reset_method() {
+ std::shared_ptr<A> sp;
+ sp.reset(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+
+ std::unique_ptr<A> up;
+ up.reset(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for stack variables
+void test_stack_variable() {
+ int x = 5;
+ std::unique_ptr<int> ptr(&x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: passing a raw pointer '&x' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for member variables
+struct S {
+ int member;
+ void test() {
+ std::unique_ptr<int> ptr(&member);
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer '&this->member' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ }
+};
+
+// Should trigger for pointer returned from function
+void test_function_return() {
+ std::shared_ptr<A> sp(getAPtr());
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should NOT trigger for new expressions - these are OK
+void test_new_expression_ok() {
+ std::shared_ptr<A> a(new A());
+ std::unique_ptr<A> b(new A());
+}
+
+// Should NOT trigger for release() calls - ownership transfer
+void test_release_ok() {
+ auto p1 = std::make_unique<A>();
+ std::unique_ptr<A> p2(p1.release());
+
+ auto p3 = std::make_shared<A>();
+ std::shared_ptr<A> p4(p3.release());
+}
+
+// Should NOT trigger for custom deleters
+void test_custom_deleter_ok() {
+ auto noop_deleter = [](A* p) { };
+ std::unique_ptr<A, decltype(noop_deleter)> p1(&getA(), noop_deleter);
+ std::shared_ptr<A> p2(&getA(), noop_deleter);
+}
+
+// Should NOT trigger for nullptr
+void test_nullptr_ok() {
+ std::shared_ptr<A> a(nullptr);
+ std::unique_ptr<A> b(nullptr);
+ std::shared_ptr<A> c;
+ c.reset(nullptr);
+}
+
+// Should NOT trigger for make_shared/make_unique
+void test_make_functions_ok() {
+ auto sp = std::make_shared<A>();
+ auto up = std::make_unique<A>();
+}
+
+// Edge case: should trigger for array new with wrong smart pointer
+void test_array_new() {
+ std::shared_ptr<A> sp(new A[10]); // This is actually wrong but not our check's concern
+ // This would be caught by other checks (mismatched new/delete)
+}
>From 506ab93d2dd5a933bd36c1f0c65d3d77cf9f7b95 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sat, 14 Feb 2026 01:41:16 +0300
Subject: [PATCH 02/33] refactoring && fix nondefault deleter cases
---
.../bugprone/SmartPtrInitializationCheck.cpp | 265 +++++++-----------
.../smart-ptr-initialization/std_smart_ptr.h | 97 +++++++
.../smart-ptr-initialization-array.cpp | 1 +
.../bugprone/smart-ptr-initialization.cpp | 83 +++---
4 files changed, 233 insertions(+), 213 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 392c193918be0..d8e557668c6f6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -8,210 +8,151 @@
#include "SmartPtrInitializationCheck.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Lex/Lexer.h"
-using namespace clang;
using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
namespace {
-AST_MATCHER(Expr, isNewExpression) {
- return isa<CXXNewExpr>(Node);
-}
-
-AST_MATCHER(Expr, isReleaseCall) {
- const auto *call = dyn_cast<CallExpr>(&Node);
- if (!call)
- return false;
-
- const auto *method = dyn_cast<CXXMemberCallExpr>(call);
- if (!method)
+// Helper function to check if a smart pointer record type has a custom deleter
+// based on the record type and number of arguments in the call/constructor
+static bool hasCustomDeleterForRecord(const CXXRecordDecl *Record,
+ unsigned NumArgs) {
+ if (!Record)
return false;
- const auto *member = method->getMethodDecl();
- if (!member)
- return false;
-
- return member->getName() == "release";
-}
-
-AST_MATCHER(Expr, isMakeUniqueOrSharedCall) {
- const auto *call = dyn_cast<CallExpr>(&Node);
- if (!call)
- return false;
-
- const auto *callee = call->getDirectCallee();
- if (!callee)
- return false;
-
- StringRef name = callee->getName();
- if (name != "make_unique" && name != "make_shared")
- return false;
-
- // Check if it's in std namespace by checking the qualified name
- std::string qualifiedName = callee->getQualifiedNameAsString();
- return qualifiedName == "std::make_unique" || qualifiedName == "std::make_shared";
-}
-
-AST_MATCHER(CXXConstructExpr, hasCustomDeleter) {
- if (Node.getNumArgs() < 2)
- return false;
-
- // Check if the second argument is a deleter
- const Expr *deleterArg = Node.getArg(1);
- if (!deleterArg)
- return false;
-
- // Check if this is a smart pointer construction with custom deleter
- const auto *record = Node.getConstructor()->getParent();
- if (!record)
- return false;
+ const std::string typeName = Record->getQualifiedNameAsString();
+ if (typeName == "std::shared_ptr") {
+ // Check if the second argument is a deleter
+ if (NumArgs >= 2)
+ return true;
+ } else if (typeName == "std::unique_ptr") {
+ // Check if the second template argument is a deleter
+ const auto *templateSpec =
+ dyn_cast<ClassTemplateSpecializationDecl>(Record);
+ if (!templateSpec)
+ return false;
+
+ const auto &templateArgs = templateSpec->getTemplateArgs();
+ // unique_ptr has at least 1 template argument (the pointer type)
+ // If it has 2, the second one is the deleter type
+ if (templateArgs.size() >= 2) {
+ const auto &deleterArg = templateArgs[1];
+ // The deleter must be a type
+ if (deleterArg.getKind() == TemplateArgument::Type) {
+ QualType deleterType = deleterArg.getAsType();
+ if (auto *deleterRecord = deleterType->getAsCXXRecordDecl()) {
+ const std::string DeleterTypeName =
+ deleterRecord->getQualifiedNameAsString();
+ if (DeleterTypeName != "std::default_delete")
+ return true;
+ }
+ }
+ }
+ }
- std::string typeName = record->getQualifiedNameAsString();
- return typeName == "std::shared_ptr" || typeName == "std::unique_ptr";
+ return false;
}
-AST_MATCHER(CallExpr, isResetWithCustomDeleter) {
- const auto *memberCall = dyn_cast<CXXMemberCallExpr>(&Node);
- if (!memberCall)
- return false;
+// TODO: all types must be in config
+// TODO: boost::shared_ptr and boost::unique_ptr
+// TODO: reset and release must be in config
+AST_MATCHER(Stmt, hasCustomDeleter) {
+ const auto *constructExpr = dyn_cast<CXXConstructExpr>(&Node);
+ if (constructExpr) {
+ const auto *record = constructExpr->getConstructor()->getParent();
+ return hasCustomDeleterForRecord(record, constructExpr->getNumArgs());
+ }
- const auto *method = memberCall->getMethodDecl();
- if (!method || method->getName() != "reset")
- return false;
+ const auto *callExpr = dyn_cast<CallExpr>(&Node);
+ if (callExpr) {
+ const auto *memberCall = dyn_cast<CXXMemberCallExpr>(callExpr);
+ if (!memberCall)
+ return false;
- if (Node.getNumArgs() < 2)
- return false;
+ const auto *method = memberCall->getMethodDecl();
+ if (!method || method->getName() != "reset")
+ return false;
- const auto *record = method->getParent();
- if (!record)
- return false;
+ const auto *record = method->getParent();
+ return hasCustomDeleterForRecord(record, callExpr->getNumArgs());
+ }
- std::string typeName = record->getQualifiedNameAsString();
- return typeName == "std::shared_ptr" || typeName == "std::unique_ptr";
+ return false;
}
} // namespace
void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
+ auto ReleaseCallMatcher =
+ cxxMemberCallExpr(callee(cxxMethodDecl(hasName("release"))));
// Matcher for smart pointer constructors
- auto smartPtrConstructorMatcher = cxxConstructExpr(
- hasDeclaration(
- cxxConstructorDecl(ofClass(hasAnyName("std::shared_ptr",
- "std::unique_ptr")))),
- hasArgument(0, expr().bind("pointer-arg")),
- unless(hasCustomDeleter()),
- unless(hasArgument(0, isNewExpression())),
- unless(hasArgument(0, isReleaseCall())),
- unless(hasArgument(0, isMakeUniqueOrSharedCall()))
- ).bind("constructor");
+ auto smartPtrConstructorMatcher =
+ cxxConstructExpr(
+ hasDeclaration(cxxConstructorDecl(
+ ofClass(hasAnyName("std::shared_ptr", "std::unique_ptr")),
+ unless(anyOf(isCopyConstructor(), isMoveConstructor())))),
+ hasArgument(0, expr(unless(nullPointerConstant())).bind("pointer-arg")),
+ unless(hasCustomDeleter()), unless(hasArgument(0, cxxNewExpr())),
+ unless(hasArgument(0, ReleaseCallMatcher)))
+ .bind("constructor");
// Matcher for reset() calls
- auto resetCallMatcher = cxxMemberCallExpr(
- on(hasType(cxxRecordDecl(hasAnyName("std::shared_ptr", "std::unique_ptr")))),
- callee(cxxMethodDecl(hasName("reset"))),
- hasArgument(0, expr().bind("pointer-arg")),
- unless(isResetWithCustomDeleter()),
- unless(hasArgument(0, isNewExpression())),
- unless(hasArgument(0, isReleaseCall())),
- unless(hasArgument(0, isMakeUniqueOrSharedCall()))
- ).bind("reset-call");
+ auto resetCallMatcher =
+ cxxMemberCallExpr(on(hasType(cxxRecordDecl(
+ hasAnyName("std::shared_ptr", "std::unique_ptr")))),
+ callee(cxxMethodDecl(hasName("reset"))),
+ hasArgument(0, expr(unless(nullPointerConstant())).bind("pointer-arg")),
+ unless(hasCustomDeleter()),
+ unless(hasArgument(0, cxxNewExpr())),
+ unless(hasArgument(0, ReleaseCallMatcher)))
+ .bind("reset-call");
Finder->addMatcher(smartPtrConstructorMatcher, this);
Finder->addMatcher(resetCallMatcher, this);
}
-void SmartPtrInitializationCheck::check(const MatchFinder::MatchResult &Result) {
+void SmartPtrInitializationCheck::check(
+ const MatchFinder::MatchResult &Result) {
const auto *pointerArg = Result.Nodes.getNodeAs<Expr>("pointer-arg");
- if (!pointerArg)
- return;
-
- // Skip if the pointer is a null pointer
- if (pointerArg->isNullPointerConstant(*Result.Context,
- Expr::NPC_ValueDependentIsNotNull))
- return;
-
- // Check if the expression is a call to a function returning a pointer
- bool isFunctionReturn = false;
- if (const auto *call = dyn_cast<CallExpr>(pointerArg)) {
- if (call->getDirectCallee()) {
- isFunctionReturn = true;
- }
- }
-
- // Check if it's taking address of something
- bool isAddressOf = isa<UnaryOperator>(pointerArg) &&
- cast<UnaryOperator>(pointerArg)->getOpcode() == UO_AddrOf;
-
- // Check if it's getting pointer from reference
- const Expr *innerExpr = pointerArg->IgnoreParenCasts();
- if (const auto *unaryOp = dyn_cast<UnaryOperator>(innerExpr)) {
- if (unaryOp->getOpcode() == UO_AddrOf) {
- isAddressOf = true;
- }
- }
-
- // Also check for member expressions that might return references
- if (const auto *memberExpr = dyn_cast<MemberExpr>(innerExpr)) {
- if (memberExpr->isArrow()) {
- // arrow operator returns pointer, not reference
- isAddressOf = false;
- }
- }
-
- if (isFunctionReturn || isAddressOf) {
- std::string message;
- const SourceLocation loc = pointerArg->getBeginLoc();
-
- if (const auto *constructor =
- Result.Nodes.getNodeAs<CXXConstructExpr>("constructor")) {
- const auto *decl = constructor->getConstructor();
- if (decl) {
- const auto *record = decl->getParent();
- if (record) {
- std::string typeName = record->getQualifiedNameAsString();
- message = "passing a raw pointer '" +
- getPointerDescription(pointerArg, *Result.Context) +
- "' to " + typeName +
- " constructor may cause double deletion";
- }
- }
- } else if (const auto *resetCall =
- Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset-call")) {
- const auto *method = resetCall->getMethodDecl();
- if (method) {
- const auto *record = method->getParent();
- if (record) {
- std::string typeName = record->getQualifiedNameAsString();
- message = "passing a raw pointer '" +
- getPointerDescription(pointerArg, *Result.Context) +
- "' to " + typeName +
- "::reset() may cause double deletion";
- }
- }
- }
-
- if (!message.empty()) {
- diag(loc, message);
+ const auto *constructor =
+ Result.Nodes.getNodeAs<CXXConstructExpr>("constructor");
+ const auto *ResetCall =
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset-call");
+ assert(pointerArg);
+
+ const SourceLocation loc = pointerArg->getBeginLoc();
+ const CXXMethodDecl *MD =
+ constructor ? constructor->getConstructor()
+ : (ResetCall ? ResetCall->getMethodDecl() : nullptr);
+
+ if (MD) {
+ const auto *record = MD->getParent();
+ if (record) {
+ const std::string typeName = record->getQualifiedNameAsString();
+ diag(loc,
+ "passing a raw pointer '%0' to %1%2 may cause double deletion")
+ << getPointerDescription(pointerArg, *Result.Context) << typeName
+ << (constructor ? " constructor" : "::reset()");
}
}
}
-std::string SmartPtrInitializationCheck::getPointerDescription(
- const Expr *PointerExpr, ASTContext &Context) {
+std::string
+SmartPtrInitializationCheck::getPointerDescription(const Expr *PointerExpr,
+ ASTContext &Context) {
std::string Desc;
llvm::raw_string_ostream OS(Desc);
-
+
// Try to get a readable representation of the expression
PrintingPolicy Policy(Context.getLangOpts());
Policy.SuppressSpecifiers = false;
Policy.SuppressTagKeyword = true;
-
+
PointerExpr->printPretty(OS, nullptr, Policy);
return OS.str();
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
new file mode 100644
index 0000000000000..380ee126738a2
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
@@ -0,0 +1,97 @@
+namespace std {
+
+typedef decltype(nullptr) nullptr_t;
+typedef unsigned long size_t;
+
+template <typename T>
+struct default_delete {
+ void operator()(T* p) const;
+};
+
+template <typename T>
+struct default_delete<T[]> {
+ void operator()(T* p) const;
+};
+
+template <typename T, typename Deleter = default_delete<T>>
+class unique_ptr {
+public:
+ unique_ptr();
+ explicit unique_ptr(T* p);
+ unique_ptr(T* p, Deleter d) {}
+ unique_ptr(std::nullptr_t);
+
+ T* release();
+
+ void reset(T* p = nullptr);
+
+ template <typename D>
+ void reset(T* p, D d) {}
+};
+
+template <typename T, typename Deleter>
+class unique_ptr<T[], Deleter> {
+public:
+ unique_ptr();
+ template <typename U>
+ explicit unique_ptr(U* p);
+ template <typename U>
+ unique_ptr(U* p, Deleter d) {}
+ unique_ptr(std::nullptr_t);
+
+ T* release();
+
+ void reset(T* p = nullptr);
+
+ template <typename D>
+ void reset(T* p, D d) {}
+};
+
+template <typename T>
+class shared_ptr {
+public:
+ shared_ptr();
+ explicit shared_ptr(T* p);
+ template <typename Deleter>
+ shared_ptr(T* p, Deleter d) {}
+ shared_ptr(std::nullptr_t);
+
+ T* release();
+
+ void reset(T* p = nullptr);
+
+ template <typename Deleter>
+ void reset(T* p, Deleter d) {}
+};
+
+template <typename T>
+class shared_ptr<T[]> {
+public:
+ shared_ptr();
+ template <typename U>
+ explicit shared_ptr(U* p);
+ template <typename U, typename Deleter>
+ shared_ptr(U* p, Deleter d) {}
+ shared_ptr(std::nullptr_t);
+
+ T* release();
+
+ void reset(T* p = nullptr);
+
+ template <typename Deleter>
+ void reset(T* p, Deleter d) {}
+};
+
+template <typename T>
+shared_ptr<T> make_shared();
+
+template <typename T>
+shared_ptr<T[]> make_shared(std::size_t n);
+
+template <typename T>
+unique_ptr<T> make_unique();
+
+template <typename T>
+unique_ptr<T[]> make_unique(std::size_t n);
+
+} // namespace std
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
new file mode 100644
index 0000000000000..aade2f7a10c6f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
@@ -0,0 +1 @@
+// RUN: %check_clang_tidy %s bugprone-smart-ptr-initialization %t -- -- -I%S
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index ea7c59e25a55e..a9cf0318c97de 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -1,54 +1,6 @@
-// RUN: %check_clang_tidy %s bugprone-smart-ptr-initialization %t
+// RUN: %check_clang_tidy %s bugprone-smart-ptr-initialization %t -- -- -I%S
-namespace std {
-
-typedef decltype(nullptr) nullptr_t;
-
-template <typename T>
-struct default_delete {
- void operator()(T* p) const;
-};
-
-template <typename T, typename Deleter = default_delete<T>>
-class unique_ptr {
-public:
- unique_ptr();
- explicit unique_ptr(T* p);
- unique_ptr(T* p, Deleter d) {}
- unique_ptr(std::nullptr_t);
-
- T* release();
-
- void reset(T* p = nullptr);
-
- template <typename D>
- void reset(T* p, D d) {}
-};
-
-template <typename T>
-class shared_ptr {
-public:
- shared_ptr();
- explicit shared_ptr(T* p);
- template <typename Deleter>
- shared_ptr(T* p, Deleter d) {}
- shared_ptr(std::nullptr_t);
-
- T* release();
-
- void reset(T* p = nullptr);
-
- template <typename Deleter>
- void reset(T* p, Deleter d) {}
-};
-
-template <typename T>
-shared_ptr<T> make_shared();
-
-template <typename T>
-unique_ptr<T> make_unique();
-
-} // namespace std
+#include "Inputs/smart-ptr-initialization/std_smart_ptr.h"
struct A {
int x;
@@ -57,6 +9,8 @@ struct A {
A& getA();
A* getAPtr();
+// TODO: std::shared_ptr<A[]> also must be supported
+
// Should trigger the check for shared_ptr constructor
void test_shared_ptr_constructor() {
std::shared_ptr<A> a(&getA());
@@ -69,17 +23,34 @@ void test_unique_ptr_constructor() {
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
+// TODO: all `reset` tests must be separately
+
// Should trigger the check for reset() method
void test_reset_method() {
std::shared_ptr<A> sp;
sp.reset(&getA());
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
-
+
std::unique_ptr<A> up;
up.reset(&getA());
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
+// Should NOT trigger the check for reset() method with custom deleter
+void test_reset_method_with_custom_deleter() {
+ auto noop_deleter = [](A* p) { };
+ std::shared_ptr<A> sp(nullptr, noop_deleter);
+ std::unique_ptr<A, decltype(noop_deleter)> up(nullptr, noop_deleter);
+
+ sp.reset(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // doesn't have deleter anymore
+
+ sp.reset(&getA(), noop_deleter);
+
+ up.reset(&getA());
+}
+
// Should trigger for stack variables
void test_stack_variable() {
int x = 5;
@@ -104,6 +75,7 @@ void test_function_return() {
// Should NOT trigger for new expressions - these are OK
void test_new_expression_ok() {
+ // TODO: forbid to pass `new A[];`??
std::shared_ptr<A> a(new A());
std::unique_ptr<A> b(new A());
}
@@ -117,9 +89,14 @@ void test_release_ok() {
std::shared_ptr<A> p4(p3.release());
}
+struct NoopDeleter {
+ void operator() (A* p) {}
+};
+
// Should NOT trigger for custom deleters
void test_custom_deleter_ok() {
auto noop_deleter = [](A* p) { };
+ std::unique_ptr<A, NoopDeleter> p0(&getA());
std::unique_ptr<A, decltype(noop_deleter)> p1(&getA(), noop_deleter);
std::shared_ptr<A> p2(&getA(), noop_deleter);
}
@@ -138,6 +115,10 @@ void test_make_functions_ok() {
auto up = std::make_unique<A>();
}
+// TODO: write that this is a job for bugprone-shared-ptr-array-mismatch
+// TODO: the same test, but for smart pointer of array
+// TODO: the same test, but with `release` call
+//
// Edge case: should trigger for array new with wrong smart pointer
void test_array_new() {
std::shared_ptr<A> sp(new A[10]); // This is actually wrong but not our check's concern
>From ab4495950b221d02fb77e7e2a0f7542b25ec9c75 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 01:33:13 +0300
Subject: [PATCH 03/33] refactoring
---
.../bugprone/SmartPtrInitializationCheck.cpp | 127 +++++++-----------
1 file changed, 45 insertions(+), 82 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index d8e557668c6f6..e925b382c277f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -18,98 +18,61 @@ namespace clang::tidy::bugprone {
namespace {
-// Helper function to check if a smart pointer record type has a custom deleter
-// based on the record type and number of arguments in the call/constructor
-static bool hasCustomDeleterForRecord(const CXXRecordDecl *Record,
- unsigned NumArgs) {
- if (!Record)
- return false;
-
- const std::string typeName = Record->getQualifiedNameAsString();
- if (typeName == "std::shared_ptr") {
- // Check if the second argument is a deleter
- if (NumArgs >= 2)
- return true;
- } else if (typeName == "std::unique_ptr") {
- // Check if the second template argument is a deleter
- const auto *templateSpec =
- dyn_cast<ClassTemplateSpecializationDecl>(Record);
- if (!templateSpec)
- return false;
-
- const auto &templateArgs = templateSpec->getTemplateArgs();
- // unique_ptr has at least 1 template argument (the pointer type)
- // If it has 2, the second one is the deleter type
- if (templateArgs.size() >= 2) {
- const auto &deleterArg = templateArgs[1];
- // The deleter must be a type
- if (deleterArg.getKind() == TemplateArgument::Type) {
- QualType deleterType = deleterArg.getAsType();
- if (auto *deleterRecord = deleterType->getAsCXXRecordDecl()) {
- const std::string DeleterTypeName =
- deleterRecord->getQualifiedNameAsString();
- if (DeleterTypeName != "std::default_delete")
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
// TODO: all types must be in config
// TODO: boost::shared_ptr and boost::unique_ptr
// TODO: reset and release must be in config
-AST_MATCHER(Stmt, hasCustomDeleter) {
- const auto *constructExpr = dyn_cast<CXXConstructExpr>(&Node);
- if (constructExpr) {
- const auto *record = constructExpr->getConstructor()->getParent();
- return hasCustomDeleterForRecord(record, constructExpr->getNumArgs());
- }
-
- const auto *callExpr = dyn_cast<CallExpr>(&Node);
- if (callExpr) {
- const auto *memberCall = dyn_cast<CXXMemberCallExpr>(callExpr);
- if (!memberCall)
- return false;
-
- const auto *method = memberCall->getMethodDecl();
- if (!method || method->getName() != "reset")
- return false;
-
- const auto *record = method->getParent();
- return hasCustomDeleterForRecord(record, callExpr->getNumArgs());
- }
-
- return false;
-}
} // namespace
void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
auto ReleaseCallMatcher =
cxxMemberCallExpr(callee(cxxMethodDecl(hasName("release"))));
+
+ auto UniquePtrWithCustomDeleter = classTemplateSpecializationDecl(
+ hasName("std::unique_ptr"), templateArgumentCountIs(2),
+ hasTemplateArgument(1, refersToType(unless(hasDeclaration(cxxRecordDecl(
+ hasName("std::default_delete")))))));
+
// Matcher for smart pointer constructors
+ // Exclude constructors with custom deleters:
+ // - shared_ptr with 2+ arguments (second is deleter)
+ // - unique_ptr with 2+ template args where second is not default_delete
+ auto HasCustomDeleter = anyOf(
+ allOf(hasDeclaration(
+ cxxConstructorDecl(ofClass(hasName("std::shared_ptr")))),
+ hasArgument(1, anything())),
+ hasDeclaration(cxxConstructorDecl(ofClass(UniquePtrWithCustomDeleter))));
+
auto smartPtrConstructorMatcher =
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(
ofClass(hasAnyName("std::shared_ptr", "std::unique_ptr")),
unless(anyOf(isCopyConstructor(), isMoveConstructor())))),
- hasArgument(0, expr(unless(nullPointerConstant())).bind("pointer-arg")),
- unless(hasCustomDeleter()), unless(hasArgument(0, cxxNewExpr())),
+ hasArgument(0,
+ expr(unless(nullPointerConstant())).bind("pointer-arg")),
+ unless(HasCustomDeleter), unless(hasArgument(0, cxxNewExpr())),
unless(hasArgument(0, ReleaseCallMatcher)))
.bind("constructor");
// Matcher for reset() calls
+ // Exclude reset() calls with custom deleters:
+ // - shared_ptr with 2+ arguments (second is deleter)
+ // - unique_ptr with custom deleter type (2+ template args where second is not
+ // default_delete)
+ auto HasCustomDeleterInReset =
+ anyOf(allOf(on(hasType(cxxRecordDecl(hasName("std::shared_ptr")))),
+ hasArgument(1, anything())),
+ on(hasType(qualType(hasDeclaration(UniquePtrWithCustomDeleter)))));
+
auto resetCallMatcher =
- cxxMemberCallExpr(on(hasType(cxxRecordDecl(
- hasAnyName("std::shared_ptr", "std::unique_ptr")))),
- callee(cxxMethodDecl(hasName("reset"))),
- hasArgument(0, expr(unless(nullPointerConstant())).bind("pointer-arg")),
- unless(hasCustomDeleter()),
- unless(hasArgument(0, cxxNewExpr())),
- unless(hasArgument(0, ReleaseCallMatcher)))
+ cxxMemberCallExpr(
+ on(hasType(
+ cxxRecordDecl(hasAnyName("std::shared_ptr", "std::unique_ptr")))),
+ callee(cxxMethodDecl(hasName("reset"))),
+ hasArgument(0,
+ expr(unless(nullPointerConstant())).bind("pointer-arg")),
+ unless(HasCustomDeleterInReset), unless(hasArgument(0, cxxNewExpr())),
+ unless(hasArgument(0, ReleaseCallMatcher)))
.bind("reset-call");
Finder->addMatcher(smartPtrConstructorMatcher, this);
@@ -129,17 +92,17 @@ void SmartPtrInitializationCheck::check(
const CXXMethodDecl *MD =
constructor ? constructor->getConstructor()
: (ResetCall ? ResetCall->getMethodDecl() : nullptr);
+ if (!MD)
+ return;
+
+ const auto *record = MD->getParent();
+ if (!record)
+ return;
- if (MD) {
- const auto *record = MD->getParent();
- if (record) {
- const std::string typeName = record->getQualifiedNameAsString();
- diag(loc,
- "passing a raw pointer '%0' to %1%2 may cause double deletion")
- << getPointerDescription(pointerArg, *Result.Context) << typeName
- << (constructor ? " constructor" : "::reset()");
- }
- }
+ const std::string typeName = record->getQualifiedNameAsString();
+ diag(loc, "passing a raw pointer '%0' to %1%2 may cause double deletion")
+ << getPointerDescription(pointerArg, *Result.Context) << typeName
+ << (constructor ? " constructor" : "::reset()");
}
std::string
>From 1bf34c325e12c5940aabaa5d3685301f4c566a67 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 16:39:10 +0300
Subject: [PATCH 04/33] Improve tests
---
.../smart-ptr-initialization/std_smart_ptr.h | 20 +--
.../smart-ptr-initialization-array-cxx17.cpp | 116 ++++++++++++++++
.../smart-ptr-initialization-array.cpp | 119 ++++++++++++++++-
.../bugprone/smart-ptr-initialization.cpp | 126 +++++++++++-------
4 files changed, 326 insertions(+), 55 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
index 380ee126738a2..afb9a2e95792a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
@@ -82,16 +82,20 @@ class shared_ptr<T[]> {
void reset(T* p, Deleter d) {}
};
-template <typename T>
-shared_ptr<T> make_shared();
+template<typename T>
+ struct remove_reference
+ { using type = T; };
-template <typename T>
-shared_ptr<T[]> make_shared(std::size_t n);
+template<typename T>
+ struct remove_reference<T&>
+ { using type = T; };
-template <typename T>
-unique_ptr<T> make_unique();
+template<typename T>
+ struct remove_reference<T&&>
+ { using type = T; };
-template <typename T>
-unique_ptr<T[]> make_unique(std::size_t n);
+template<typename T>
+ constexpr typename std::remove_reference<T>::type&&
+ move(T&& t) noexcept;
} // namespace std
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
new file mode 100644
index 0000000000000..f679c67188d4e
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
@@ -0,0 +1,116 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-smart-ptr-initialization %t -- -- -I%S
+
+#include "Inputs/smart-ptr-initialization/std_smart_ptr.h"
+
+struct A {
+ int x;
+};
+
+A arr[10];
+
+// Should trigger the check for shared_ptr constructor
+void test_shared_ptr_constructor() {
+ std::shared_ptr<A[]> a(arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for stack variables
+void test_stack_variable() {
+ int x[10] = {5};
+ std::shared_ptr<int[]> ptr(x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer 'x' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for member variables
+struct S {
+ int member[10];
+ void test() {
+ std::shared_ptr<int[]> ptr(member);
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: passing a raw pointer 'this->member' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ }
+};
+
+// Should NOT trigger for new expressions - these are OK
+void test_new_expression_ok() {
+ std::shared_ptr<A[]> a(new A[10]);
+}
+
+// Should NOT trigger for release() calls - ownership transfer
+void test_release_ok(std::shared_ptr<A[]> p3) {
+ std::shared_ptr<A[]> p4(p3.release());
+}
+
+struct NoopDeleter {
+ void operator() (A* p) {}
+};
+
+// Should NOT trigger for custom deleters
+void test_custom_deleter_ok() {
+ auto noop_deleter = [](A* p) { };
+ std::shared_ptr<A[]> p2(arr, noop_deleter);
+}
+
+// Should NOT trigger for nullptr
+void test_nullptr_ok() {
+ std::shared_ptr<A[]> a(nullptr);
+}
+
+// Should NOT trigger for copy and move constructors
+void test_copy_move_constructor_ok(std::shared_ptr<A[]> sp) {
+ auto sp2 = sp;
+ auto sp3 = std::move(sp);
+}
+
+// Should trigger the check for shared_ptr reset
+void test_shared_ptr_reset() {
+ std::shared_ptr<A[]> a;
+ a.reset(arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for stack variables with reset
+void test_stack_variable_reset() {
+ int x[10] = {5};
+ std::shared_ptr<int[]> ptr;
+ ptr.reset(x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should NOT trigger for new expressions with reset - these are OK
+void test_new_expression_reset_ok() {
+ std::shared_ptr<A[]> a;
+ a.reset(new A[10]);
+}
+
+// Should NOT trigger for release() calls with reset - ownership transfer
+void test_release_reset_ok(std::shared_ptr<A[]> p3) {
+ std::shared_ptr<A[]> p4;
+ p4.reset(p3.release());
+}
+
+// Should NOT trigger for custom deleters with reset
+void test_custom_deleter_reset_ok() {
+ auto noop_deleter = [](A* p) { };
+ std::shared_ptr<A[]> p2;
+ p2.reset(arr, noop_deleter);
+}
+
+// Should NOT trigger for nullptr with reset
+void test_nullptr_reset_ok() {
+ std::shared_ptr<A[]> a;
+ a.reset(nullptr);
+}
+
+//
+// Edge case: should trigger for array new with wrong smart pointer
+void test_array_new() {
+ std::shared_ptr<A[]> sp(new A); // This is actually wrong but not our check's concern
+ sp.reset(new A);
+ // This would be caught by bugprone-shared-ptr-array-mismatch checks
+}
+
+void test_array_release(std::shared_ptr<A> spa) {
+ std::shared_ptr<A[]> sp(spa.release()); // This is actually wrong but not our check's concern
+ sp.reset(spa.release());
+ // This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
index aade2f7a10c6f..807d34f126b29 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
@@ -1 +1,118 @@
-// RUN: %check_clang_tidy %s bugprone-smart-ptr-initialization %t -- -- -I%S
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I%S
+
+#include "Inputs/smart-ptr-initialization/std_smart_ptr.h"
+
+struct A {
+ int x;
+};
+
+A arr[10];
+
+// Should trigger the check for unique_ptr constructor
+void test_unique_ptr_constructor() {
+ std::unique_ptr<A[]> b(arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for stack variables
+void test_stack_variable() {
+ int x[10] = {5};
+ std::unique_ptr<int[]> ptr(x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer 'x' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for member variables
+struct S {
+ int member[10];
+ void test() {
+ std::unique_ptr<int[]> ptr(member);
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: passing a raw pointer 'this->member' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ }
+};
+
+// Should NOT trigger for new expressions - these are OK
+void test_new_expression_ok() {
+ std::unique_ptr<A[]> b(new A[10]);
+}
+
+// Should NOT trigger for release() calls - ownership transfer
+void test_release_ok(std::unique_ptr<A[]> p1) {
+ std::unique_ptr<A[]> p2(p1.release());
+}
+
+struct NoopDeleter {
+ void operator() (A* p) {}
+};
+
+// Should NOT trigger for custom deleters
+void test_custom_deleter_ok() {
+ auto noop_deleter = [](A* p) { };
+ std::unique_ptr<A[], NoopDeleter> p0(arr);
+ std::unique_ptr<A[], decltype(noop_deleter)> p1(arr, noop_deleter);
+}
+
+// Should NOT trigger for nullptr
+void test_nullptr_ok() {
+ std::unique_ptr<A[]> b(nullptr);
+}
+
+// Should NOT trigger for copy and move constructors
+void test_copy_move_constructor_ok(std::unique_ptr<A[]> up) {
+ auto up3 = std::move(up);
+}
+
+// Should trigger the check for unique_ptr reset
+void test_unique_ptr_reset() {
+ std::unique_ptr<A[]> b;
+ b.reset(arr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for stack variables with reset
+void test_stack_variable_reset() {
+ int x[10] = {5};
+ std::unique_ptr<int[]> ptr;
+ ptr.reset(x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should NOT trigger for new expressions with reset - these are OK
+void test_new_expression_reset_ok() {
+ std::unique_ptr<A[]> b;
+ b.reset(new A[10]);
+}
+
+// Should NOT trigger for release() calls with reset - ownership transfer
+void test_release_reset_ok(std::unique_ptr<A[]> p1) {
+ std::unique_ptr<A[]> p2;
+ p2.reset(p1.release());
+}
+
+// Should NOT trigger for custom deleters with reset
+void test_custom_deleter_reset_ok() {
+ auto noop_deleter = [](A* p) { };
+ std::unique_ptr<A[], NoopDeleter> p0;
+ p0.reset(arr);
+ std::unique_ptr<A[], decltype(noop_deleter)> p1;
+ p1.reset(arr, noop_deleter);
+}
+
+// Should NOT trigger for nullptr with reset
+void test_nullptr_reset_ok() {
+ std::unique_ptr<A[]> b;
+ b.reset(nullptr);
+}
+
+//
+// Edge case: should trigger for array new with wrong smart pointer
+void test_array_new() {
+ std::unique_ptr<A[]> sp(new A); // This is actually wrong but not our check's concern
+ sp.reset(new A);
+ // This would be caught by bugprone-shared-ptr-array-mismatch checks
+}
+
+void test_array_release(std::unique_ptr<A> spa) {
+ std::unique_ptr<A[]> sp(spa.release()); // This is actually wrong but not our check's concern
+ sp.reset(spa.release());
+ // This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index a9cf0318c97de..a9779c55b26f6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-smart-ptr-initialization %t -- -- -I%S
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I%S
#include "Inputs/smart-ptr-initialization/std_smart_ptr.h"
@@ -9,8 +9,6 @@ struct A {
A& getA();
A* getAPtr();
-// TODO: std::shared_ptr<A[]> also must be supported
-
// Should trigger the check for shared_ptr constructor
void test_shared_ptr_constructor() {
std::shared_ptr<A> a(&getA());
@@ -23,34 +21,6 @@ void test_unique_ptr_constructor() {
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
-// TODO: all `reset` tests must be separately
-
-// Should trigger the check for reset() method
-void test_reset_method() {
- std::shared_ptr<A> sp;
- sp.reset(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
-
- std::unique_ptr<A> up;
- up.reset(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
-}
-
-// Should NOT trigger the check for reset() method with custom deleter
-void test_reset_method_with_custom_deleter() {
- auto noop_deleter = [](A* p) { };
- std::shared_ptr<A> sp(nullptr, noop_deleter);
- std::unique_ptr<A, decltype(noop_deleter)> up(nullptr, noop_deleter);
-
- sp.reset(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
- // doesn't have deleter anymore
-
- sp.reset(&getA(), noop_deleter);
-
- up.reset(&getA());
-}
-
// Should trigger for stack variables
void test_stack_variable() {
int x = 5;
@@ -75,17 +45,13 @@ void test_function_return() {
// Should NOT trigger for new expressions - these are OK
void test_new_expression_ok() {
- // TODO: forbid to pass `new A[];`??
std::shared_ptr<A> a(new A());
std::unique_ptr<A> b(new A());
}
// Should NOT trigger for release() calls - ownership transfer
-void test_release_ok() {
- auto p1 = std::make_unique<A>();
+void test_release_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
std::unique_ptr<A> p2(p1.release());
-
- auto p3 = std::make_shared<A>();
std::shared_ptr<A> p4(p3.release());
}
@@ -105,22 +71,90 @@ void test_custom_deleter_ok() {
void test_nullptr_ok() {
std::shared_ptr<A> a(nullptr);
std::unique_ptr<A> b(nullptr);
- std::shared_ptr<A> c;
- c.reset(nullptr);
}
-// Should NOT trigger for make_shared/make_unique
-void test_make_functions_ok() {
- auto sp = std::make_shared<A>();
- auto up = std::make_unique<A>();
+// Should NOT trigger for copy and move constructors
+void test_copy_move_constructor_ok(std::shared_ptr<A> sp, std::unique_ptr<A> up) {
+ auto sp2 = sp;
+
+ auto sp3 = std::move(sp);
+ auto up3 = std::move(up);
+}
+
+// Should trigger the check for shared_ptr reset
+void test_shared_ptr_reset() {
+ std::shared_ptr<A> a;
+ a.reset(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger the check for unique_ptr reset
+void test_unique_ptr_reset() {
+ std::unique_ptr<A> b;
+ b.reset(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for stack variables with reset
+void test_stack_variable_reset() {
+ int x = 5;
+ std::unique_ptr<int> ptr;
+ ptr.reset(&x);
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer '&x' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should trigger for pointer returned from function with reset
+void test_function_return_reset() {
+ std::shared_ptr<A> sp;
+ sp.reset(getAPtr());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+// Should NOT trigger for new expressions with reset - these are OK
+void test_new_expression_reset_ok() {
+ std::shared_ptr<A> a;
+ a.reset(new A());
+ std::unique_ptr<A> b;
+ b.reset(new A());
+}
+
+// Should NOT trigger for release() calls with reset - ownership transfer
+void test_release_reset_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
+ std::unique_ptr<A> p2;
+ p2.reset(p1.release());
+ std::shared_ptr<A> p4;
+ p4.reset(p3.release());
+}
+
+// Should NOT trigger for custom deleters with reset
+void test_custom_deleter_reset_ok() {
+ auto noop_deleter = [](A* p) { };
+ std::unique_ptr<A, NoopDeleter> p0;
+ p0.reset(&getA());
+ std::unique_ptr<A, decltype(noop_deleter)> p1;
+ p1.reset(&getA(), noop_deleter);
+ std::shared_ptr<A> p2;
+ p2.reset(&getA(), noop_deleter);
+}
+
+// Should NOT trigger for nullptr with reset
+void test_nullptr_reset_ok() {
+ std::shared_ptr<A> a;
+ a.reset(nullptr);
+ std::unique_ptr<A> b;
+ b.reset(nullptr);
}
-// TODO: write that this is a job for bugprone-shared-ptr-array-mismatch
-// TODO: the same test, but for smart pointer of array
-// TODO: the same test, but with `release` call
//
// Edge case: should trigger for array new with wrong smart pointer
void test_array_new() {
std::shared_ptr<A> sp(new A[10]); // This is actually wrong but not our check's concern
- // This would be caught by other checks (mismatched new/delete)
+ sp.reset(new A[10]);
+ // This would be caught by bugprone-shared-ptr-array-mismatch checks
+}
+
+void test_array_release(std::shared_ptr<A[]> spa) {
+ std::shared_ptr<A> sp(spa.release()); // This is actually wrong but not our check's concern
+ sp.reset(spa.release());
+ // This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
}
>From bc05c23dbb6606443045aeffb42bc526da60f3e4 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 17:36:49 +0300
Subject: [PATCH 05/33] Introduce options
---
.../bugprone/SmartPtrInitializationCheck.cpp | 51 ++++++++++++++-----
.../bugprone/SmartPtrInitializationCheck.h | 7 ++-
2 files changed, 44 insertions(+), 14 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index e925b382c277f..89f698ccd38c4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "SmartPtrInitializationCheck.h"
+#include "../utils/OptionsUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -18,35 +19,62 @@ namespace clang::tidy::bugprone {
namespace {
-// TODO: all types must be in config
-// TODO: boost::shared_ptr and boost::unique_ptr
-// TODO: reset and release must be in config
+const auto DefaultSharedPointers = "::std::shared_ptr;::boost::shared_ptr";
+const auto DefaultUniquePointers = "::std::unique_ptr";
+const auto DefaultDefaultDeleters = "::std::default_delete";
} // namespace
+SmartPtrInitializationCheck::SmartPtrInitializationCheck(
+ StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ SharedPointers(utils::options::parseStringList(
+ Options.get("SharedPointers", DefaultSharedPointers))),
+ UniquePointers(utils::options::parseStringList(
+ Options.get("UniquePointers", DefaultUniquePointers))),
+ DefaultDeleters(utils::options::parseStringList(
+ Options.get("DefaultDeleters", DefaultDefaultDeleters))) {}
+
+void SmartPtrInitializationCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "SharedPointers",
+ utils::options::serializeStringList(SharedPointers));
+ Options.store(Opts, "UniquePointers",
+ utils::options::serializeStringList(UniquePointers));
+ Options.store(Opts, "DefaultDeleters",
+ utils::options::serializeStringList(DefaultDeleters));
+}
+
void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
auto ReleaseCallMatcher =
cxxMemberCallExpr(callee(cxxMethodDecl(hasName("release"))));
+ // Build matchers for the smart pointer types
+ auto SharedPtrMatcher = hasAnyName(SharedPointers);
+ auto UniquePtrMatcher = hasAnyName(UniquePointers);
+ auto AllSmartPtrMatcher = anyOf(SharedPtrMatcher, UniquePtrMatcher);
+
+ // Matcher for unique_ptr types with custom deleters
+ auto DefaultDeleterMatcher = hasAnyName(DefaultDeleters);
auto UniquePtrWithCustomDeleter = classTemplateSpecializationDecl(
- hasName("std::unique_ptr"), templateArgumentCountIs(2),
- hasTemplateArgument(1, refersToType(unless(hasDeclaration(cxxRecordDecl(
- hasName("std::default_delete")))))));
+ UniquePtrMatcher, templateArgumentCountIs(2),
+ hasTemplateArgument(1, refersToType(unless(hasDeclaration(cxxRecordDecl(
+ DefaultDeleterMatcher))))));
// Matcher for smart pointer constructors
// Exclude constructors with custom deleters:
// - shared_ptr with 2+ arguments (second is deleter)
// - unique_ptr with 2+ template args where second is not default_delete
auto HasCustomDeleter = anyOf(
- allOf(hasDeclaration(
- cxxConstructorDecl(ofClass(hasName("std::shared_ptr")))),
+ allOf(hasDeclaration(cxxConstructorDecl(
+ ofClass(SharedPtrMatcher))),
hasArgument(1, anything())),
hasDeclaration(cxxConstructorDecl(ofClass(UniquePtrWithCustomDeleter))));
auto smartPtrConstructorMatcher =
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(
- ofClass(hasAnyName("std::shared_ptr", "std::unique_ptr")),
+ ofClass(AllSmartPtrMatcher),
unless(anyOf(isCopyConstructor(), isMoveConstructor())))),
hasArgument(0,
expr(unless(nullPointerConstant())).bind("pointer-arg")),
@@ -60,14 +88,13 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
// - unique_ptr with custom deleter type (2+ template args where second is not
// default_delete)
auto HasCustomDeleterInReset =
- anyOf(allOf(on(hasType(cxxRecordDecl(hasName("std::shared_ptr")))),
+ anyOf(allOf(on(hasType(cxxRecordDecl(SharedPtrMatcher))),
hasArgument(1, anything())),
on(hasType(qualType(hasDeclaration(UniquePtrWithCustomDeleter)))));
auto resetCallMatcher =
cxxMemberCallExpr(
- on(hasType(
- cxxRecordDecl(hasAnyName("std::shared_ptr", "std::unique_ptr")))),
+ on(hasType(cxxRecordDecl(AllSmartPtrMatcher))),
callee(cxxMethodDecl(hasName("reset"))),
hasArgument(0,
expr(unless(nullPointerConstant())).bind("pointer-arg")),
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
index b21774b6b0806..d46a48242cf20 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -20,14 +20,17 @@ namespace clang::tidy::bugprone {
/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/smart-ptr-initialization.html
class SmartPtrInitializationCheck : public ClangTidyCheck {
public:
- SmartPtrInitializationCheck(StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context) {}
+ SmartPtrInitializationCheck(StringRef Name, ClangTidyContext *Context);
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
private:
std::string getPointerDescription(const Expr *PointerExpr,
ASTContext &Context);
+ const std::vector<StringRef> SharedPointers;
+ const std::vector<StringRef> UniquePointers;
+ const std::vector<StringRef> DefaultDeleters;
};
} // namespace clang::tidy::bugprone
>From f32db1c4f0babe2ad78b3be05b10233489dd314f Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 17:44:53 +0300
Subject: [PATCH 06/33] Refactoring the code following LLVM Code style
---
.../bugprone/SmartPtrInitializationCheck.cpp | 45 +++++++++----------
.../bugprone/SmartPtrInitializationCheck.h | 4 +-
2 files changed, 24 insertions(+), 25 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 89f698ccd38c4..10896e80ba80f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -58,20 +58,19 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
auto DefaultDeleterMatcher = hasAnyName(DefaultDeleters);
auto UniquePtrWithCustomDeleter = classTemplateSpecializationDecl(
UniquePtrMatcher, templateArgumentCountIs(2),
- hasTemplateArgument(1, refersToType(unless(hasDeclaration(cxxRecordDecl(
- DefaultDeleterMatcher))))));
+ hasTemplateArgument(1, refersToType(unless(hasDeclaration(
+ cxxRecordDecl(DefaultDeleterMatcher))))));
// Matcher for smart pointer constructors
// Exclude constructors with custom deleters:
// - shared_ptr with 2+ arguments (second is deleter)
// - unique_ptr with 2+ template args where second is not default_delete
auto HasCustomDeleter = anyOf(
- allOf(hasDeclaration(cxxConstructorDecl(
- ofClass(SharedPtrMatcher))),
+ allOf(hasDeclaration(cxxConstructorDecl(ofClass(SharedPtrMatcher))),
hasArgument(1, anything())),
hasDeclaration(cxxConstructorDecl(ofClass(UniquePtrWithCustomDeleter))));
- auto smartPtrConstructorMatcher =
+ auto SmartPtrConstructorMatcher =
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(
ofClass(AllSmartPtrMatcher),
@@ -92,7 +91,7 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
hasArgument(1, anything())),
on(hasType(qualType(hasDeclaration(UniquePtrWithCustomDeleter)))));
- auto resetCallMatcher =
+ auto ResetCallMatcher =
cxxMemberCallExpr(
on(hasType(cxxRecordDecl(AllSmartPtrMatcher))),
callee(cxxMethodDecl(hasName("reset"))),
@@ -102,41 +101,41 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
unless(hasArgument(0, ReleaseCallMatcher)))
.bind("reset-call");
- Finder->addMatcher(smartPtrConstructorMatcher, this);
- Finder->addMatcher(resetCallMatcher, this);
+ Finder->addMatcher(SmartPtrConstructorMatcher, this);
+ Finder->addMatcher(ResetCallMatcher, this);
}
void SmartPtrInitializationCheck::check(
const MatchFinder::MatchResult &Result) {
- const auto *pointerArg = Result.Nodes.getNodeAs<Expr>("pointer-arg");
- const auto *constructor =
+ const auto *PointerArg = Result.Nodes.getNodeAs<Expr>("pointer-arg");
+ const auto *Constructor =
Result.Nodes.getNodeAs<CXXConstructExpr>("constructor");
const auto *ResetCall =
Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset-call");
- assert(pointerArg);
+ assert(PointerArg);
- const SourceLocation loc = pointerArg->getBeginLoc();
- const CXXMethodDecl *MD =
- constructor ? constructor->getConstructor()
+ const SourceLocation Loc = PointerArg->getBeginLoc();
+ const CXXMethodDecl *MethodDecl =
+ Constructor ? Constructor->getConstructor()
: (ResetCall ? ResetCall->getMethodDecl() : nullptr);
- if (!MD)
+ if (!MethodDecl)
return;
- const auto *record = MD->getParent();
- if (!record)
+ const auto *Record = MethodDecl->getParent();
+ if (!Record)
return;
- const std::string typeName = record->getQualifiedNameAsString();
- diag(loc, "passing a raw pointer '%0' to %1%2 may cause double deletion")
- << getPointerDescription(pointerArg, *Result.Context) << typeName
- << (constructor ? " constructor" : "::reset()");
+ const std::string TypeName = Record->getQualifiedNameAsString();
+ diag(Loc, "passing a raw pointer '%0' to %1%2 may cause double deletion")
+ << getPointerDescription(PointerArg, *Result.Context) << TypeName
+ << (Constructor ? " constructor" : "::reset()");
}
std::string
SmartPtrInitializationCheck::getPointerDescription(const Expr *PointerExpr,
ASTContext &Context) {
- std::string Desc;
- llvm::raw_string_ostream OS(Desc);
+ std::string Description;
+ llvm::raw_string_ostream OS(Description);
// Try to get a readable representation of the expression
PrintingPolicy Policy(Context.getLangOpts());
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
index d46a48242cf20..e8814387d0bc4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -26,7 +26,7 @@ class SmartPtrInitializationCheck : public ClangTidyCheck {
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
private:
- std::string getPointerDescription(const Expr *PointerExpr,
+ std::string getPointerDescription(const Expr *PointerExpr,
ASTContext &Context);
const std::vector<StringRef> SharedPointers;
const std::vector<StringRef> UniquePointers;
@@ -35,4 +35,4 @@ class SmartPtrInitializationCheck : public ClangTidyCheck {
} // namespace clang::tidy::bugprone
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRINITIALIZATIONCHECK_H
\ No newline at end of file
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRINITIALIZATIONCHECK_H
>From b3670d28885f110a24b52ad90aac106cc08f7c07 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 17:48:54 +0300
Subject: [PATCH 07/33] remove redundant change
---
clang-tools-extra/docs/clang-tidy/checks/list.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index aa4d8106eef9a..a21d986e3a02b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -626,4 +626,4 @@ Check aliases
:doc:`hicpp-use-override <hicpp/use-override>`, :doc:`modernize-use-override <modernize/use-override>`, "Yes"
:doc:`hicpp-vararg <hicpp/vararg>`, :doc:`cppcoreguidelines-pro-type-vararg <cppcoreguidelines/pro-type-vararg>`,
:doc:`llvm-else-after-return <llvm/else-after-return>`, :doc:`readability-else-after-return <readability/else-after-return>`, "Yes"
- :doc:`llvm-qualified-auto <llvm/qualified-auto>`, :doc:`readability-qualified-auto <readability/qualified-auto>`, "Yes"
\ No newline at end of file
+ :doc:`llvm-qualified-auto <llvm/qualified-auto>`, :doc:`readability-qualified-auto <readability/qualified-auto>`, "Yes"
>From 189fbd3b25ae9a7d3f0751ba17cf2b69e5a1983b Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 18:07:52 +0300
Subject: [PATCH 08/33] Add alias in CERT module
---
clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp | 3 +++
clang-tools-extra/docs/ReleaseNotes.rst | 5 +++++
.../docs/clang-tidy/checks/cert/mem56-cpp.rst | 10 ++++++++++
3 files changed, 18 insertions(+)
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index f64cb47d18b4e..32d273c374511 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -21,6 +21,7 @@
#include "../bugprone/SignalHandlerCheck.h"
#include "../bugprone/SignedCharMisuseCheck.h"
#include "../bugprone/SizeofExpressionCheck.h"
+#include "../bugprone/SmartPtrInitializationCheck.h"
#include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h"
#include "../bugprone/StdNamespaceModificationCheck.h"
#include "../bugprone/SuspiciousMemoryComparisonCheck.h"
@@ -267,6 +268,8 @@ class CERTModule : public ClangTidyModule {
CheckFactories.registerCheck<misc::ThrowByValueCatchByReferenceCheck>(
"cert-err61-cpp");
// MEM
+ CheckFactories.registerCheck<bugprone::SmartPtrInitializationCheck>(
+ "cert-mem56-cpp");
CheckFactories
.registerCheck<bugprone::DefaultOperatorNewOnOveralignedTypeCheck>(
"cert-mem57-cpp");
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 64098142025e4..ee3ec09825535 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -142,6 +142,11 @@ New checks
New check aliases
^^^^^^^^^^^^^^^^^
+- New alias :doc:`cert-mem56-cpp <clang-tidy/checks/cert/mem56-cpp>` to
+ :doc:`bugprone-smart-ptr-initialization
+ <clang-tidy/checks/bugprone/smart-ptr-initialization>`
+ was added.
+
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
new file mode 100644
index 0000000000000..6858b4d1e4c11
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-mem56-cpp
+.. meta::
+ :http-equiv=refresh: 5;URL=../bugprone/smart-ptr-initialization.html
+
+cert-mem56-cpp
+==============
+
+The `cert-mem56-cpp` check is an alias, please see
+:doc:`bugprone-smart-ptr-initialization.html
+<../bugprone/smart-ptr-initialization.html>` for more information.
>From 7d4a64c4c5daf9b8f8bf3bffac342c2e6a25b7e9 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 22:04:56 +0300
Subject: [PATCH 09/33] refactoring
---
.../bugprone/SmartPtrInitializationCheck.cpp | 55 ++++++++++++-------
1 file changed, 35 insertions(+), 20 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 10896e80ba80f..24d590e5b9b96 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -46,37 +46,48 @@ void SmartPtrInitializationCheck::storeOptions(
}
void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
+ const auto IsSharedPtr = hasAnyName(SharedPointers);
+ const auto IsUniquePtr = hasAnyName(UniquePointers);
+ const auto IsSmartPtr = anyOf(IsSharedPtr, IsUniquePtr);
+ const auto IsDefaultDeleter = hasAnyName(DefaultDeleters);
+
+ const auto IsSharedPtrRecord = cxxRecordDecl(IsSharedPtr);
+ const auto IsUniquePtrRecord = cxxRecordDecl(IsUniquePtr);
+ const auto IsSmartPtrRecord = cxxRecordDecl(IsSmartPtr);
+
+ auto ReleaseMethod = cxxMethodDecl(hasName("release"));
+ auto ResetMethod = cxxMethodDecl(hasName("reset"));
+
auto ReleaseCallMatcher =
- cxxMemberCallExpr(callee(cxxMethodDecl(hasName("release"))));
+ cxxMemberCallExpr(callee(ReleaseMethod));
- // Build matchers for the smart pointer types
- auto SharedPtrMatcher = hasAnyName(SharedPointers);
- auto UniquePtrMatcher = hasAnyName(UniquePointers);
- auto AllSmartPtrMatcher = anyOf(SharedPtrMatcher, UniquePtrMatcher);
+ auto PointerArg = expr(unless(nullPointerConstant())).bind("pointer-arg");
// Matcher for unique_ptr types with custom deleters
- auto DefaultDeleterMatcher = hasAnyName(DefaultDeleters);
auto UniquePtrWithCustomDeleter = classTemplateSpecializationDecl(
- UniquePtrMatcher, templateArgumentCountIs(2),
- hasTemplateArgument(1, refersToType(unless(hasDeclaration(
- cxxRecordDecl(DefaultDeleterMatcher))))));
+ IsUniquePtr, templateArgumentCountIs(2),
+ hasTemplateArgument(1, refersToType(unless(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(
+ classTemplateSpecializationDecl(
+ IsDefaultDeleter))))))));
// Matcher for smart pointer constructors
// Exclude constructors with custom deleters:
// - shared_ptr with 2+ arguments (second is deleter)
// - unique_ptr with 2+ template args where second is not default_delete
auto HasCustomDeleter = anyOf(
- allOf(hasDeclaration(cxxConstructorDecl(ofClass(SharedPtrMatcher))),
+ allOf(hasDeclaration(cxxConstructorDecl(ofClass(IsSharedPtrRecord))),
hasArgument(1, anything())),
- hasDeclaration(cxxConstructorDecl(ofClass(UniquePtrWithCustomDeleter))));
+ allOf(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(UniquePtrWithCustomDeleter)))),
+ hasDeclaration(cxxConstructorDecl(ofClass(IsUniquePtrRecord)))));
auto SmartPtrConstructorMatcher =
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(
- ofClass(AllSmartPtrMatcher),
+ ofClass(IsSmartPtrRecord),
unless(anyOf(isCopyConstructor(), isMoveConstructor())))),
- hasArgument(0,
- expr(unless(nullPointerConstant())).bind("pointer-arg")),
+ hasArgument(0, PointerArg),
unless(HasCustomDeleter), unless(hasArgument(0, cxxNewExpr())),
unless(hasArgument(0, ReleaseCallMatcher)))
.bind("constructor");
@@ -87,16 +98,20 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
// - unique_ptr with custom deleter type (2+ template args where second is not
// default_delete)
auto HasCustomDeleterInReset =
- anyOf(allOf(on(hasType(cxxRecordDecl(SharedPtrMatcher))),
+ anyOf(allOf(on(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(
+ classTemplateSpecializationDecl(IsSharedPtr)))))),
hasArgument(1, anything())),
- on(hasType(qualType(hasDeclaration(UniquePtrWithCustomDeleter)))));
+ on(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(UniquePtrWithCustomDeleter))))));
auto ResetCallMatcher =
cxxMemberCallExpr(
- on(hasType(cxxRecordDecl(AllSmartPtrMatcher))),
- callee(cxxMethodDecl(hasName("reset"))),
- hasArgument(0,
- expr(unless(nullPointerConstant())).bind("pointer-arg")),
+ on(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(
+ classTemplateSpecializationDecl(IsSmartPtr)))))),
+ callee(ResetMethod),
+ hasArgument(0, PointerArg),
unless(HasCustomDeleterInReset), unless(hasArgument(0, cxxNewExpr())),
unless(hasArgument(0, ReleaseCallMatcher)))
.bind("reset-call");
>From f75e966618bb7e2cefffa56ccf038860de607d5a Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 22:06:39 +0300
Subject: [PATCH 10/33] Fix && apply format
---
.../bugprone/SmartPtrInitializationCheck.cpp | 44 +++++++++----------
1 file changed, 20 insertions(+), 24 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 24d590e5b9b96..786d949903d7a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -58,18 +58,19 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
auto ReleaseMethod = cxxMethodDecl(hasName("release"));
auto ResetMethod = cxxMethodDecl(hasName("reset"));
- auto ReleaseCallMatcher =
- cxxMemberCallExpr(callee(ReleaseMethod));
+ auto ReleaseCallMatcher = cxxMemberCallExpr(callee(ReleaseMethod));
- auto PointerArg = expr(unless(nullPointerConstant())).bind("pointer-arg");
+ // Array automatically decays to pointer
+ auto PointerArg = expr(anyOf(hasType(pointerType()), hasType(arrayType())))
+ .bind("pointer-arg");
// Matcher for unique_ptr types with custom deleters
auto UniquePtrWithCustomDeleter = classTemplateSpecializationDecl(
IsUniquePtr, templateArgumentCountIs(2),
- hasTemplateArgument(1, refersToType(unless(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(
- classTemplateSpecializationDecl(
- IsDefaultDeleter))))))));
+ hasTemplateArgument(
+ 1, refersToType(
+ unless(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+ classTemplateSpecializationDecl(IsDefaultDeleter))))))));
// Matcher for smart pointer constructors
// Exclude constructors with custom deleters:
@@ -84,11 +85,9 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
auto SmartPtrConstructorMatcher =
cxxConstructExpr(
- hasDeclaration(cxxConstructorDecl(
- ofClass(IsSmartPtrRecord),
- unless(anyOf(isCopyConstructor(), isMoveConstructor())))),
- hasArgument(0, PointerArg),
- unless(HasCustomDeleter), unless(hasArgument(0, cxxNewExpr())),
+ hasDeclaration(cxxConstructorDecl(ofClass(IsSmartPtrRecord))),
+ hasArgument(0, PointerArg), unless(HasCustomDeleter),
+ unless(hasArgument(0, cxxNewExpr())),
unless(hasArgument(0, ReleaseCallMatcher)))
.bind("constructor");
@@ -97,21 +96,18 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
// - shared_ptr with 2+ arguments (second is deleter)
// - unique_ptr with custom deleter type (2+ template args where second is not
// default_delete)
- auto HasCustomDeleterInReset =
- anyOf(allOf(on(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(
- classTemplateSpecializationDecl(IsSharedPtr)))))),
- hasArgument(1, anything())),
- on(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(UniquePtrWithCustomDeleter))))));
+ auto HasCustomDeleterInReset = anyOf(
+ allOf(on(hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+ classTemplateSpecializationDecl(IsSharedPtr)))))),
+ hasArgument(1, anything())),
+ on(hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(UniquePtrWithCustomDeleter))))));
auto ResetCallMatcher =
cxxMemberCallExpr(
- on(hasType(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(
- classTemplateSpecializationDecl(IsSmartPtr)))))),
- callee(ResetMethod),
- hasArgument(0, PointerArg),
+ on(hasType(hasUnqualifiedDesugaredType(recordType(
+ hasDeclaration(classTemplateSpecializationDecl(IsSmartPtr)))))),
+ callee(ResetMethod), hasArgument(0, PointerArg),
unless(HasCustomDeleterInReset), unless(hasArgument(0, cxxNewExpr())),
unless(hasArgument(0, ReleaseCallMatcher)))
.bind("reset-call");
>From e141347c5980211a976267e8bbd8049feebf07c1 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 23:08:20 +0300
Subject: [PATCH 11/33] Docs by DeepSeek
---
clang-tools-extra/docs/ReleaseNotes.rst | 3 +-
.../bugprone/smart-ptr-initialization.rst | 104 +++++++++++++++++-
2 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index ee3ec09825535..e3c3ea6cc648d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -100,7 +100,8 @@ New checks
- New :doc:`bugprone-smart-ptr-initialization
<clang-tidy/checks/bugprone/smart-ptr-initialization>` check.
- FIXME: Write a short description.
+ Detects dangerous initialization of smart pointers with raw pointers that are
+ already owned elsewhere, which can lead to double deletion.
- New :doc:`llvm-type-switch-case-types
<clang-tidy/checks/llvm/type-switch-case-types>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
index ed72c6b1b92b1..b3b4bb9ca60e7 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
@@ -1,6 +1,106 @@
.. title:: clang-tidy - bugprone-smart-ptr-initialization
bugprone-smart-ptr-initialization
-=================================
+==================================
-FIXME: Describe what patterns does the check detect and why. Give examples.
+Detects dangerous initialization of smart pointers with raw pointers that are
+already owned elsewhere, which can lead to double deletion.
+
+This check implements CERT C++ rule `MEM56-CPP. Do not store an already-owned
+pointer value in an unrelated smart pointer
+<https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer>`_.
+
+Examples
+--------
+
+The check flags cases where raw pointers that are already owned or managed
+elsewhere are passed to smart pointer constructors or ``reset()`` methods:
+
+.. code-block:: c++
+
+ A& getA();
+ void foo() {
+ // Warning: '&getA()' is already managed elsewhere
+ std::shared_ptr<A> a(&getA());
+ }
+
+ void bar() {
+ int x = 10;
+ // Warning: '&x' points to a local variable
+ std::unique_ptr<int> ptr(&x);
+ }
+
+ void baz() {
+ std::vector<int> vec{1, 2, 3};
+ std::shared_ptr<int> sp;
+ // Warning: '&vec[0]' is managed by the vector
+ sp.reset(&vec[0]);
+ }
+
+Allowed cases
+-------------
+
+The check ignores legitimate cases:
+
+1. **New expressions**: Pointers from ``new`` operators are safe:
+
+ .. code-block:: c++
+
+ std::unique_ptr<int> p(new int(5)); // OK
+
+2. **Release calls**: Pointers from ``release()`` method are transferred:
+
+ .. code-block:: c++
+
+ auto p1 = std::make_unique<int>(5);
+ std::unique_ptr<int> p2(p1.release()); // OK
+
+3. **Custom deleters**: Smart pointers with custom deleters are ignored:
+
+ .. code-block:: c++
+
+ void customDeleter(int* p) { delete p; }
+ std::unique_ptr<int, decltype(&customDeleter)> p(&getA(), customDeleter);
+
+4. **Null pointers**: ``nullptr`` is always safe:
+
+ .. code-block:: c++
+
+ std::shared_ptr<int> p(nullptr); // OK
+ p.reset(nullptr); // OK
+
+Options
+-------
+
+.. option:: SharedPointers
+
+ A semicolon-separated list of (fully qualified) shared pointer type names
+ that should be checked. Default value is
+ `::std::shared_ptr;::boost::shared_ptr`.
+
+.. option:: UniquePointers
+
+ A semicolon-separated list of (fully qualified) unique pointer type names
+ that should be checked. Default value is
+ `::std::unique_ptr`.
+
+.. option:: DefaultDeleters
+
+ A semicolon-separated list of (fully qualified) default deleter type names.
+ Smart pointers with deleters matching these types are considered to use the
+ default deleter and are checked. Smart pointers with custom deleters are
+ ignored. Default value is `::std::default_delete`.
+
+Limitations
+----------
+
+This check only supports smart pointers with shared and unique ownership
+semantics. Smart pointers with different semantics, such as
+``boost::scoped_ptr``, cannot be used with the current version of this check.
+
+References
+----------
+
+* `CERT C++ MEM56-CPP <https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer>`_
+* `C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-ptr>`_
+* `C++ Core Guidelines R.20: Use unique_ptr or shared_ptr to represent ownership <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner>`_
>From 4f77a71e80faabda753e8023db6fb9e125d2b732 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 23:20:05 +0300
Subject: [PATCH 12/33] fix links
---
.../clang-tidy/checks/bugprone/smart-ptr-initialization.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
index b3b4bb9ca60e7..f50ac44f7d109 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
@@ -102,5 +102,5 @@ References
----------
* `CERT C++ MEM56-CPP <https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer>`_
-* `C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-ptr>`_
-* `C++ Core Guidelines R.20: Use unique_ptr or shared_ptr to represent ownership <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-owner>`_
+* `C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership>`_
+* `C++ Core Guidelines R.20: Use unique_ptr or shared_ptr to represent ownership <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership>`_
>From 4f19e1fbbd22d19aeee7e67a6a3b2d0a4dd417ee Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 23:23:05 +0300
Subject: [PATCH 13/33] fix link
---
.../clang-tidy/checks/bugprone/smart-ptr-initialization.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
index f50ac44f7d109..fc0249e197961 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
@@ -102,5 +102,5 @@ References
----------
* `CERT C++ MEM56-CPP <https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer>`_
-* `C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership>`_
+* `C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r3-a-raw-pointer-a-t-is-non-owning>`_
* `C++ Core Guidelines R.20: Use unique_ptr or shared_ptr to represent ownership <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership>`_
>From 5ec9e69a4f88f811af9f3a6dace246c01c3d170d Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sun, 15 Feb 2026 23:47:43 +0300
Subject: [PATCH 14/33] lint
---
.../clang-tidy/checks/bugprone/smart-ptr-initialization.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
index fc0249e197961..f1cce7e97c0fd 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
@@ -92,7 +92,7 @@ Options
ignored. Default value is `::std::default_delete`.
Limitations
-----------
+-----------
This check only supports smart pointers with shared and unique ownership
semantics. Smart pointers with different semantics, such as
>From b9084da7a53656f1f18f2945c6db565066a9840b Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 16 Feb 2026 00:04:17 +0300
Subject: [PATCH 15/33] fix for building docs
---
clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
index 6858b4d1e4c11..2ca3a0f075321 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
@@ -6,5 +6,4 @@ cert-mem56-cpp
==============
The `cert-mem56-cpp` check is an alias, please see
-:doc:`bugprone-smart-ptr-initialization.html
-<../bugprone/smart-ptr-initialization.html>` for more information.
+:doc:`bugprone-smart-ptr-initialization <../bugprone/smart-ptr-initialization>` for more information.
>From c8eb4816f9d6aa296215abd3ab9c3f670e4eaf61 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Mon, 16 Feb 2026 00:11:10 +0300
Subject: [PATCH 16/33] lint
---
clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
index 2ca3a0f075321..c822756ad921b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
@@ -6,4 +6,5 @@ cert-mem56-cpp
==============
The `cert-mem56-cpp` check is an alias, please see
-:doc:`bugprone-smart-ptr-initialization <../bugprone/smart-ptr-initialization>` for more information.
+:doc:`bugprone-smart-ptr-initialization <../bugprone/smart-ptr-initialization>`
+for more information.
>From 06bbf31f52c3ab2e8d7910c48b15e09d802169ea Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Thu, 6 Aug 2026 18:48:42 +0300
Subject: [PATCH 17/33] Fixes for last merge commit
---
.../docs/clang-tidy/checks/list.md | 2 +
.../docs/clang-tidy/checks/list.rst | 629 ------------------
2 files changed, 2 insertions(+), 629 deletions(-)
delete mode 100644 clang-tools-extra/docs/clang-tidy/checks/list.rst
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md
index 12d8a48ee8d86..9791bd52405e5 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.md
@@ -146,6 +146,7 @@ zircon/*
| {doc}`bugprone-signed-char-misuse <bugprone/signed-char-misuse>` | |
| {doc}`bugprone-sizeof-container <bugprone/sizeof-container>` | |
| {doc}`bugprone-sizeof-expression <bugprone/sizeof-expression>` | |
+| {doc}`bugprone-smart-ptr-initialization <bugprone/smart-ptr-initialization>` | |
| {doc}`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>` | |
| {doc}`bugprone-standalone-empty <bugprone/standalone-empty>` | Yes |
| {doc}`bugprone-std-exception-baseclass <bugprone/std-exception-baseclass>` | |
@@ -473,6 +474,7 @@ zircon/*
| {doc}`cert-flp30-c <cert/flp30-c>` | {doc}`bugprone-float-loop-counter <bugprone/float-loop-counter>` | |
| {doc}`cert-flp37-c <cert/flp37-c>` | {doc}`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>` | |
| {doc}`cert-int09-c <cert/int09-c>` | {doc}`readability-enum-initial-value <readability/enum-initial-value>` | Yes |
+| {doc}`cert-mem56-cpp <cert/mem56-cpp>` | {doc}`bugprone-smart-ptr-initialization <bugprone/smart-ptr-initialization>` | |
| {doc}`cert-mem57-cpp <cert/mem57-cpp>` | {doc}`bugprone-default-operator-new-on-overaligned-type <bugprone/default-operator-new-on-overaligned-type>` | |
| {doc}`cert-msc24-c <cert/msc24-c>` | {doc}`bugprone-unsafe-functions <bugprone/unsafe-functions>` | |
| {doc}`cert-msc30-c <cert/msc30-c>` | {doc}`misc-predictable-rand <misc/predictable-rand>` | |
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
deleted file mode 100644
index a21d986e3a02b..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ /dev/null
@@ -1,629 +0,0 @@
-.. title:: clang-tidy - Clang-Tidy Checks
-
-Clang-Tidy Checks
-=================
-
-.. toctree::
- :glob:
- :hidden:
-
- abseil/*
- altera/*
- android/*
- boost/*
- bugprone/*
- cert/*
- clang-analyzer/*
- concurrency/*
- cppcoreguidelines/*
- darwin/*
- fuchsia/*
- google/*
- hicpp/*
- linuxkernel/*
- llvm/*
- llvmlibc/*
- misc/*
- modernize/*
- mpi/*
- objc/*
- openmp/*
- performance/*
- portability/*
- readability/*
- zircon/*
-
-.. csv-table::
- :header: "Name", "Offers fixes"
-
- :doc:`abseil-cleanup-ctad <abseil/cleanup-ctad>`, "Yes"
- :doc:`abseil-duration-addition <abseil/duration-addition>`, "Yes"
- :doc:`abseil-duration-comparison <abseil/duration-comparison>`, "Yes"
- :doc:`abseil-duration-conversion-cast <abseil/duration-conversion-cast>`, "Yes"
- :doc:`abseil-duration-division <abseil/duration-division>`, "Yes"
- :doc:`abseil-duration-factory-float <abseil/duration-factory-float>`, "Yes"
- :doc:`abseil-duration-factory-scale <abseil/duration-factory-scale>`, "Yes"
- :doc:`abseil-duration-subtraction <abseil/duration-subtraction>`, "Yes"
- :doc:`abseil-duration-unnecessary-conversion <abseil/duration-unnecessary-conversion>`, "Yes"
- :doc:`abseil-faster-strsplit-delimiter <abseil/faster-strsplit-delimiter>`, "Yes"
- :doc:`abseil-no-internal-dependencies <abseil/no-internal-dependencies>`,
- :doc:`abseil-no-namespace <abseil/no-namespace>`,
- :doc:`abseil-redundant-strcat-calls <abseil/redundant-strcat-calls>`, "Yes"
- :doc:`abseil-str-cat-append <abseil/str-cat-append>`, "Yes"
- :doc:`abseil-string-find-startswith <abseil/string-find-startswith>`, "Yes"
- :doc:`abseil-string-find-str-contains <abseil/string-find-str-contains>`, "Yes"
- :doc:`abseil-time-comparison <abseil/time-comparison>`, "Yes"
- :doc:`abseil-time-subtraction <abseil/time-subtraction>`, "Yes"
- :doc:`abseil-unchecked-statusor-access <abseil/unchecked-statusor-access>`,
- :doc:`abseil-upgrade-duration-conversions <abseil/upgrade-duration-conversions>`, "Yes"
- :doc:`altera-id-dependent-backward-branch <altera/id-dependent-backward-branch>`,
- :doc:`altera-kernel-name-restriction <altera/kernel-name-restriction>`,
- :doc:`altera-single-work-item-barrier <altera/single-work-item-barrier>`,
- :doc:`altera-struct-pack-align <altera/struct-pack-align>`, "Yes"
- :doc:`altera-unroll-loops <altera/unroll-loops>`,
- :doc:`android-cloexec-accept <android/cloexec-accept>`, "Yes"
- :doc:`android-cloexec-accept4 <android/cloexec-accept4>`, "Yes"
- :doc:`android-cloexec-creat <android/cloexec-creat>`, "Yes"
- :doc:`android-cloexec-dup <android/cloexec-dup>`, "Yes"
- :doc:`android-cloexec-epoll-create <android/cloexec-epoll-create>`, "Yes"
- :doc:`android-cloexec-epoll-create1 <android/cloexec-epoll-create1>`, "Yes"
- :doc:`android-cloexec-fopen <android/cloexec-fopen>`, "Yes"
- :doc:`android-cloexec-inotify-init <android/cloexec-inotify-init>`, "Yes"
- :doc:`android-cloexec-inotify-init1 <android/cloexec-inotify-init1>`, "Yes"
- :doc:`android-cloexec-memfd-create <android/cloexec-memfd-create>`, "Yes"
- :doc:`android-cloexec-open <android/cloexec-open>`, "Yes"
- :doc:`android-cloexec-pipe <android/cloexec-pipe>`, "Yes"
- :doc:`android-cloexec-pipe2 <android/cloexec-pipe2>`, "Yes"
- :doc:`android-cloexec-socket <android/cloexec-socket>`, "Yes"
- :doc:`android-comparison-in-temp-failure-retry <android/comparison-in-temp-failure-retry>`,
- :doc:`boost-use-ranges <boost/use-ranges>`, "Yes"
- :doc:`boost-use-to-string <boost/use-to-string>`, "Yes"
- :doc:`bugprone-argument-comment <bugprone/argument-comment>`, "Yes"
- :doc:`bugprone-assert-side-effect <bugprone/assert-side-effect>`,
- :doc:`bugprone-assignment-in-if-condition <bugprone/assignment-in-if-condition>`,
- :doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`,
- :doc:`bugprone-bitwise-pointer-cast <bugprone/bitwise-pointer-cast>`,
- :doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
- :doc:`bugprone-branch-clone <bugprone/branch-clone>`,
- :doc:`bugprone-capturing-this-in-member-variable <bugprone/capturing-this-in-member-variable>`,
- :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`,
- :doc:`bugprone-chained-comparison <bugprone/chained-comparison>`,
- :doc:`bugprone-command-processor <bugprone/command-processor>`,
- :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
- :doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
- :doc:`bugprone-copy-constructor-mutates-argument <bugprone/copy-constructor-mutates-argument>`,
- :doc:`bugprone-crtp-constructor-accessibility <bugprone/crtp-constructor-accessibility>`, "Yes"
- :doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
- :doc:`bugprone-default-operator-new-on-overaligned-type <bugprone/default-operator-new-on-overaligned-type>`,
- :doc:`bugprone-derived-method-shadowing-base-method <bugprone/derived-method-shadowing-base-method>`,
- :doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
- :doc:`bugprone-easily-swappable-parameters <bugprone/easily-swappable-parameters>`,
- :doc:`bugprone-empty-catch <bugprone/empty-catch>`,
- :doc:`bugprone-exception-copy-constructor-throws <bugprone/exception-copy-constructor-throws>`,
- :doc:`bugprone-exception-escape <bugprone/exception-escape>`,
- :doc:`bugprone-float-loop-counter <bugprone/float-loop-counter>`,
- :doc:`bugprone-fold-init-type <bugprone/fold-init-type>`,
- :doc:`bugprone-forward-declaration-namespace <bugprone/forward-declaration-namespace>`,
- :doc:`bugprone-forwarding-reference-overload <bugprone/forwarding-reference-overload>`,
- :doc:`bugprone-implicit-widening-of-multiplication-result <bugprone/implicit-widening-of-multiplication-result>`, "Yes"
- :doc:`bugprone-inaccurate-erase <bugprone/inaccurate-erase>`, "Yes"
- :doc:`bugprone-inc-dec-in-conditions <bugprone/inc-dec-in-conditions>`,
- :doc:`bugprone-incorrect-enable-if <bugprone/incorrect-enable-if>`, "Yes"
- :doc:`bugprone-incorrect-enable-shared-from-this <bugprone/incorrect-enable-shared-from-this>`, "Yes"
- :doc:`bugprone-incorrect-roundings <bugprone/incorrect-roundings>`,
- :doc:`bugprone-infinite-loop <bugprone/infinite-loop>`,
- :doc:`bugprone-integer-division <bugprone/integer-division>`,
- :doc:`bugprone-invalid-enum-default-initialization <bugprone/invalid-enum-default-initialization>`,
- :doc:`bugprone-lambda-function-name <bugprone/lambda-function-name>`,
- :doc:`bugprone-macro-parentheses <bugprone/macro-parentheses>`, "Yes"
- :doc:`bugprone-macro-repeated-side-effects <bugprone/macro-repeated-side-effects>`,
- :doc:`bugprone-misleading-setter-of-reference <bugprone/misleading-setter-of-reference>`,
- :doc:`bugprone-misplaced-operator-in-strlen-in-alloc <bugprone/misplaced-operator-in-strlen-in-alloc>`, "Yes"
- :doc:`bugprone-misplaced-pointer-arithmetic-in-alloc <bugprone/misplaced-pointer-arithmetic-in-alloc>`, "Yes"
- :doc:`bugprone-misplaced-widening-cast <bugprone/misplaced-widening-cast>`,
- :doc:`bugprone-move-forwarding-reference <bugprone/move-forwarding-reference>`, "Yes"
- :doc:`bugprone-multi-level-implicit-pointer-conversion <bugprone/multi-level-implicit-pointer-conversion>`,
- :doc:`bugprone-multiple-new-in-one-expression <bugprone/multiple-new-in-one-expression>`,
- :doc:`bugprone-multiple-statement-macro <bugprone/multiple-statement-macro>`,
- :doc:`bugprone-narrowing-conversions <bugprone/narrowing-conversions>`,
- :doc:`bugprone-no-escape <bugprone/no-escape>`,
- :doc:`bugprone-non-zero-enum-to-bool-conversion <bugprone/non-zero-enum-to-bool-conversion>`,
- :doc:`bugprone-nondeterministic-pointer-iteration-order <bugprone/nondeterministic-pointer-iteration-order>`,
- :doc:`bugprone-not-null-terminated-result <bugprone/not-null-terminated-result>`, "Yes"
- :doc:`bugprone-optional-value-conversion <bugprone/optional-value-conversion>`, "Yes"
- :doc:`bugprone-parent-virtual-call <bugprone/parent-virtual-call>`, "Yes"
- :doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
- :doc:`bugprone-posix-return <bugprone/posix-return>`, "Yes"
- :doc:`bugprone-random-generator-seed <bugprone/random-generator-seed>`,
- :doc:`bugprone-raw-memory-call-on-non-trivial-type <bugprone/raw-memory-call-on-non-trivial-type>`,
- :doc:`bugprone-redundant-branch-condition <bugprone/redundant-branch-condition>`, "Yes"
- :doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
- :doc:`bugprone-return-const-ref-from-parameter <bugprone/return-const-ref-from-parameter>`,
- :doc:`bugprone-shared-ptr-array-mismatch <bugprone/shared-ptr-array-mismatch>`, "Yes"
- :doc:`bugprone-signal-handler <bugprone/signal-handler>`,
- :doc:`bugprone-signed-char-misuse <bugprone/signed-char-misuse>`,
- :doc:`bugprone-sizeof-container <bugprone/sizeof-container>`,
- :doc:`bugprone-sizeof-expression <bugprone/sizeof-expression>`,
- :doc:`bugprone-smart-ptr-initialization <bugprone/smart-ptr-initialization>`,
- :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
- :doc:`bugprone-standalone-empty <bugprone/standalone-empty>`, "Yes"
- :doc:`bugprone-std-namespace-modification <bugprone/std-namespace-modification>`,
- :doc:`bugprone-string-constructor <bugprone/string-constructor>`, "Yes"
- :doc:`bugprone-string-integer-assignment <bugprone/string-integer-assignment>`, "Yes"
- :doc:`bugprone-string-literal-with-embedded-nul <bugprone/string-literal-with-embedded-nul>`,
- :doc:`bugprone-stringview-nullptr <bugprone/stringview-nullptr>`, "Yes"
- :doc:`bugprone-suspicious-enum-usage <bugprone/suspicious-enum-usage>`,
- :doc:`bugprone-suspicious-include <bugprone/suspicious-include>`,
- :doc:`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>`,
- :doc:`bugprone-suspicious-memset-usage <bugprone/suspicious-memset-usage>`, "Yes"
- :doc:`bugprone-suspicious-missing-comma <bugprone/suspicious-missing-comma>`,
- :doc:`bugprone-suspicious-realloc-usage <bugprone/suspicious-realloc-usage>`,
- :doc:`bugprone-suspicious-semicolon <bugprone/suspicious-semicolon>`, "Yes"
- :doc:`bugprone-suspicious-string-compare <bugprone/suspicious-string-compare>`, "Yes"
- :doc:`bugprone-suspicious-stringview-data-usage <bugprone/suspicious-stringview-data-usage>`,
- :doc:`bugprone-swapped-arguments <bugprone/swapped-arguments>`, "Yes"
- :doc:`bugprone-switch-missing-default-case <bugprone/switch-missing-default-case>`,
- :doc:`bugprone-tagged-union-member-count <bugprone/tagged-union-member-count>`,
- :doc:`bugprone-terminating-continue <bugprone/terminating-continue>`, "Yes"
- :doc:`bugprone-throw-keyword-missing <bugprone/throw-keyword-missing>`,
- :doc:`bugprone-throwing-static-initialization <bugprone/throwing-static-initialization>`,
- :doc:`bugprone-too-small-loop-variable <bugprone/too-small-loop-variable>`,
- :doc:`bugprone-unchecked-optional-access <bugprone/unchecked-optional-access>`,
- :doc:`bugprone-unchecked-string-to-number-conversion <bugprone/unchecked-string-to-number-conversion>`,
- :doc:`bugprone-undefined-memory-manipulation <bugprone/undefined-memory-manipulation>`,
- :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`,
- :doc:`bugprone-unhandled-exception-at-new <bugprone/unhandled-exception-at-new>`,
- :doc:`bugprone-unhandled-self-assignment <bugprone/unhandled-self-assignment>`,
- :doc:`bugprone-unintended-char-ostream-output <bugprone/unintended-char-ostream-output>`, "Yes"
- :doc:`bugprone-unique-ptr-array-mismatch <bugprone/unique-ptr-array-mismatch>`, "Yes"
- :doc:`bugprone-unsafe-functions <bugprone/unsafe-functions>`,
- :doc:`bugprone-unused-local-non-trivial-variable <bugprone/unused-local-non-trivial-variable>`,
- :doc:`bugprone-unused-raii <bugprone/unused-raii>`, "Yes"
- :doc:`bugprone-unused-return-value <bugprone/unused-return-value>`,
- :doc:`bugprone-use-after-move <bugprone/use-after-move>`,
- :doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes"
- :doc:`cert-err33-c <cert/err33-c>`,
- :doc:`cert-err60-cpp <cert/err60-cpp>`,
- :doc:`cert-flp30-c <cert/flp30-c>`,
- :doc:`cert-msc50-cpp <cert/msc50-cpp>`,
- :doc:`cert-oop58-cpp <cert/oop58-cpp>`,
- :doc:`concurrency-mt-unsafe <concurrency/mt-unsafe>`,
- :doc:`concurrency-thread-canceltype-asynchronous <concurrency/thread-canceltype-asynchronous>`,
- :doc:`cppcoreguidelines-avoid-capturing-lambda-coroutines <cppcoreguidelines/avoid-capturing-lambda-coroutines>`,
- :doc:`cppcoreguidelines-avoid-const-or-ref-data-members <cppcoreguidelines/avoid-const-or-ref-data-members>`,
- :doc:`cppcoreguidelines-avoid-do-while <cppcoreguidelines/avoid-do-while>`,
- :doc:`cppcoreguidelines-avoid-goto <cppcoreguidelines/avoid-goto>`,
- :doc:`cppcoreguidelines-avoid-non-const-global-variables <cppcoreguidelines/avoid-non-const-global-variables>`,
- :doc:`cppcoreguidelines-avoid-reference-coroutine-parameters <cppcoreguidelines/avoid-reference-coroutine-parameters>`,
- :doc:`cppcoreguidelines-init-variables <cppcoreguidelines/init-variables>`, "Yes"
- :doc:`cppcoreguidelines-interfaces-global-init <cppcoreguidelines/interfaces-global-init>`,
- :doc:`cppcoreguidelines-macro-usage <cppcoreguidelines/macro-usage>`,
- :doc:`cppcoreguidelines-misleading-capture-default-by-value <cppcoreguidelines/misleading-capture-default-by-value>`, "Yes"
- :doc:`cppcoreguidelines-missing-std-forward <cppcoreguidelines/missing-std-forward>`,
- :doc:`cppcoreguidelines-no-malloc <cppcoreguidelines/no-malloc>`,
- :doc:`cppcoreguidelines-no-suspend-with-lock <cppcoreguidelines/no-suspend-with-lock>`,
- :doc:`cppcoreguidelines-owning-memory <cppcoreguidelines/owning-memory>`,
- :doc:`cppcoreguidelines-prefer-member-initializer <cppcoreguidelines/prefer-member-initializer>`, "Yes"
- :doc:`cppcoreguidelines-pro-bounds-array-to-pointer-decay <cppcoreguidelines/pro-bounds-array-to-pointer-decay>`,
- :doc:`cppcoreguidelines-pro-bounds-avoid-unchecked-container-access <cppcoreguidelines/pro-bounds-avoid-unchecked-container-access>`, "Yes"
- :doc:`cppcoreguidelines-pro-bounds-constant-array-index <cppcoreguidelines/pro-bounds-constant-array-index>`, "Yes"
- :doc:`cppcoreguidelines-pro-bounds-pointer-arithmetic <cppcoreguidelines/pro-bounds-pointer-arithmetic>`,
- :doc:`cppcoreguidelines-pro-type-const-cast <cppcoreguidelines/pro-type-const-cast>`,
- :doc:`cppcoreguidelines-pro-type-cstyle-cast <cppcoreguidelines/pro-type-cstyle-cast>`, "Yes"
- :doc:`cppcoreguidelines-pro-type-member-init <cppcoreguidelines/pro-type-member-init>`, "Yes"
- :doc:`cppcoreguidelines-pro-type-reinterpret-cast <cppcoreguidelines/pro-type-reinterpret-cast>`,
- :doc:`cppcoreguidelines-pro-type-static-cast-downcast <cppcoreguidelines/pro-type-static-cast-downcast>`, "Yes"
- :doc:`cppcoreguidelines-pro-type-union-access <cppcoreguidelines/pro-type-union-access>`,
- :doc:`cppcoreguidelines-pro-type-vararg <cppcoreguidelines/pro-type-vararg>`,
- :doc:`cppcoreguidelines-rvalue-reference-param-not-moved <cppcoreguidelines/rvalue-reference-param-not-moved>`,
- :doc:`cppcoreguidelines-slicing <cppcoreguidelines/slicing>`,
- :doc:`cppcoreguidelines-special-member-functions <cppcoreguidelines/special-member-functions>`,
- :doc:`cppcoreguidelines-use-enum-class <cppcoreguidelines/use-enum-class>`,
- :doc:`cppcoreguidelines-virtual-class-destructor <cppcoreguidelines/virtual-class-destructor>`, "Yes"
- :doc:`darwin-avoid-spinlock <darwin/avoid-spinlock>`,
- :doc:`darwin-dispatch-once-nonstatic <darwin/dispatch-once-nonstatic>`, "Yes"
- :doc:`fuchsia-default-arguments-calls <fuchsia/default-arguments-calls>`,
- :doc:`fuchsia-default-arguments-declarations <fuchsia/default-arguments-declarations>`, "Yes"
- :doc:`fuchsia-overloaded-operator <fuchsia/overloaded-operator>`,
- :doc:`fuchsia-statically-constructed-objects <fuchsia/statically-constructed-objects>`,
- :doc:`fuchsia-temporary-objects <fuchsia/temporary-objects>`,
- :doc:`fuchsia-trailing-return <fuchsia/trailing-return>`,
- :doc:`fuchsia-virtual-inheritance <fuchsia/virtual-inheritance>`,
- :doc:`google-build-explicit-make-pair <google/build-explicit-make-pair>`,
- :doc:`google-build-using-namespace <google/build-using-namespace>`,
- :doc:`google-default-arguments <google/default-arguments>`,
- :doc:`google-explicit-constructor <google/explicit-constructor>`, "Yes"
- :doc:`google-global-names-in-headers <google/global-names-in-headers>`,
- :doc:`google-objc-avoid-nsobject-new <google/objc-avoid-nsobject-new>`,
- :doc:`google-objc-avoid-throwing-exception <google/objc-avoid-throwing-exception>`,
- :doc:`google-objc-function-naming <google/objc-function-naming>`,
- :doc:`google-objc-global-variable-declaration <google/objc-global-variable-declaration>`,
- :doc:`google-readability-avoid-underscore-in-googletest-name <google/readability-avoid-underscore-in-googletest-name>`,
- :doc:`google-readability-todo <google/readability-todo>`,
- :doc:`google-runtime-float <google/runtime-float>`,
- :doc:`google-runtime-int <google/runtime-int>`,
- :doc:`google-runtime-operator <google/runtime-operator>`,
- :doc:`google-upgrade-googletest-case <google/upgrade-googletest-case>`, "Yes"
- :doc:`hicpp-exception-baseclass <hicpp/exception-baseclass>`,
- :doc:`hicpp-ignored-remove-result <hicpp/ignored-remove-result>`,
- :doc:`hicpp-multiway-paths-covered <hicpp/multiway-paths-covered>`,
- :doc:`hicpp-no-assembler <hicpp/no-assembler>`,
- :doc:`hicpp-signed-bitwise <hicpp/signed-bitwise>`,
- :doc:`linuxkernel-must-check-errs <linuxkernel/must-check-errs>`,
- :doc:`llvm-header-guard <llvm/header-guard>`,
- :doc:`llvm-include-order <llvm/include-order>`, "Yes"
- :doc:`llvm-namespace-comment <llvm/namespace-comment>`,
- :doc:`llvm-prefer-isa-or-dyn-cast-in-conditionals <llvm/prefer-isa-or-dyn-cast-in-conditionals>`, "Yes"
- :doc:`llvm-prefer-register-over-unsigned <llvm/prefer-register-over-unsigned>`, "Yes"
- :doc:`llvm-prefer-static-over-anonymous-namespace <llvm/prefer-static-over-anonymous-namespace>`,
- :doc:`llvm-twine-local <llvm/twine-local>`, "Yes"
- :doc:`llvm-type-switch-case-types <llvm/type-switch-case-types>`, "Yes"
- :doc:`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>`, "Yes"
- :doc:`llvm-use-ranges <llvm/use-ranges>`, "Yes"
- :doc:`llvm-use-vector-utils <llvm/use-vector-utils>`, "Yes"
- :doc:`llvmlibc-callee-namespace <llvmlibc/callee-namespace>`,
- :doc:`llvmlibc-implementation-in-namespace <llvmlibc/implementation-in-namespace>`,
- :doc:`llvmlibc-inline-function-decl <llvmlibc/inline-function-decl>`, "Yes"
- :doc:`llvmlibc-restrict-system-libc-headers <llvmlibc/restrict-system-libc-headers>`, "Yes"
- :doc:`misc-anonymous-namespace-in-header <misc/anonymous-namespace-in-header>`,
- :doc:`misc-confusable-identifiers <misc/confusable-identifiers>`,
- :doc:`misc-const-correctness <misc/const-correctness>`, "Yes"
- :doc:`misc-coroutine-hostile-raii <misc/coroutine-hostile-raii>`,
- :doc:`misc-definitions-in-headers <misc/definitions-in-headers>`, "Yes"
- :doc:`misc-header-include-cycle <misc/header-include-cycle>`,
- :doc:`misc-include-cleaner <misc/include-cleaner>`, "Yes"
- :doc:`misc-misleading-bidirectional <misc/misleading-bidirectional>`,
- :doc:`misc-misleading-identifier <misc/misleading-identifier>`,
- :doc:`misc-misplaced-const <misc/misplaced-const>`,
- :doc:`misc-multiple-inheritance <misc/multiple-inheritance>`,
- :doc:`misc-new-delete-overloads <misc/new-delete-overloads>`,
- :doc:`misc-no-recursion <misc/no-recursion>`,
- :doc:`misc-non-copyable-objects <misc/non-copyable-objects>`,
- :doc:`misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
- :doc:`misc-override-with-different-visibility <misc/override-with-different-visibility>`,
- :doc:`misc-predictable-rand <misc/predictable-rand>`,
- :doc:`misc-redundant-expression <misc/redundant-expression>`, "Yes"
- :doc:`misc-static-assert <misc/static-assert>`, "Yes"
- :doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
- :doc:`misc-unconventional-assign-operator <misc/unconventional-assign-operator>`,
- :doc:`misc-uniqueptr-reset-release <misc/uniqueptr-reset-release>`, "Yes"
- :doc:`misc-unused-alias-decls <misc/unused-alias-decls>`, "Yes"
- :doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
- :doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
- :doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
- :doc:`misc-use-internal-linkage <misc/use-internal-linkage>`, "Yes"
- :doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
- :doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
- :doc:`modernize-avoid-c-style-cast <modernize/avoid-c-style-cast>`,
- :doc:`modernize-avoid-setjmp-longjmp <modernize/avoid-setjmp-longjmp>`,
- :doc:`modernize-avoid-variadic-functions <modernize/avoid-variadic-functions>`,
- :doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes"
- :doc:`modernize-deprecated-headers <modernize/deprecated-headers>`, "Yes"
- :doc:`modernize-deprecated-ios-base-aliases <modernize/deprecated-ios-base-aliases>`, "Yes"
- :doc:`modernize-loop-convert <modernize/loop-convert>`, "Yes"
- :doc:`modernize-macro-to-enum <modernize/macro-to-enum>`, "Yes"
- :doc:`modernize-make-shared <modernize/make-shared>`, "Yes"
- :doc:`modernize-make-unique <modernize/make-unique>`, "Yes"
- :doc:`modernize-min-max-use-initializer-list <modernize/min-max-use-initializer-list>`, "Yes"
- :doc:`modernize-pass-by-value <modernize/pass-by-value>`, "Yes"
- :doc:`modernize-raw-string-literal <modernize/raw-string-literal>`, "Yes"
- :doc:`modernize-redundant-void-arg <modernize/redundant-void-arg>`, "Yes"
- :doc:`modernize-replace-auto-ptr <modernize/replace-auto-ptr>`, "Yes"
- :doc:`modernize-replace-disallow-copy-and-assign-macro <modernize/replace-disallow-copy-and-assign-macro>`, "Yes"
- :doc:`modernize-replace-random-shuffle <modernize/replace-random-shuffle>`, "Yes"
- :doc:`modernize-return-braced-init-list <modernize/return-braced-init-list>`, "Yes"
- :doc:`modernize-shrink-to-fit <modernize/shrink-to-fit>`, "Yes"
- :doc:`modernize-type-traits <modernize/type-traits>`, "Yes"
- :doc:`modernize-unary-static-assert <modernize/unary-static-assert>`, "Yes"
- :doc:`modernize-use-auto <modernize/use-auto>`, "Yes"
- :doc:`modernize-use-bool-literals <modernize/use-bool-literals>`, "Yes"
- :doc:`modernize-use-constraints <modernize/use-constraints>`, "Yes"
- :doc:`modernize-use-default-member-init <modernize/use-default-member-init>`, "Yes"
- :doc:`modernize-use-designated-initializers <modernize/use-designated-initializers>`, "Yes"
- :doc:`modernize-use-emplace <modernize/use-emplace>`, "Yes"
- :doc:`modernize-use-equals-default <modernize/use-equals-default>`, "Yes"
- :doc:`modernize-use-equals-delete <modernize/use-equals-delete>`, "Yes"
- :doc:`modernize-use-integer-sign-comparison <modernize/use-integer-sign-comparison>`, "Yes"
- :doc:`modernize-use-nodiscard <modernize/use-nodiscard>`, "Yes"
- :doc:`modernize-use-noexcept <modernize/use-noexcept>`, "Yes"
- :doc:`modernize-use-nullptr <modernize/use-nullptr>`, "Yes"
- :doc:`modernize-use-override <modernize/use-override>`, "Yes"
- :doc:`modernize-use-ranges <modernize/use-ranges>`, "Yes"
- :doc:`modernize-use-scoped-lock <modernize/use-scoped-lock>`, "Yes"
- :doc:`modernize-use-starts-ends-with <modernize/use-starts-ends-with>`, "Yes"
- :doc:`modernize-use-std-format <modernize/use-std-format>`, "Yes"
- :doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes"
- :doc:`modernize-use-std-print <modernize/use-std-print>`, "Yes"
- :doc:`modernize-use-string-view <modernize/use-string-view>`, "Yes"
- :doc:`modernize-use-structured-binding <modernize/use-structured-binding>`, "Yes"
- :doc:`modernize-use-trailing-return-type <modernize/use-trailing-return-type>`, "Yes"
- :doc:`modernize-use-transparent-functors <modernize/use-transparent-functors>`, "Yes"
- :doc:`modernize-use-uncaught-exceptions <modernize/use-uncaught-exceptions>`, "Yes"
- :doc:`modernize-use-using <modernize/use-using>`, "Yes"
- :doc:`mpi-buffer-deref <mpi/buffer-deref>`, "Yes"
- :doc:`mpi-type-mismatch <mpi/type-mismatch>`, "Yes"
- :doc:`objc-assert-equals <objc/assert-equals>`, "Yes"
- :doc:`objc-avoid-nserror-init <objc/avoid-nserror-init>`,
- :doc:`objc-dealloc-in-category <objc/dealloc-in-category>`,
- :doc:`objc-forbidden-subclassing <objc/forbidden-subclassing>`,
- :doc:`objc-missing-hash <objc/missing-hash>`,
- :doc:`objc-nsdate-formatter <objc/nsdate-formatter>`,
- :doc:`objc-nsinvocation-argument-lifetime <objc/nsinvocation-argument-lifetime>`, "Yes"
- :doc:`objc-property-declaration <objc/property-declaration>`, "Yes"
- :doc:`objc-super-self <objc/super-self>`, "Yes"
- :doc:`openmp-exception-escape <openmp/exception-escape>`,
- :doc:`openmp-use-default-none <openmp/use-default-none>`,
- :doc:`performance-avoid-endl <performance/avoid-endl>`, "Yes"
- :doc:`performance-enum-size <performance/enum-size>`,
- :doc:`performance-faster-string-find <performance/faster-string-find>`, "Yes"
- :doc:`performance-for-range-copy <performance/for-range-copy>`, "Yes"
- :doc:`performance-implicit-conversion-in-loop <performance/implicit-conversion-in-loop>`,
- :doc:`performance-inefficient-algorithm <performance/inefficient-algorithm>`, "Yes"
- :doc:`performance-inefficient-string-concatenation <performance/inefficient-string-concatenation>`,
- :doc:`performance-inefficient-vector-operation <performance/inefficient-vector-operation>`, "Yes"
- :doc:`performance-move-const-arg <performance/move-const-arg>`, "Yes"
- :doc:`performance-move-constructor-init <performance/move-constructor-init>`,
- :doc:`performance-no-automatic-move <performance/no-automatic-move>`,
- :doc:`performance-no-int-to-ptr <performance/no-int-to-ptr>`,
- :doc:`performance-noexcept-destructor <performance/noexcept-destructor>`, "Yes"
- :doc:`performance-noexcept-move-constructor <performance/noexcept-move-constructor>`, "Yes"
- :doc:`performance-noexcept-swap <performance/noexcept-swap>`, "Yes"
- :doc:`performance-string-view-conversions <performance/string-view-conversions>`, "Yes"
- :doc:`performance-trivially-destructible <performance/trivially-destructible>`, "Yes"
- :doc:`performance-type-promotion-in-math-fn <performance/type-promotion-in-math-fn>`, "Yes"
- :doc:`performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization>`, "Yes"
- :doc:`performance-unnecessary-value-param <performance/unnecessary-value-param>`, "Yes"
- :doc:`portability-avoid-pragma-once <portability/avoid-pragma-once>`,
- :doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes"
- :doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
- :doc:`portability-std-allocator-const <portability/std-allocator-const>`,
- :doc:`portability-template-virtual-member-function <portability/template-virtual-member-function>`,
- :doc:`readability-ambiguous-smartptr-reset-call <readability/ambiguous-smartptr-reset-call>`, "Yes"
- :doc:`readability-avoid-const-params-in-decls <readability/avoid-const-params-in-decls>`, "Yes"
- :doc:`readability-avoid-nested-conditional-operator <readability/avoid-nested-conditional-operator>`,
- :doc:`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>`, "Yes"
- :doc:`readability-avoid-unconditional-preprocessor-if <readability/avoid-unconditional-preprocessor-if>`,
- :doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
- :doc:`readability-const-return-type <readability/const-return-type>`, "Yes"
- :doc:`readability-container-contains <readability/container-contains>`, "Yes"
- :doc:`readability-container-data-pointer <readability/container-data-pointer>`, "Yes"
- :doc:`readability-container-size-empty <readability/container-size-empty>`, "Yes"
- :doc:`readability-convert-member-functions-to-static <readability/convert-member-functions-to-static>`, "Yes"
- :doc:`readability-delete-null-pointer <readability/delete-null-pointer>`, "Yes"
- :doc:`readability-duplicate-include <readability/duplicate-include>`, "Yes"
- :doc:`readability-else-after-return <readability/else-after-return>`, "Yes"
- :doc:`readability-enum-initial-value <readability/enum-initial-value>`, "Yes"
- :doc:`readability-function-cognitive-complexity <readability/function-cognitive-complexity>`,
- :doc:`readability-function-size <readability/function-size>`,
- :doc:`readability-identifier-length <readability/identifier-length>`,
- :doc:`readability-identifier-naming <readability/identifier-naming>`, "Yes"
- :doc:`readability-implicit-bool-conversion <readability/implicit-bool-conversion>`, "Yes"
- :doc:`readability-inconsistent-declaration-parameter-name <readability/inconsistent-declaration-parameter-name>`, "Yes"
- :doc:`readability-inconsistent-ifelse-braces <readability/inconsistent-ifelse-braces>`, "Yes"
- :doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes"
- :doc:`readability-magic-numbers <readability/magic-numbers>`,
- :doc:`readability-make-member-function-const <readability/make-member-function-const>`, "Yes"
- :doc:`readability-math-missing-parentheses <readability/math-missing-parentheses>`, "Yes"
- :doc:`readability-misleading-indentation <readability/misleading-indentation>`,
- :doc:`readability-misplaced-array-index <readability/misplaced-array-index>`, "Yes"
- :doc:`readability-named-parameter <readability/named-parameter>`, "Yes"
- :doc:`readability-non-const-parameter <readability/non-const-parameter>`, "Yes"
- :doc:`readability-operators-representation <readability/operators-representation>`, "Yes"
- :doc:`readability-qualified-auto <readability/qualified-auto>`, "Yes"
- :doc:`readability-redundant-access-specifiers <readability/redundant-access-specifiers>`, "Yes"
- :doc:`readability-redundant-casting <readability/redundant-casting>`, "Yes"
- :doc:`readability-redundant-control-flow <readability/redundant-control-flow>`, "Yes"
- :doc:`readability-redundant-declaration <readability/redundant-declaration>`, "Yes"
- :doc:`readability-redundant-function-ptr-dereference <readability/redundant-function-ptr-dereference>`, "Yes"
- :doc:`readability-redundant-inline-specifier <readability/redundant-inline-specifier>`, "Yes"
- :doc:`readability-redundant-member-init <readability/redundant-member-init>`, "Yes"
- :doc:`readability-redundant-parentheses <readability/redundant-parentheses>`, "Yes"
- :doc:`readability-redundant-preprocessor <readability/redundant-preprocessor>`,
- :doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes"
- :doc:`readability-redundant-string-cstr <readability/redundant-string-cstr>`, "Yes"
- :doc:`readability-redundant-string-init <readability/redundant-string-init>`, "Yes"
- :doc:`readability-redundant-typename <readability/redundant-typename>`, "Yes"
- :doc:`readability-reference-to-constructed-temporary <readability/reference-to-constructed-temporary>`,
- :doc:`readability-simplify-boolean-expr <readability/simplify-boolean-expr>`, "Yes"
- :doc:`readability-simplify-subscript-expr <readability/simplify-subscript-expr>`, "Yes"
- :doc:`readability-static-accessed-through-instance <readability/static-accessed-through-instance>`, "Yes"
- :doc:`readability-static-definition-in-anonymous-namespace <readability/static-definition-in-anonymous-namespace>`, "Yes"
- :doc:`readability-string-compare <readability/string-compare>`, "Yes"
- :doc:`readability-suspicious-call-argument <readability/suspicious-call-argument>`,
- :doc:`readability-trailing-comma <readability/trailing-comma>`, "Yes"
- :doc:`readability-uniqueptr-delete-release <readability/uniqueptr-delete-release>`, "Yes"
- :doc:`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>`, "Yes"
- :doc:`readability-use-anyofallof <readability/use-anyofallof>`,
- :doc:`readability-use-concise-preprocessor-directives <readability/use-concise-preprocessor-directives>`, "Yes"
- :doc:`readability-use-std-min-max <readability/use-std-min-max>`, "Yes"
- :doc:`zircon-temporary-objects <zircon/temporary-objects>`,
-
-Check aliases
--------------
-
-.. csv-table::
- :header: "Name", "Redirect", "Offers fixes"
-
- :doc:`cert-arr39-c <cert/arr39-c>`, :doc:`bugprone-sizeof-expression <bugprone/sizeof-expression>`,
- :doc:`cert-con36-c <cert/con36-c>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
- :doc:`cert-con54-cpp <cert/con54-cpp>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
- :doc:`cert-ctr56-cpp <cert/ctr56-cpp>`, :doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,
- :doc:`cert-dcl03-c <cert/dcl03-c>`, :doc:`misc-static-assert <misc/static-assert>`, "Yes"
- :doc:`cert-dcl16-c <cert/dcl16-c>`, :doc:`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>`, "Yes"
- :doc:`cert-dcl37-c <cert/dcl37-c>`, :doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
- :doc:`cert-dcl50-cpp <cert/dcl50-cpp>`, :doc:`modernize-avoid-variadic-functions <modernize/avoid-variadic-functions>`,
- :doc:`cert-dcl51-cpp <cert/dcl51-cpp>`, :doc:`bugprone-reserved-identifier <bugprone/reserved-identifier>`, "Yes"
- :doc:`cert-dcl54-cpp <cert/dcl54-cpp>`, :doc:`misc-new-delete-overloads <misc/new-delete-overloads>`,
- :doc:`cert-dcl58-cpp <cert/dcl58-cpp>`, :doc:`bugprone-std-namespace-modification <bugprone/std-namespace-modification>`,
- :doc:`cert-dcl59-cpp <cert/dcl59-cpp>`, :doc:`misc-anonymous-namespace-in-header <misc/anonymous-namespace-in-header>`,
- :doc:`cert-env33-c <cert/env33-c>`, :doc:`bugprone-command-processor <bugprone/command-processor>`,
- :doc:`cert-err09-cpp <cert/err09-cpp>`, :doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
- :doc:`cert-err34-c <cert/err34-c>`, :doc:`bugprone-unchecked-string-to-number-conversion <bugprone/unchecked-string-to-number-conversion>`,
- :doc:`cert-err52-cpp <cert/err52-cpp>`, :doc:`modernize-avoid-setjmp-longjmp <modernize/avoid-setjmp-longjmp>`,
- :doc:`cert-err58-cpp <cert/err58-cpp>`, :doc:`bugprone-throwing-static-initialization <bugprone/throwing-static-initialization>`,
- :doc:`cert-err60-cpp <cert/err60-cpp>`, :doc:`bugprone-exception-copy-constructor-throws <bugprone/exception-copy-constructor-throws>`,
- :doc:`cert-err61-cpp <cert/err61-cpp>`, :doc:`misc-throw-by-value-catch-by-reference <misc/throw-by-value-catch-by-reference>`,
- :doc:`cert-exp42-c <cert/exp42-c>`, :doc:`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>`,
- :doc:`cert-fio38-c <cert/fio38-c>`, :doc:`misc-non-copyable-objects <misc/non-copyable-objects>`,
- :doc:`cert-flp30-c <cert/flp30-c>`, :doc:`bugprone-float-loop-counter <bugprone/float-loop-counter>`,
- :doc:`cert-flp37-c <cert/flp37-c>`, :doc:`bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison>`,
- :doc:`cert-int09-c <cert/int09-c>`, :doc:`readability-enum-initial-value <readability/enum-initial-value>`, "Yes"
- :doc:`cert-mem57-cpp <cert/mem57-cpp>`, :doc:`bugprone-default-operator-new-on-overaligned-type <bugprone/default-operator-new-on-overaligned-type>`,
- :doc:`cert-msc24-c <cert/msc24-c>`, :doc:`bugprone-unsafe-functions <bugprone/unsafe-functions>`,
- :doc:`cert-msc30-c <cert/msc30-c>`, :doc:`misc-predictable-rand <misc/predictable-rand>`,
- :doc:`cert-msc32-c <cert/msc32-c>`, :doc:`bugprone-random-generator-seed <bugprone/random-generator-seed>`,
- :doc:`cert-msc33-c <cert/msc33-c>`, :doc:`bugprone-unsafe-functions <bugprone/unsafe-functions>`,
- :doc:`cert-msc50-cpp <cert/msc50-cpp>`, :doc:`misc-predictable-rand <misc/predictable-rand>`,
- :doc:`cert-msc51-cpp <cert/msc51-cpp>`, :doc:`bugprone-random-generator-seed <bugprone/random-generator-seed>`,
- :doc:`cert-msc54-cpp <cert/msc54-cpp>`, :doc:`bugprone-signal-handler <bugprone/signal-handler>`,
- :doc:`cert-oop11-cpp <cert/oop11-cpp>`, :doc:`performance-move-constructor-init <performance/move-constructor-init>`,
- :doc:`cert-oop54-cpp <cert/oop54-cpp>`, :doc:`bugprone-unhandled-self-assignment <bugprone/unhandled-self-assignment>`,
- :doc:`cert-oop57-cpp <cert/oop57-cpp>`, :doc:`bugprone-raw-memory-call-on-non-trivial-type <bugprone/raw-memory-call-on-non-trivial-type>`,
- :doc:`cert-oop58-cpp <cert/oop58-cpp>`, :doc:`bugprone-copy-constructor-mutates-argument <bugprone/copy-constructor-mutates-argument>`,
- :doc:`cert-pos44-c <cert/pos44-c>`, :doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`,
- :doc:`cert-pos47-c <cert/pos47-c>`, :doc:`concurrency-thread-canceltype-asynchronous <concurrency/thread-canceltype-asynchronous>`,
- :doc:`cert-sig30-c <cert/sig30-c>`, :doc:`bugprone-signal-handler <bugprone/signal-handler>`,
- :doc:`cert-str34-c <cert/str34-c>`, :doc:`bugprone-signed-char-misuse <bugprone/signed-char-misuse>`,
- :doc:`clang-analyzer-core.BitwiseShift <clang-analyzer/core.BitwiseShift>`, `Clang Static Analyzer core.BitwiseShift <https://clang.llvm.org/docs/analyzer/checkers.html#core-bitwiseshift>`_,
- :doc:`clang-analyzer-core.CallAndMessage <clang-analyzer/core.CallAndMessage>`, `Clang Static Analyzer core.CallAndMessage <https://clang.llvm.org/docs/analyzer/checkers.html#core-callandmessage>`_,
- :doc:`clang-analyzer-core.DivideZero <clang-analyzer/core.DivideZero>`, `Clang Static Analyzer core.DivideZero <https://clang.llvm.org/docs/analyzer/checkers.html#core-dividezero>`_,
- :doc:`clang-analyzer-core.NonNullParamChecker <clang-analyzer/core.NonNullParamChecker>`, `Clang Static Analyzer core.NonNullParamChecker <https://clang.llvm.org/docs/analyzer/checkers.html#core-nonnullparamchecker>`_,
- :doc:`clang-analyzer-core.NullDereference <clang-analyzer/core.NullDereference>`, `Clang Static Analyzer core.NullDereference <https://clang.llvm.org/docs/analyzer/checkers.html#core-nulldereference>`_,
- :doc:`clang-analyzer-core.StackAddressEscape <clang-analyzer/core.StackAddressEscape>`, `Clang Static Analyzer core.StackAddressEscape <https://clang.llvm.org/docs/analyzer/checkers.html#core-stackaddressescape>`_,
- :doc:`clang-analyzer-core.UndefinedBinaryOperatorResult <clang-analyzer/core.UndefinedBinaryOperatorResult>`, `Clang Static Analyzer core.UndefinedBinaryOperatorResult <https://clang.llvm.org/docs/analyzer/checkers.html#core-undefinedbinaryoperatorresult>`_,
- :doc:`clang-analyzer-core.VLASize <clang-analyzer/core.VLASize>`, `Clang Static Analyzer core.VLASize <https://clang.llvm.org/docs/analyzer/checkers.html#core-vlasize>`_,
- :doc:`clang-analyzer-core.uninitialized.ArraySubscript <clang-analyzer/core.uninitialized.ArraySubscript>`, `Clang Static Analyzer core.uninitialized.ArraySubscript <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-arraysubscript>`_,
- :doc:`clang-analyzer-core.uninitialized.Assign <clang-analyzer/core.uninitialized.Assign>`, `Clang Static Analyzer core.uninitialized.Assign <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-assign>`_,
- :doc:`clang-analyzer-core.uninitialized.Branch <clang-analyzer/core.uninitialized.Branch>`, `Clang Static Analyzer core.uninitialized.Branch <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-branch>`_,
- :doc:`clang-analyzer-core.uninitialized.CapturedBlockVariable <clang-analyzer/core.uninitialized.CapturedBlockVariable>`, `Clang Static Analyzer core.uninitialized.CapturedBlockVariable <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-capturedblockvariable>`_,
- :doc:`clang-analyzer-core.uninitialized.NewArraySize <clang-analyzer/core.uninitialized.NewArraySize>`, `Clang Static Analyzer core.uninitialized.NewArraySize <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-newarraysize>`_,
- :doc:`clang-analyzer-core.uninitialized.UndefReturn <clang-analyzer/core.uninitialized.UndefReturn>`, `Clang Static Analyzer core.uninitialized.UndefReturn <https://clang.llvm.org/docs/analyzer/checkers.html#core-uninitialized-undefreturn>`_,
- :doc:`clang-analyzer-cplusplus.ArrayDelete <clang-analyzer/cplusplus.ArrayDelete>`, `Clang Static Analyzer cplusplus.ArrayDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-arraydelete>`_,
- :doc:`clang-analyzer-cplusplus.InnerPointer <clang-analyzer/cplusplus.InnerPointer>`, `Clang Static Analyzer cplusplus.InnerPointer <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-innerpointer>`_,
- :doc:`clang-analyzer-cplusplus.Move <clang-analyzer/cplusplus.Move>`, `Clang Static Analyzer cplusplus.Move <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-move>`_,
- :doc:`clang-analyzer-cplusplus.NewDelete <clang-analyzer/cplusplus.NewDelete>`, `Clang Static Analyzer cplusplus.NewDelete <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-newdelete>`_,
- :doc:`clang-analyzer-cplusplus.NewDeleteLeaks <clang-analyzer/cplusplus.NewDeleteLeaks>`, `Clang Static Analyzer cplusplus.NewDeleteLeaks <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-newdeleteleaks>`_,
- :doc:`clang-analyzer-cplusplus.PlacementNew <clang-analyzer/cplusplus.PlacementNew>`, `Clang Static Analyzer cplusplus.PlacementNew <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-placementnew>`_,
- :doc:`clang-analyzer-cplusplus.SelfAssignment <clang-analyzer/cplusplus.SelfAssignment>`, `Clang Static Analyzer cplusplus.SelfAssignment <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-selfassignment>`_,
- :doc:`clang-analyzer-cplusplus.StringChecker <clang-analyzer/cplusplus.StringChecker>`, `Clang Static Analyzer cplusplus.StringChecker <https://clang.llvm.org/docs/analyzer/checkers.html#cplusplus-stringchecker>`_,
- :doc:`clang-analyzer-deadcode.DeadStores <clang-analyzer/deadcode.DeadStores>`, `Clang Static Analyzer deadcode.DeadStores <https://clang.llvm.org/docs/analyzer/checkers.html#deadcode-deadstores>`_,
- :doc:`clang-analyzer-fuchsia.HandleChecker <clang-analyzer/fuchsia.HandleChecker>`, `Clang Static Analyzer fuchsia.HandleChecker <https://clang.llvm.org/docs/analyzer/checkers.html#fuchsia-handlechecker>`_,
- :doc:`clang-analyzer-nullability.NullPassedToNonnull <clang-analyzer/nullability.NullPassedToNonnull>`, `Clang Static Analyzer nullability.NullPassedToNonnull <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullpassedtononnull>`_,
- :doc:`clang-analyzer-nullability.NullReturnedFromNonnull <clang-analyzer/nullability.NullReturnedFromNonnull>`, `Clang Static Analyzer nullability.NullReturnedFromNonnull <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullreturnedfromnonnull>`_,
- :doc:`clang-analyzer-nullability.NullableDereferenced <clang-analyzer/nullability.NullableDereferenced>`, `Clang Static Analyzer nullability.NullableDereferenced <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullabledereferenced>`_,
- :doc:`clang-analyzer-nullability.NullablePassedToNonnull <clang-analyzer/nullability.NullablePassedToNonnull>`, `Clang Static Analyzer nullability.NullablePassedToNonnull <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullablepassedtononnull>`_,
- :doc:`clang-analyzer-nullability.NullableReturnedFromNonnull <clang-analyzer/nullability.NullableReturnedFromNonnull>`, `Clang Static Analyzer nullability.NullableReturnedFromNonnull <https://clang.llvm.org/docs/analyzer/checkers.html#nullability-nullablereturnedfromnonnull>`_,
- :doc:`clang-analyzer-optin.core.EnumCastOutOfRange <clang-analyzer/optin.core.EnumCastOutOfRange>`, `Clang Static Analyzer optin.core.EnumCastOutOfRange <https://clang.llvm.org/docs/analyzer/checkers.html#optin-core-enumcastoutofrange>`_,
- :doc:`clang-analyzer-optin.cplusplus.UninitializedObject <clang-analyzer/optin.cplusplus.UninitializedObject>`, `Clang Static Analyzer optin.cplusplus.UninitializedObject <https://clang.llvm.org/docs/analyzer/checkers.html#optin-cplusplus-uninitializedobject>`_,
- :doc:`clang-analyzer-optin.cplusplus.VirtualCall <clang-analyzer/optin.cplusplus.VirtualCall>`, `Clang Static Analyzer optin.cplusplus.VirtualCall <https://clang.llvm.org/docs/analyzer/checkers.html#optin-cplusplus-virtualcall>`_,
- :doc:`clang-analyzer-optin.mpi.MPI-Checker <clang-analyzer/optin.mpi.MPI-Checker>`, `Clang Static Analyzer optin.mpi.MPI-Checker <https://clang.llvm.org/docs/analyzer/checkers.html#optin-mpi-mpi-checker>`_,
- :doc:`clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker <clang-analyzer/optin.osx.cocoa.localizability.EmptyLocalizationContextChecker>`, `Clang Static Analyzer optin.osx.cocoa.localizability.EmptyLocalizationContextChecker <https://clang.llvm.org/docs/analyzer/checkers.html#optin-osx-cocoa-localizability-emptylocalizationcontextchecker>`_,
- :doc:`clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker <clang-analyzer/optin.osx.cocoa.localizability.NonLocalizedStringChecker>`, `Clang Static Analyzer optin.osx.cocoa.localizability.NonLocalizedStringChecker <https://clang.llvm.org/docs/analyzer/checkers.html#optin-osx-cocoa-localizability-nonlocalizedstringchecker>`_,
- :doc:`clang-analyzer-optin.performance.GCDAntipattern <clang-analyzer/optin.performance.GCDAntipattern>`, `Clang Static Analyzer optin.performance.GCDAntipattern <https://clang.llvm.org/docs/analyzer/checkers.html#optin-performance-gcdantipattern>`_,
- :doc:`clang-analyzer-optin.performance.Padding <clang-analyzer/optin.performance.Padding>`, `Clang Static Analyzer optin.performance.Padding <https://clang.llvm.org/docs/analyzer/checkers.html#optin-performance-padding>`_,
- :doc:`clang-analyzer-optin.portability.UnixAPI <clang-analyzer/optin.portability.UnixAPI>`, `Clang Static Analyzer optin.portability.UnixAPI <https://clang.llvm.org/docs/analyzer/checkers.html#optin-portability-unixapi>`_,
- :doc:`clang-analyzer-optin.taint.TaintedAlloc <clang-analyzer/optin.taint.TaintedAlloc>`, `Clang Static Analyzer optin.taint.TaintedAlloc <https://clang.llvm.org/docs/analyzer/checkers.html#optin-taint-taintedalloc>`_,
- :doc:`clang-analyzer-osx.API <clang-analyzer/osx.API>`, `Clang Static Analyzer osx.API <https://clang.llvm.org/docs/analyzer/checkers.html#osx-api>`_,
- :doc:`clang-analyzer-osx.NumberObjectConversion <clang-analyzer/osx.NumberObjectConversion>`, `Clang Static Analyzer osx.NumberObjectConversion <https://clang.llvm.org/docs/analyzer/checkers.html#osx-numberobjectconversion>`_,
- :doc:`clang-analyzer-osx.ObjCProperty <clang-analyzer/osx.ObjCProperty>`, `Clang Static Analyzer osx.ObjCProperty <https://clang.llvm.org/docs/analyzer/checkers.html#osx-objcproperty>`_,
- :doc:`clang-analyzer-osx.SecKeychainAPI <clang-analyzer/osx.SecKeychainAPI>`, `Clang Static Analyzer osx.SecKeychainAPI <https://clang.llvm.org/docs/analyzer/checkers.html#osx-seckeychainapi>`_,
- :doc:`clang-analyzer-osx.cocoa.AtSync <clang-analyzer/osx.cocoa.AtSync>`, `Clang Static Analyzer osx.cocoa.AtSync <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-atsync>`_,
- :doc:`clang-analyzer-osx.cocoa.AutoreleaseWrite <clang-analyzer/osx.cocoa.AutoreleaseWrite>`, `Clang Static Analyzer osx.cocoa.AutoreleaseWrite <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-autoreleasewrite>`_,
- :doc:`clang-analyzer-osx.cocoa.ClassRelease <clang-analyzer/osx.cocoa.ClassRelease>`, `Clang Static Analyzer osx.cocoa.ClassRelease <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-classrelease>`_,
- :doc:`clang-analyzer-osx.cocoa.Dealloc <clang-analyzer/osx.cocoa.Dealloc>`, `Clang Static Analyzer osx.cocoa.Dealloc <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-dealloc>`_,
- :doc:`clang-analyzer-osx.cocoa.IncompatibleMethodTypes <clang-analyzer/osx.cocoa.IncompatibleMethodTypes>`, `Clang Static Analyzer osx.cocoa.IncompatibleMethodTypes <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-incompatiblemethodtypes>`_,
- :doc:`clang-analyzer-osx.cocoa.Loops <clang-analyzer/osx.cocoa.Loops>`, `Clang Static Analyzer osx.cocoa.Loops <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-loops>`_,
- :doc:`clang-analyzer-osx.cocoa.MissingSuperCall <clang-analyzer/osx.cocoa.MissingSuperCall>`, `Clang Static Analyzer osx.cocoa.MissingSuperCall <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-missingsupercall>`_,
- :doc:`clang-analyzer-osx.cocoa.NSAutoreleasePool <clang-analyzer/osx.cocoa.NSAutoreleasePool>`, `Clang Static Analyzer osx.cocoa.NSAutoreleasePool <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-nsautoreleasepool>`_,
- :doc:`clang-analyzer-osx.cocoa.NSError <clang-analyzer/osx.cocoa.NSError>`, `Clang Static Analyzer osx.cocoa.NSError <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-nserror>`_,
- :doc:`clang-analyzer-osx.cocoa.NilArg <clang-analyzer/osx.cocoa.NilArg>`, `Clang Static Analyzer osx.cocoa.NilArg <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-nilarg>`_,
- :doc:`clang-analyzer-osx.cocoa.NonNilReturnValue <clang-analyzer/osx.cocoa.NonNilReturnValue>`, `Clang Static Analyzer osx.cocoa.NonNilReturnValue <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-nonnilreturnvalue>`_,
- :doc:`clang-analyzer-osx.cocoa.ObjCGenerics <clang-analyzer/osx.cocoa.ObjCGenerics>`, `Clang Static Analyzer osx.cocoa.ObjCGenerics <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-objcgenerics>`_,
- :doc:`clang-analyzer-osx.cocoa.RetainCount <clang-analyzer/osx.cocoa.RetainCount>`, `Clang Static Analyzer osx.cocoa.RetainCount <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-retaincount>`_,
- :doc:`clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak <clang-analyzer/osx.cocoa.RunLoopAutoreleaseLeak>`, `Clang Static Analyzer osx.cocoa.RunLoopAutoreleaseLeak <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-runloopautoreleaseleak>`_,
- :doc:`clang-analyzer-osx.cocoa.SelfInit <clang-analyzer/osx.cocoa.SelfInit>`, `Clang Static Analyzer osx.cocoa.SelfInit <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-selfinit>`_,
- :doc:`clang-analyzer-osx.cocoa.SuperDealloc <clang-analyzer/osx.cocoa.SuperDealloc>`, `Clang Static Analyzer osx.cocoa.SuperDealloc <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-superdealloc>`_,
- :doc:`clang-analyzer-osx.cocoa.UnusedIvars <clang-analyzer/osx.cocoa.UnusedIvars>`, `Clang Static Analyzer osx.cocoa.UnusedIvars <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-unusedivars>`_,
- :doc:`clang-analyzer-osx.cocoa.VariadicMethodTypes <clang-analyzer/osx.cocoa.VariadicMethodTypes>`, `Clang Static Analyzer osx.cocoa.VariadicMethodTypes <https://clang.llvm.org/docs/analyzer/checkers.html#osx-cocoa-variadicmethodtypes>`_,
- :doc:`clang-analyzer-osx.coreFoundation.CFError <clang-analyzer/osx.coreFoundation.CFError>`, `Clang Static Analyzer osx.coreFoundation.CFError <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-cferror>`_,
- :doc:`clang-analyzer-osx.coreFoundation.CFNumber <clang-analyzer/osx.coreFoundation.CFNumber>`, `Clang Static Analyzer osx.coreFoundation.CFNumber <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-cfnumber>`_,
- :doc:`clang-analyzer-osx.coreFoundation.CFRetainRelease <clang-analyzer/osx.coreFoundation.CFRetainRelease>`, `Clang Static Analyzer osx.coreFoundation.CFRetainRelease <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-cfretainrelease>`_,
- :doc:`clang-analyzer-osx.coreFoundation.containers.OutOfBounds <clang-analyzer/osx.coreFoundation.containers.OutOfBounds>`, `Clang Static Analyzer osx.coreFoundation.containers.OutOfBounds <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-outofbounds>`_,
- :doc:`clang-analyzer-osx.coreFoundation.containers.PointerSizedValues <clang-analyzer/osx.coreFoundation.containers.PointerSizedValues>`, `Clang Static Analyzer osx.coreFoundation.containers.PointerSizedValues <https://clang.llvm.org/docs/analyzer/checkers.html#osx-corefoundation-containers-pointersizedvalues>`_,
- :doc:`clang-analyzer-security.FloatLoopCounter <clang-analyzer/security.FloatLoopCounter>`, `Clang Static Analyzer security.FloatLoopCounter <https://clang.llvm.org/docs/analyzer/checkers.html#security-floatloopcounter>`_,
- :doc:`clang-analyzer-security.PutenvStackArray <clang-analyzer/security.PutenvStackArray>`, `Clang Static Analyzer security.PutenvStackArray <https://clang.llvm.org/docs/analyzer/checkers.html#security-putenvstackarray-c>`_,
- :doc:`clang-analyzer-security.SetgidSetuidOrder <clang-analyzer/security.SetgidSetuidOrder>`, `Clang Static Analyzer security.SetgidSetuidOrder <https://clang.llvm.org/docs/analyzer/checkers.html#security-setgidsetuidorder-c>`_,
- :doc:`clang-analyzer-security.cert.env.InvalidPtr <clang-analyzer/security.cert.env.InvalidPtr>`, `Clang Static Analyzer security.cert.env.InvalidPtr <https://clang.llvm.org/docs/analyzer/checkers.html#security-cert-env-invalidptr>`_,
- :doc:`clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling <clang-analyzer/security.insecureAPI.DeprecatedOrUnsafeBufferHandling>`, `Clang Static Analyzer security.insecureAPI.DeprecatedOrUnsafeBufferHandling <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-deprecatedorunsafebufferhandling>`_,
- :doc:`clang-analyzer-security.insecureAPI.UncheckedReturn <clang-analyzer/security.insecureAPI.UncheckedReturn>`, `Clang Static Analyzer security.insecureAPI.UncheckedReturn <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-uncheckedreturn>`_,
- :doc:`clang-analyzer-security.insecureAPI.bcmp <clang-analyzer/security.insecureAPI.bcmp>`, `Clang Static Analyzer security.insecureAPI.bcmp <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-bcmp>`_,
- :doc:`clang-analyzer-security.insecureAPI.bcopy <clang-analyzer/security.insecureAPI.bcopy>`, `Clang Static Analyzer security.insecureAPI.bcopy <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-bcopy>`_,
- :doc:`clang-analyzer-security.insecureAPI.bzero <clang-analyzer/security.insecureAPI.bzero>`, `Clang Static Analyzer security.insecureAPI.bzero <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-bzero>`_,
- :doc:`clang-analyzer-security.insecureAPI.decodeValueOfObjCType <clang-analyzer/security.insecureAPI.decodeValueOfObjCType>`, `Clang Static Analyzer security.insecureAPI.decodeValueOfObjCType <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-decodevalueofobjctype>`_,
- :doc:`clang-analyzer-security.insecureAPI.getpw <clang-analyzer/security.insecureAPI.getpw>`, `Clang Static Analyzer security.insecureAPI.getpw <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-getpw>`_,
- :doc:`clang-analyzer-security.insecureAPI.gets <clang-analyzer/security.insecureAPI.gets>`, `Clang Static Analyzer security.insecureAPI.gets <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-gets>`_,
- :doc:`clang-analyzer-security.insecureAPI.mkstemp <clang-analyzer/security.insecureAPI.mkstemp>`, `Clang Static Analyzer security.insecureAPI.mkstemp <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-mkstemp>`_,
- :doc:`clang-analyzer-security.insecureAPI.mktemp <clang-analyzer/security.insecureAPI.mktemp>`, `Clang Static Analyzer security.insecureAPI.mktemp <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-mktemp>`_,
- :doc:`clang-analyzer-security.insecureAPI.rand <clang-analyzer/security.insecureAPI.rand>`, `Clang Static Analyzer security.insecureAPI.rand <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-rand>`_,
- :doc:`clang-analyzer-security.insecureAPI.strcpy <clang-analyzer/security.insecureAPI.strcpy>`, `Clang Static Analyzer security.insecureAPI.strcpy <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-strcpy>`_,
- :doc:`clang-analyzer-security.insecureAPI.vfork <clang-analyzer/security.insecureAPI.vfork>`, `Clang Static Analyzer security.insecureAPI.vfork <https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-vfork>`_,
- :doc:`clang-analyzer-unix.API <clang-analyzer/unix.API>`, `Clang Static Analyzer unix.API <https://clang.llvm.org/docs/analyzer/checkers.html#unix-api>`_,
- :doc:`clang-analyzer-unix.BlockInCriticalSection <clang-analyzer/unix.BlockInCriticalSection>`, `Clang Static Analyzer unix.BlockInCriticalSection <https://clang.llvm.org/docs/analyzer/checkers.html#unix-blockincriticalsection>`_,
- :doc:`clang-analyzer-unix.Errno <clang-analyzer/unix.Errno>`, `Clang Static Analyzer unix.Errno <https://clang.llvm.org/docs/analyzer/checkers.html#unix-errno>`_,
- :doc:`clang-analyzer-unix.Malloc <clang-analyzer/unix.Malloc>`, `Clang Static Analyzer unix.Malloc <https://clang.llvm.org/docs/analyzer/checkers.html#unix-malloc>`_,
- :doc:`clang-analyzer-unix.MallocSizeof <clang-analyzer/unix.MallocSizeof>`, `Clang Static Analyzer unix.MallocSizeof <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mallocsizeof>`_,
- :doc:`clang-analyzer-unix.MismatchedDeallocator <clang-analyzer/unix.MismatchedDeallocator>`, `Clang Static Analyzer unix.MismatchedDeallocator <https://clang.llvm.org/docs/analyzer/checkers.html#unix-mismatcheddeallocator>`_,
- :doc:`clang-analyzer-unix.StdCLibraryFunctions <clang-analyzer/unix.StdCLibraryFunctions>`, `Clang Static Analyzer unix.StdCLibraryFunctions <https://clang.llvm.org/docs/analyzer/checkers.html#unix-stdclibraryfunctions>`_,
- :doc:`clang-analyzer-unix.Stream <clang-analyzer/unix.Stream>`, `Clang Static Analyzer unix.Stream <https://clang.llvm.org/docs/analyzer/checkers.html#unix-stream>`_,
- :doc:`clang-analyzer-unix.Vfork <clang-analyzer/unix.Vfork>`, `Clang Static Analyzer unix.Vfork <https://clang.llvm.org/docs/analyzer/checkers.html#unix-vfork>`_,
- :doc:`clang-analyzer-unix.cstring.BadSizeArg <clang-analyzer/unix.cstring.BadSizeArg>`, `Clang Static Analyzer unix.cstring.BadSizeArg <https://clang.llvm.org/docs/analyzer/checkers.html#unix-cstring-badsizearg>`_,
- :doc:`clang-analyzer-unix.cstring.NullArg <clang-analyzer/unix.cstring.NullArg>`, `Clang Static Analyzer unix.cstring.NullArg <https://clang.llvm.org/docs/analyzer/checkers.html#unix-cstring-nullarg>`_,
- :doc:`clang-analyzer-webkit.NoUncountedMemberChecker <clang-analyzer/webkit.NoUncountedMemberChecker>`, `Clang Static Analyzer webkit.NoUncountedMemberChecker <https://clang.llvm.org/docs/analyzer/checkers.html#webkit-nouncountedmemberchecker>`_,
- :doc:`clang-analyzer-webkit.RefCntblBaseVirtualDtor <clang-analyzer/webkit.RefCntblBaseVirtualDtor>`, `Clang Static Analyzer webkit.RefCntblBaseVirtualDtor <https://clang.llvm.org/docs/analyzer/checkers.html#webkit-refcntblbasevirtualdtor>`_,
- :doc:`clang-analyzer-webkit.UncountedLambdaCapturesChecker <clang-analyzer/webkit.UncountedLambdaCapturesChecker>`, `Clang Static Analyzer webkit.UncountedLambdaCapturesChecker <https://clang.llvm.org/docs/analyzer/checkers.html#webkit-uncountedlambdacaptureschecker>`_,
- :doc:`cppcoreguidelines-avoid-c-arrays <cppcoreguidelines/avoid-c-arrays>`, :doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
- :doc:`cppcoreguidelines-avoid-magic-numbers <cppcoreguidelines/avoid-magic-numbers>`, :doc:`readability-magic-numbers <readability/magic-numbers>`,
- :doc:`cppcoreguidelines-c-copy-assignment-signature <cppcoreguidelines/c-copy-assignment-signature>`, :doc:`misc-unconventional-assign-operator <misc/unconventional-assign-operator>`,
- :doc:`cppcoreguidelines-explicit-virtual-functions <cppcoreguidelines/explicit-virtual-functions>`, :doc:`modernize-use-override <modernize/use-override>`, "Yes"
- :doc:`cppcoreguidelines-macro-to-enum <cppcoreguidelines/macro-to-enum>`, :doc:`modernize-macro-to-enum <modernize/macro-to-enum>`, "Yes"
- :doc:`cppcoreguidelines-narrowing-conversions <cppcoreguidelines/narrowing-conversions>`, :doc:`bugprone-narrowing-conversions <bugprone/narrowing-conversions>`,
- :doc:`cppcoreguidelines-noexcept-destructor <cppcoreguidelines/noexcept-destructor>`, :doc:`performance-noexcept-destructor <performance/noexcept-destructor>`, "Yes"
- :doc:`cppcoreguidelines-noexcept-move-operations <cppcoreguidelines/noexcept-move-operations>`, :doc:`performance-noexcept-move-constructor <performance/noexcept-move-constructor>`, "Yes"
- :doc:`cppcoreguidelines-noexcept-swap <cppcoreguidelines/noexcept-swap>`, :doc:`performance-noexcept-swap <performance/noexcept-swap>`, "Yes"
- :doc:`cppcoreguidelines-non-private-member-variables-in-classes <cppcoreguidelines/non-private-member-variables-in-classes>`, :doc:`misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes>`,
- :doc:`cppcoreguidelines-use-default-member-init <cppcoreguidelines/use-default-member-init>`, :doc:`modernize-use-default-member-init <modernize/use-default-member-init>`, "Yes"
- :doc:`fuchsia-header-anon-namespaces <fuchsia/header-anon-namespaces>`, :doc:`misc-anonymous-namespace-in-header <misc/anonymous-namespace-in-header>`,
- :doc:`fuchsia-multiple-inheritance <fuchsia/multiple-inheritance>`, :doc:`misc-multiple-inheritance <misc/multiple-inheritance>`,
- :doc:`google-build-namespaces <google/build-namespaces>`, :doc:`misc-anonymous-namespace-in-header <misc/anonymous-namespace-in-header>`,
- :doc:`google-readability-braces-around-statements <google/readability-braces-around-statements>`, :doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
- :doc:`google-readability-casting <google/readability-casting>`, :doc:`modernize-avoid-c-style-cast <modernize/avoid-c-style-cast>`,
- :doc:`google-readability-function-size <google/readability-function-size>`, :doc:`readability-function-size <readability/function-size>`,
- :doc:`google-readability-namespace-comments <google/readability-namespace-comments>`, :doc:`llvm-namespace-comment <llvm/namespace-comment>`,
- :doc:`hicpp-avoid-c-arrays <hicpp/avoid-c-arrays>`, :doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
- :doc:`hicpp-avoid-goto <hicpp/avoid-goto>`, :doc:`cppcoreguidelines-avoid-goto <cppcoreguidelines/avoid-goto>`,
- :doc:`hicpp-braces-around-statements <hicpp/braces-around-statements>`, :doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
- :doc:`hicpp-deprecated-headers <hicpp/deprecated-headers>`, :doc:`modernize-deprecated-headers <modernize/deprecated-headers>`, "Yes"
- :doc:`hicpp-explicit-conversions <hicpp/explicit-conversions>`, :doc:`google-explicit-constructor <google/explicit-constructor>`, "Yes"
- :doc:`hicpp-function-size <hicpp/function-size>`, :doc:`readability-function-size <readability/function-size>`,
- :doc:`hicpp-invalid-access-moved <hicpp/invalid-access-moved>`, :doc:`bugprone-use-after-move <bugprone/use-after-move>`,
- :doc:`hicpp-member-init <hicpp/member-init>`, :doc:`cppcoreguidelines-pro-type-member-init <cppcoreguidelines/pro-type-member-init>`, "Yes"
- :doc:`hicpp-move-const-arg <hicpp/move-const-arg>`, :doc:`performance-move-const-arg <performance/move-const-arg>`, "Yes"
- :doc:`hicpp-named-parameter <hicpp/named-parameter>`, :doc:`readability-named-parameter <readability/named-parameter>`, "Yes"
- :doc:`hicpp-new-delete-operators <hicpp/new-delete-operators>`, :doc:`misc-new-delete-overloads <misc/new-delete-overloads>`,
- :doc:`hicpp-no-array-decay <hicpp/no-array-decay>`, :doc:`cppcoreguidelines-pro-bounds-array-to-pointer-decay <cppcoreguidelines/pro-bounds-array-to-pointer-decay>`,
- :doc:`hicpp-no-malloc <hicpp/no-malloc>`, :doc:`cppcoreguidelines-no-malloc <cppcoreguidelines/no-malloc>`,
- :doc:`hicpp-noexcept-move <hicpp/noexcept-move>`, :doc:`performance-noexcept-move-constructor <performance/noexcept-move-constructor>`, "Yes"
- :doc:`hicpp-special-member-functions <hicpp/special-member-functions>`, :doc:`cppcoreguidelines-special-member-functions <cppcoreguidelines/special-member-functions>`,
- :doc:`hicpp-static-assert <hicpp/static-assert>`, :doc:`misc-static-assert <misc/static-assert>`, "Yes"
- :doc:`hicpp-undelegated-constructor <hicpp/undelegated-constructor>`, :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`,
- :doc:`hicpp-uppercase-literal-suffix <hicpp/uppercase-literal-suffix>`, :doc:`readability-uppercase-literal-suffix <readability/uppercase-literal-suffix>`, "Yes"
- :doc:`hicpp-use-auto <hicpp/use-auto>`, :doc:`modernize-use-auto <modernize/use-auto>`, "Yes"
- :doc:`hicpp-use-emplace <hicpp/use-emplace>`, :doc:`modernize-use-emplace <modernize/use-emplace>`, "Yes"
- :doc:`hicpp-use-equals-default <hicpp/use-equals-default>`, :doc:`modernize-use-equals-default <modernize/use-equals-default>`, "Yes"
- :doc:`hicpp-use-equals-delete <hicpp/use-equals-delete>`, :doc:`modernize-use-equals-delete <modernize/use-equals-delete>`, "Yes"
- :doc:`hicpp-use-noexcept <hicpp/use-noexcept>`, :doc:`modernize-use-noexcept <modernize/use-noexcept>`, "Yes"
- :doc:`hicpp-use-nullptr <hicpp/use-nullptr>`, :doc:`modernize-use-nullptr <modernize/use-nullptr>`, "Yes"
- :doc:`hicpp-use-override <hicpp/use-override>`, :doc:`modernize-use-override <modernize/use-override>`, "Yes"
- :doc:`hicpp-vararg <hicpp/vararg>`, :doc:`cppcoreguidelines-pro-type-vararg <cppcoreguidelines/pro-type-vararg>`,
- :doc:`llvm-else-after-return <llvm/else-after-return>`, :doc:`readability-else-after-return <readability/else-after-return>`, "Yes"
- :doc:`llvm-qualified-auto <llvm/qualified-auto>`, :doc:`readability-qualified-auto <readability/qualified-auto>`, "Yes"
>From 83c844cf7a2936bca5aa15ef5b7c10d2d72442ef Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Thu, 6 Aug 2026 19:10:53 +0300
Subject: [PATCH 18/33] review
---
clang-tools-extra/docs/ReleaseNotes.rst | 2 -
.../bugprone/smart-ptr-initialization.md | 99 ++++++++++++++++
.../bugprone/smart-ptr-initialization.rst | 106 ------------------
3 files changed, 99 insertions(+), 108 deletions(-)
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
delete mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 44d91dc4805fb..50afc6fb2c620 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -107,8 +107,6 @@ New checks
Detects dangerous initialization of smart pointers with raw pointers that are
already owned elsewhere, which can lead to double deletion.
-- New :doc:`llvm-type-switch-case-types
- <clang-tidy/checks/llvm/type-switch-case-types>` check.
- New :doc:`performance-expensive-value-or
<clang-tidy/checks/performance/expensive-value-or>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
new file mode 100644
index 0000000000000..4306e2090d090
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
@@ -0,0 +1,99 @@
+# clang-tidy - bugprone-smart-ptr-initialization
+
+## bugprone-smart-ptr-initialization
+
+Detects dangerous initialization of smart pointers with raw pointers that are
+already owned elsewhere, which can lead to double deletion.
+
+This check implements CERT C++ rule [MEM56-CPP. Do not store an already-owned
+pointer value in an unrelated smart pointer](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer).
+
+## Examples
+
+The check flags cases where raw pointers that are already owned or managed
+elsewhere are passed to smart pointer constructors or `reset()` methods:
+
+```cpp
+A& getA();
+void foo() {
+ // Warning: '&getA()' is already managed elsewhere
+ std::shared_ptr<A> a(&getA());
+}
+
+void bar() {
+ int x = 10;
+ // Warning: '&x' points to a local variable
+ std::unique_ptr<int> ptr(&x);
+}
+
+void baz() {
+ std::vector<int> vec{1, 2, 3};
+ std::shared_ptr<int> sp;
+ // Warning: '&vec[0]' is managed by the vector
+ sp.reset(&vec[0]);
+}
+```
+
+## Allowed cases
+
+The check ignores legitimate cases:
+
+1. **New expressions**: Pointers from `new` operators are safe:
+
+ ```cpp
+ std::unique_ptr<int> p(new int(5)); // OK
+ ```
+
+2. **Release calls**: Pointers from `release()` method are transferred:
+
+ ```cpp
+ auto p1 = std::make_unique<int>(5);
+ std::unique_ptr<int> p2(p1.release()); // OK
+ ```
+
+3. **Custom deleters**: Smart pointers with custom deleters are ignored:
+
+ ```cpp
+ void customDeleter(int* p) { delete p; }
+ std::unique_ptr<int, decltype(&customDeleter)> p(&getA(), customDeleter);
+ ```
+
+4. **Null pointers**: `nullptr` is always safe:
+
+ ```cpp
+ std::shared_ptr<int> p(nullptr); // OK
+ p.reset(nullptr); // OK
+ ```
+
+## Options
+
+- **SharedPointers**
+
+ A semicolon-separated list of (fully qualified) shared pointer type names
+ that should be checked. Default value is
+ `::std::shared_ptr;::boost::shared_ptr`.
+
+- **UniquePointers**
+
+ A semicolon-separated list of (fully qualified) unique pointer type names
+ that should be checked. Default value is
+ `::std::unique_ptr`.
+
+- **DefaultDeleters**
+
+ A semicolon-separated list of (fully qualified) default deleter type names.
+ Smart pointers with deleters matching these types are considered to use the
+ default deleter and are checked. Smart pointers with custom deleters are
+ ignored. Default value is `::std::default_delete`.
+
+## Limitations
+
+This check only supports smart pointers with shared and unique ownership
+semantics. Smart pointers with different semantics, such as
+`boost::scoped_ptr`, cannot be used with the current version of this check.
+
+## References
+
+- [CERT C++ MEM56-CPP](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer)
+- [C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r3-a-raw-pointer-a-t-is-non-owning)
+- [C++ Core Guidelines R.20: Use unique_ptr or shared_ptr to represent ownership](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership)
\ No newline at end of file
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
deleted file mode 100644
index f1cce7e97c0fd..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.rst
+++ /dev/null
@@ -1,106 +0,0 @@
-.. title:: clang-tidy - bugprone-smart-ptr-initialization
-
-bugprone-smart-ptr-initialization
-==================================
-
-Detects dangerous initialization of smart pointers with raw pointers that are
-already owned elsewhere, which can lead to double deletion.
-
-This check implements CERT C++ rule `MEM56-CPP. Do not store an already-owned
-pointer value in an unrelated smart pointer
-<https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer>`_.
-
-Examples
---------
-
-The check flags cases where raw pointers that are already owned or managed
-elsewhere are passed to smart pointer constructors or ``reset()`` methods:
-
-.. code-block:: c++
-
- A& getA();
- void foo() {
- // Warning: '&getA()' is already managed elsewhere
- std::shared_ptr<A> a(&getA());
- }
-
- void bar() {
- int x = 10;
- // Warning: '&x' points to a local variable
- std::unique_ptr<int> ptr(&x);
- }
-
- void baz() {
- std::vector<int> vec{1, 2, 3};
- std::shared_ptr<int> sp;
- // Warning: '&vec[0]' is managed by the vector
- sp.reset(&vec[0]);
- }
-
-Allowed cases
--------------
-
-The check ignores legitimate cases:
-
-1. **New expressions**: Pointers from ``new`` operators are safe:
-
- .. code-block:: c++
-
- std::unique_ptr<int> p(new int(5)); // OK
-
-2. **Release calls**: Pointers from ``release()`` method are transferred:
-
- .. code-block:: c++
-
- auto p1 = std::make_unique<int>(5);
- std::unique_ptr<int> p2(p1.release()); // OK
-
-3. **Custom deleters**: Smart pointers with custom deleters are ignored:
-
- .. code-block:: c++
-
- void customDeleter(int* p) { delete p; }
- std::unique_ptr<int, decltype(&customDeleter)> p(&getA(), customDeleter);
-
-4. **Null pointers**: ``nullptr`` is always safe:
-
- .. code-block:: c++
-
- std::shared_ptr<int> p(nullptr); // OK
- p.reset(nullptr); // OK
-
-Options
--------
-
-.. option:: SharedPointers
-
- A semicolon-separated list of (fully qualified) shared pointer type names
- that should be checked. Default value is
- `::std::shared_ptr;::boost::shared_ptr`.
-
-.. option:: UniquePointers
-
- A semicolon-separated list of (fully qualified) unique pointer type names
- that should be checked. Default value is
- `::std::unique_ptr`.
-
-.. option:: DefaultDeleters
-
- A semicolon-separated list of (fully qualified) default deleter type names.
- Smart pointers with deleters matching these types are considered to use the
- default deleter and are checked. Smart pointers with custom deleters are
- ignored. Default value is `::std::default_delete`.
-
-Limitations
------------
-
-This check only supports smart pointers with shared and unique ownership
-semantics. Smart pointers with different semantics, such as
-``boost::scoped_ptr``, cannot be used with the current version of this check.
-
-References
-----------
-
-* `CERT C++ MEM56-CPP <https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer>`_
-* `C++ Core Guidelines R.3: A raw pointer (a T*) is non-owning <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r3-a-raw-pointer-a-t-is-non-owning>`_
-* `C++ Core Guidelines R.20: Use unique_ptr or shared_ptr to represent ownership <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r20-use-unique_ptr-or-shared_ptr-to-represent-ownership>`_
>From 4cce988d6ab1137dec5bb48bdec41566baf6a5c9 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 11:19:08 +0300
Subject: [PATCH 19/33] review
---
.../clang-tidy/bugprone/SmartPtrInitializationCheck.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 786d949903d7a..24d1f7d4df24a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -55,10 +55,8 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
const auto IsUniquePtrRecord = cxxRecordDecl(IsUniquePtr);
const auto IsSmartPtrRecord = cxxRecordDecl(IsSmartPtr);
- auto ReleaseMethod = cxxMethodDecl(hasName("release"));
- auto ResetMethod = cxxMethodDecl(hasName("reset"));
-
- auto ReleaseCallMatcher = cxxMemberCallExpr(callee(ReleaseMethod));
+ auto ReleaseCallMatcher =
+ cxxMemberCallExpr(callee(cxxMethodDecl(hasName("release"))));
// Array automatically decays to pointer
auto PointerArg = expr(anyOf(hasType(pointerType()), hasType(arrayType())))
@@ -107,7 +105,7 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
cxxMemberCallExpr(
on(hasType(hasUnqualifiedDesugaredType(recordType(
hasDeclaration(classTemplateSpecializationDecl(IsSmartPtr)))))),
- callee(ResetMethod), hasArgument(0, PointerArg),
+ callee(cxxMethodDecl(hasName("reset"))), hasArgument(0, PointerArg),
unless(HasCustomDeleterInReset), unless(hasArgument(0, cxxNewExpr())),
unless(hasArgument(0, ReleaseCallMatcher)))
.bind("reset-call");
>From bbeb280cb2ddf66f75584536dec248eef0eb9ba3 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 12:47:08 +0300
Subject: [PATCH 20/33] remove obvious comments
---
.../smart-ptr-initialization-array-cxx17.cpp | 13 -------------
.../bugprone/smart-ptr-initialization-array.cpp | 13 -------------
.../bugprone/smart-ptr-initialization.cpp | 17 -----------------
3 files changed, 43 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
index f679c67188d4e..782e9a7fd38cf 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
@@ -8,13 +8,11 @@ struct A {
A arr[10];
-// Should trigger the check for shared_ptr constructor
void test_shared_ptr_constructor() {
std::shared_ptr<A[]> a(arr);
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger for stack variables
void test_stack_variable() {
int x[10] = {5};
std::shared_ptr<int[]> ptr(x);
@@ -30,12 +28,10 @@ struct S {
}
};
-// Should NOT trigger for new expressions - these are OK
void test_new_expression_ok() {
std::shared_ptr<A[]> a(new A[10]);
}
-// Should NOT trigger for release() calls - ownership transfer
void test_release_ok(std::shared_ptr<A[]> p3) {
std::shared_ptr<A[]> p4(p3.release());
}
@@ -44,31 +40,26 @@ struct NoopDeleter {
void operator() (A* p) {}
};
-// Should NOT trigger for custom deleters
void test_custom_deleter_ok() {
auto noop_deleter = [](A* p) { };
std::shared_ptr<A[]> p2(arr, noop_deleter);
}
-// Should NOT trigger for nullptr
void test_nullptr_ok() {
std::shared_ptr<A[]> a(nullptr);
}
-// Should NOT trigger for copy and move constructors
void test_copy_move_constructor_ok(std::shared_ptr<A[]> sp) {
auto sp2 = sp;
auto sp3 = std::move(sp);
}
-// Should trigger the check for shared_ptr reset
void test_shared_ptr_reset() {
std::shared_ptr<A[]> a;
a.reset(arr);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger for stack variables with reset
void test_stack_variable_reset() {
int x[10] = {5};
std::shared_ptr<int[]> ptr;
@@ -76,26 +67,22 @@ void test_stack_variable_reset() {
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should NOT trigger for new expressions with reset - these are OK
void test_new_expression_reset_ok() {
std::shared_ptr<A[]> a;
a.reset(new A[10]);
}
-// Should NOT trigger for release() calls with reset - ownership transfer
void test_release_reset_ok(std::shared_ptr<A[]> p3) {
std::shared_ptr<A[]> p4;
p4.reset(p3.release());
}
-// Should NOT trigger for custom deleters with reset
void test_custom_deleter_reset_ok() {
auto noop_deleter = [](A* p) { };
std::shared_ptr<A[]> p2;
p2.reset(arr, noop_deleter);
}
-// Should NOT trigger for nullptr with reset
void test_nullptr_reset_ok() {
std::shared_ptr<A[]> a;
a.reset(nullptr);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
index 807d34f126b29..bbcd26807a7a2 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
@@ -8,13 +8,11 @@ struct A {
A arr[10];
-// Should trigger the check for unique_ptr constructor
void test_unique_ptr_constructor() {
std::unique_ptr<A[]> b(arr);
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger for stack variables
void test_stack_variable() {
int x[10] = {5};
std::unique_ptr<int[]> ptr(x);
@@ -30,12 +28,10 @@ struct S {
}
};
-// Should NOT trigger for new expressions - these are OK
void test_new_expression_ok() {
std::unique_ptr<A[]> b(new A[10]);
}
-// Should NOT trigger for release() calls - ownership transfer
void test_release_ok(std::unique_ptr<A[]> p1) {
std::unique_ptr<A[]> p2(p1.release());
}
@@ -44,31 +40,26 @@ struct NoopDeleter {
void operator() (A* p) {}
};
-// Should NOT trigger for custom deleters
void test_custom_deleter_ok() {
auto noop_deleter = [](A* p) { };
std::unique_ptr<A[], NoopDeleter> p0(arr);
std::unique_ptr<A[], decltype(noop_deleter)> p1(arr, noop_deleter);
}
-// Should NOT trigger for nullptr
void test_nullptr_ok() {
std::unique_ptr<A[]> b(nullptr);
}
-// Should NOT trigger for copy and move constructors
void test_copy_move_constructor_ok(std::unique_ptr<A[]> up) {
auto up3 = std::move(up);
}
-// Should trigger the check for unique_ptr reset
void test_unique_ptr_reset() {
std::unique_ptr<A[]> b;
b.reset(arr);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger for stack variables with reset
void test_stack_variable_reset() {
int x[10] = {5};
std::unique_ptr<int[]> ptr;
@@ -76,19 +67,16 @@ void test_stack_variable_reset() {
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should NOT trigger for new expressions with reset - these are OK
void test_new_expression_reset_ok() {
std::unique_ptr<A[]> b;
b.reset(new A[10]);
}
-// Should NOT trigger for release() calls with reset - ownership transfer
void test_release_reset_ok(std::unique_ptr<A[]> p1) {
std::unique_ptr<A[]> p2;
p2.reset(p1.release());
}
-// Should NOT trigger for custom deleters with reset
void test_custom_deleter_reset_ok() {
auto noop_deleter = [](A* p) { };
std::unique_ptr<A[], NoopDeleter> p0;
@@ -97,7 +85,6 @@ void test_custom_deleter_reset_ok() {
p1.reset(arr, noop_deleter);
}
-// Should NOT trigger for nullptr with reset
void test_nullptr_reset_ok() {
std::unique_ptr<A[]> b;
b.reset(nullptr);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index a9779c55b26f6..100fbb5430eaa 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -9,19 +9,16 @@ struct A {
A& getA();
A* getAPtr();
-// Should trigger the check for shared_ptr constructor
void test_shared_ptr_constructor() {
std::shared_ptr<A> a(&getA());
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger the check for unique_ptr constructor
void test_unique_ptr_constructor() {
std::unique_ptr<A> b(&getA());
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger for stack variables
void test_stack_variable() {
int x = 5;
std::unique_ptr<int> ptr(&x);
@@ -37,19 +34,16 @@ struct S {
}
};
-// Should trigger for pointer returned from function
void test_function_return() {
std::shared_ptr<A> sp(getAPtr());
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should NOT trigger for new expressions - these are OK
void test_new_expression_ok() {
std::shared_ptr<A> a(new A());
std::unique_ptr<A> b(new A());
}
-// Should NOT trigger for release() calls - ownership transfer
void test_release_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
std::unique_ptr<A> p2(p1.release());
std::shared_ptr<A> p4(p3.release());
@@ -59,7 +53,6 @@ struct NoopDeleter {
void operator() (A* p) {}
};
-// Should NOT trigger for custom deleters
void test_custom_deleter_ok() {
auto noop_deleter = [](A* p) { };
std::unique_ptr<A, NoopDeleter> p0(&getA());
@@ -67,13 +60,11 @@ void test_custom_deleter_ok() {
std::shared_ptr<A> p2(&getA(), noop_deleter);
}
-// Should NOT trigger for nullptr
void test_nullptr_ok() {
std::shared_ptr<A> a(nullptr);
std::unique_ptr<A> b(nullptr);
}
-// Should NOT trigger for copy and move constructors
void test_copy_move_constructor_ok(std::shared_ptr<A> sp, std::unique_ptr<A> up) {
auto sp2 = sp;
@@ -81,21 +72,18 @@ void test_copy_move_constructor_ok(std::shared_ptr<A> sp, std::unique_ptr<A> up)
auto up3 = std::move(up);
}
-// Should trigger the check for shared_ptr reset
void test_shared_ptr_reset() {
std::shared_ptr<A> a;
a.reset(&getA());
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger the check for unique_ptr reset
void test_unique_ptr_reset() {
std::unique_ptr<A> b;
b.reset(&getA());
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger for stack variables with reset
void test_stack_variable_reset() {
int x = 5;
std::unique_ptr<int> ptr;
@@ -103,14 +91,12 @@ void test_stack_variable_reset() {
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer '&x' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should trigger for pointer returned from function with reset
void test_function_return_reset() {
std::shared_ptr<A> sp;
sp.reset(getAPtr());
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
}
-// Should NOT trigger for new expressions with reset - these are OK
void test_new_expression_reset_ok() {
std::shared_ptr<A> a;
a.reset(new A());
@@ -118,7 +104,6 @@ void test_new_expression_reset_ok() {
b.reset(new A());
}
-// Should NOT trigger for release() calls with reset - ownership transfer
void test_release_reset_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
std::unique_ptr<A> p2;
p2.reset(p1.release());
@@ -126,7 +111,6 @@ void test_release_reset_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
p4.reset(p3.release());
}
-// Should NOT trigger for custom deleters with reset
void test_custom_deleter_reset_ok() {
auto noop_deleter = [](A* p) { };
std::unique_ptr<A, NoopDeleter> p0;
@@ -137,7 +121,6 @@ void test_custom_deleter_reset_ok() {
p2.reset(&getA(), noop_deleter);
}
-// Should NOT trigger for nullptr with reset
void test_nullptr_reset_ok() {
std::shared_ptr<A> a;
a.reset(nullptr);
>From 35b1fd04a3c9df02946e0c5e1d6f360d57e981a0 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 14:51:27 +0300
Subject: [PATCH 21/33] simplify check method a lot
---
.../bugprone/SmartPtrInitializationCheck.cpp | 50 ++++++++-----------
.../bugprone/SmartPtrInitializationCheck.h | 4 ++
2 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 24d1f7d4df24a..304f95108e2ea 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -81,13 +81,13 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
recordType(hasDeclaration(UniquePtrWithCustomDeleter)))),
hasDeclaration(cxxConstructorDecl(ofClass(IsUniquePtrRecord)))));
- auto SmartPtrConstructorMatcher =
- cxxConstructExpr(
- hasDeclaration(cxxConstructorDecl(ofClass(IsSmartPtrRecord))),
- hasArgument(0, PointerArg), unless(HasCustomDeleter),
- unless(hasArgument(0, cxxNewExpr())),
- unless(hasArgument(0, ReleaseCallMatcher)))
- .bind("constructor");
+ auto SmartPtrConstructorMatcher = cxxConstructExpr(
+ hasDeclaration(
+ cxxConstructorDecl(ofClass(IsSmartPtrRecord.bind("method-parent")))
+ .bind("method-decl")),
+ hasArgument(0, PointerArg), unless(HasCustomDeleter),
+ unless(hasArgument(0, cxxNewExpr())),
+ unless(hasArgument(0, ReleaseCallMatcher)));
// Matcher for reset() calls
// Exclude reset() calls with custom deleters:
@@ -101,14 +101,16 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
on(hasType(hasUnqualifiedDesugaredType(
recordType(hasDeclaration(UniquePtrWithCustomDeleter))))));
- auto ResetCallMatcher =
- cxxMemberCallExpr(
- on(hasType(hasUnqualifiedDesugaredType(recordType(
- hasDeclaration(classTemplateSpecializationDecl(IsSmartPtr)))))),
- callee(cxxMethodDecl(hasName("reset"))), hasArgument(0, PointerArg),
- unless(HasCustomDeleterInReset), unless(hasArgument(0, cxxNewExpr())),
- unless(hasArgument(0, ReleaseCallMatcher)))
- .bind("reset-call");
+ auto ResetCallMatcher = cxxMemberCallExpr(
+
+ on(hasType(hasUnqualifiedDesugaredType(recordType(
+ hasDeclaration(classTemplateSpecializationDecl(IsSmartPtr)))))),
+ callee(cxxMethodDecl(hasParent(cxxRecordDecl().bind("method-parent")),
+ hasName("reset"))
+ .bind("method-decl")),
+ hasArgument(0, PointerArg), unless(HasCustomDeleterInReset),
+ unless(hasArgument(0, cxxNewExpr())),
+ unless(hasArgument(0, ReleaseCallMatcher)));
Finder->addMatcher(SmartPtrConstructorMatcher, this);
Finder->addMatcher(ResetCallMatcher, this);
@@ -117,27 +119,19 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
void SmartPtrInitializationCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *PointerArg = Result.Nodes.getNodeAs<Expr>("pointer-arg");
- const auto *Constructor =
- Result.Nodes.getNodeAs<CXXConstructExpr>("constructor");
- const auto *ResetCall =
- Result.Nodes.getNodeAs<CXXMemberCallExpr>("reset-call");
- assert(PointerArg);
+ const auto *MethodDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("method-decl");
+ const auto *Record = Result.Nodes.getNodeAs<CXXRecordDecl>("method-parent");
- const SourceLocation Loc = PointerArg->getBeginLoc();
- const CXXMethodDecl *MethodDecl =
- Constructor ? Constructor->getConstructor()
- : (ResetCall ? ResetCall->getMethodDecl() : nullptr);
if (!MethodDecl)
return;
- const auto *Record = MethodDecl->getParent();
- if (!Record)
- return;
+ assert(PointerArg && Record);
+ const SourceLocation Loc = PointerArg->getBeginLoc();
const std::string TypeName = Record->getQualifiedNameAsString();
diag(Loc, "passing a raw pointer '%0' to %1%2 may cause double deletion")
<< getPointerDescription(PointerArg, *Result.Context) << TypeName
- << (Constructor ? " constructor" : "::reset()");
+ << (isa<CXXConstructorDecl>(MethodDecl) ? " constructor" : "::reset()");
}
std::string
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
index e8814387d0bc4..0b0c635cf58f8 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -25,6 +25,10 @@ class SmartPtrInitializationCheck : public ClangTidyCheck {
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+
private:
std::string getPointerDescription(const Expr *PointerExpr,
ASTContext &Context);
>From f633c76ce3c42830185e0a535a098ee4ac0f4626 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 15:07:49 +0300
Subject: [PATCH 22/33] templates are works fine
---
.../clang-tidy/bugprone/SmartPtrInitializationCheck.cpp | 2 +-
.../clang-tidy/bugprone/SmartPtrInitializationCheck.h | 4 ----
.../checkers/bugprone/smart-ptr-initialization.cpp | 8 ++++++++
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 304f95108e2ea..94151e84efabf 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -105,7 +105,7 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
on(hasType(hasUnqualifiedDesugaredType(recordType(
hasDeclaration(classTemplateSpecializationDecl(IsSmartPtr)))))),
- callee(cxxMethodDecl(hasParent(cxxRecordDecl().bind("method-parent")),
+ callee(cxxMethodDecl(ofClass(IsSmartPtrRecord.bind("method-parent")),
hasName("reset"))
.bind("method-decl")),
hasArgument(0, PointerArg), unless(HasCustomDeleterInReset),
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
index 0b0c635cf58f8..e8814387d0bc4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -25,10 +25,6 @@ class SmartPtrInitializationCheck : public ClangTidyCheck {
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
- std::optional<TraversalKind> getCheckTraversalKind() const override {
- return TK_IgnoreUnlessSpelledInSource;
- }
-
private:
std::string getPointerDescription(const Expr *PointerExpr,
ASTContext &Context);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index 100fbb5430eaa..842e1169b7bca 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -141,3 +141,11 @@ void test_array_release(std::shared_ptr<A[]> spa) {
sp.reset(spa.release());
// This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
}
+
+template<typename T>
+void test_shared_ptr_constructor_template() {
+ T a(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+int a = (test_shared_ptr_constructor_template<std::shared_ptr<A>>(), 0);
>From d648d8544d5fb842dccf70a71d73df273931bb8a Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 17:07:10 +0300
Subject: [PATCH 23/33] get ride of handwritten mock smart pointers
---
.../bugprone/SmartPtrInitializationCheck.cpp | 10 +-
.../smart-ptr-initialization/std_smart_ptr.h | 101 ------------------
.../smart-ptr-initialization-array-cxx17.cpp | 45 +++++---
.../smart-ptr-initialization-array.cpp | 42 ++++++--
.../bugprone/smart-ptr-initialization.cpp | 46 ++++++--
5 files changed, 102 insertions(+), 142 deletions(-)
delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 94151e84efabf..d3edf45f9048c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -128,10 +128,12 @@ void SmartPtrInitializationCheck::check(
assert(PointerArg && Record);
const SourceLocation Loc = PointerArg->getBeginLoc();
- const std::string TypeName = Record->getQualifiedNameAsString();
- diag(Loc, "passing a raw pointer '%0' to %1%2 may cause double deletion")
- << getPointerDescription(PointerArg, *Result.Context) << TypeName
- << (isa<CXXConstructorDecl>(MethodDecl) ? " constructor" : "::reset()");
+ if (Loc.isValid()) {
+ const std::string TypeName = Record->getQualifiedNameAsString();
+ diag(Loc, "passing a raw pointer '%0' to %1%2 may cause double deletion")
+ << getPointerDescription(PointerArg, *Result.Context) << TypeName
+ << (isa<CXXConstructorDecl>(MethodDecl) ? " constructor" : "::reset()");
+ }
}
std::string
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h b/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
deleted file mode 100644
index afb9a2e95792a..0000000000000
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/smart-ptr-initialization/std_smart_ptr.h
+++ /dev/null
@@ -1,101 +0,0 @@
-namespace std {
-
-typedef decltype(nullptr) nullptr_t;
-typedef unsigned long size_t;
-
-template <typename T>
-struct default_delete {
- void operator()(T* p) const;
-};
-
-template <typename T>
-struct default_delete<T[]> {
- void operator()(T* p) const;
-};
-
-template <typename T, typename Deleter = default_delete<T>>
-class unique_ptr {
-public:
- unique_ptr();
- explicit unique_ptr(T* p);
- unique_ptr(T* p, Deleter d) {}
- unique_ptr(std::nullptr_t);
-
- T* release();
-
- void reset(T* p = nullptr);
-
- template <typename D>
- void reset(T* p, D d) {}
-};
-
-template <typename T, typename Deleter>
-class unique_ptr<T[], Deleter> {
-public:
- unique_ptr();
- template <typename U>
- explicit unique_ptr(U* p);
- template <typename U>
- unique_ptr(U* p, Deleter d) {}
- unique_ptr(std::nullptr_t);
-
- T* release();
-
- void reset(T* p = nullptr);
-
- template <typename D>
- void reset(T* p, D d) {}
-};
-
-template <typename T>
-class shared_ptr {
-public:
- shared_ptr();
- explicit shared_ptr(T* p);
- template <typename Deleter>
- shared_ptr(T* p, Deleter d) {}
- shared_ptr(std::nullptr_t);
-
- T* release();
-
- void reset(T* p = nullptr);
-
- template <typename Deleter>
- void reset(T* p, Deleter d) {}
-};
-
-template <typename T>
-class shared_ptr<T[]> {
-public:
- shared_ptr();
- template <typename U>
- explicit shared_ptr(U* p);
- template <typename U, typename Deleter>
- shared_ptr(U* p, Deleter d) {}
- shared_ptr(std::nullptr_t);
-
- T* release();
-
- void reset(T* p = nullptr);
-
- template <typename Deleter>
- void reset(T* p, Deleter d) {}
-};
-
-template<typename T>
- struct remove_reference
- { using type = T; };
-
-template<typename T>
- struct remove_reference<T&>
- { using type = T; };
-
-template<typename T>
- struct remove_reference<T&&>
- { using type = T; };
-
-template<typename T>
- constexpr typename std::remove_reference<T>::type&&
- move(T&& t) noexcept;
-
-} // namespace std
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
index 782e9a7fd38cf..6bf78d20b3d58 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
@@ -1,6 +1,26 @@
-// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-smart-ptr-initialization %t -- -- -I%S
+// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-smart-ptr-initialization %t -- -- -I %S/../modernize/Inputs/smart-ptr
+
+#include "shared_ptr.h"
+#include "unique_ptr.h"
+
+namespace std {
+template<typename T>
+ struct remove_reference
+ { using type = T; };
+
+template<typename T>
+ struct remove_reference<T&>
+ { using type = T; };
+
+template<typename T>
+ struct remove_reference<T&&>
+ { using type = T; };
+
+template<typename T>
+ constexpr typename std::remove_reference<T>::type&&
+ move(T&& t) noexcept;
+}
-#include "Inputs/smart-ptr-initialization/std_smart_ptr.h"
struct A {
int x;
@@ -32,10 +52,6 @@ void test_new_expression_ok() {
std::shared_ptr<A[]> a(new A[10]);
}
-void test_release_ok(std::shared_ptr<A[]> p3) {
- std::shared_ptr<A[]> p4(p3.release());
-}
-
struct NoopDeleter {
void operator() (A* p) {}
};
@@ -72,20 +88,16 @@ void test_new_expression_reset_ok() {
a.reset(new A[10]);
}
-void test_release_reset_ok(std::shared_ptr<A[]> p3) {
- std::shared_ptr<A[]> p4;
- p4.reset(p3.release());
-}
-
void test_custom_deleter_reset_ok() {
auto noop_deleter = [](A* p) { };
std::shared_ptr<A[]> p2;
- p2.reset(arr, noop_deleter);
+ // FIXME: mock shared_ptr must support reset with custom deleter
+ // p2.reset(arr, noop_deleter);
}
-void test_nullptr_reset_ok() {
+void test_reset_ok() {
std::shared_ptr<A[]> a;
- a.reset(nullptr);
+ a.reset();
}
//
@@ -97,7 +109,8 @@ void test_array_new() {
}
void test_array_release(std::shared_ptr<A> spa) {
- std::shared_ptr<A[]> sp(spa.release()); // This is actually wrong but not our check's concern
- sp.reset(spa.release());
+ // TODO:
+ // std::shared_ptr<A[]> sp(spa.release()); // This is actually wrong but not our check's concern
+ // sp.reset(spa.release());
// This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
index bbcd26807a7a2..ebe7f3319c38f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
@@ -1,6 +1,26 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I%S
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I %S/../modernize/Inputs/smart-ptr
+
+#include "shared_ptr.h"
+#include "unique_ptr.h"
+
+namespace std {
+template<typename T>
+ struct remove_reference
+ { using type = T; };
+
+template<typename T>
+ struct remove_reference<T&>
+ { using type = T; };
+
+template<typename T>
+ struct remove_reference<T&&>
+ { using type = T; };
+
+template<typename T>
+ constexpr typename std::remove_reference<T>::type&&
+ move(T&& t) noexcept;
+}
-#include "Inputs/smart-ptr-initialization/std_smart_ptr.h"
struct A {
int x;
@@ -32,9 +52,10 @@ void test_new_expression_ok() {
std::unique_ptr<A[]> b(new A[10]);
}
-void test_release_ok(std::unique_ptr<A[]> p1) {
- std::unique_ptr<A[]> p2(p1.release());
-}
+// FIXME: WTF with our mock unique_ptr?
+// void test_release_ok(std::unique_ptr<A[]> p1) {
+// std::unique_ptr<A[]> p2(p1.release());
+// }
struct NoopDeleter {
void operator() (A* p) {}
@@ -72,17 +93,18 @@ void test_new_expression_reset_ok() {
b.reset(new A[10]);
}
-void test_release_reset_ok(std::unique_ptr<A[]> p1) {
- std::unique_ptr<A[]> p2;
- p2.reset(p1.release());
-}
+// FIXME: WTF with our mock unique_ptr?
+// void test_release_reset_ok(std::unique_ptr<A[]> p1) {
+// std::unique_ptr<A[]> p2;
+// p2.reset(p1.release());
+// }
void test_custom_deleter_reset_ok() {
auto noop_deleter = [](A* p) { };
std::unique_ptr<A[], NoopDeleter> p0;
p0.reset(arr);
std::unique_ptr<A[], decltype(noop_deleter)> p1;
- p1.reset(arr, noop_deleter);
+ p1.reset(arr);
}
void test_nullptr_reset_ok() {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index 842e1169b7bca..6dd36eb5f26d7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -1,6 +1,26 @@
-// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I%S
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I %S/../modernize/Inputs/smart-ptr
+
+#include "shared_ptr.h"
+#include "unique_ptr.h"
+
+namespace std {
+template<typename T>
+ struct remove_reference
+ { using type = T; };
+
+template<typename T>
+ struct remove_reference<T&>
+ { using type = T; };
+
+template<typename T>
+ struct remove_reference<T&&>
+ { using type = T; };
+
+template<typename T>
+ constexpr typename std::remove_reference<T>::type&&
+ move(T&& t) noexcept;
+}
-#include "Inputs/smart-ptr-initialization/std_smart_ptr.h"
struct A {
int x;
@@ -46,7 +66,6 @@ void test_new_expression_ok() {
void test_release_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
std::unique_ptr<A> p2(p1.release());
- std::shared_ptr<A> p4(p3.release());
}
struct NoopDeleter {
@@ -107,8 +126,6 @@ void test_new_expression_reset_ok() {
void test_release_reset_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
std::unique_ptr<A> p2;
p2.reset(p1.release());
- std::shared_ptr<A> p4;
- p4.reset(p3.release());
}
void test_custom_deleter_reset_ok() {
@@ -116,18 +133,24 @@ void test_custom_deleter_reset_ok() {
std::unique_ptr<A, NoopDeleter> p0;
p0.reset(&getA());
std::unique_ptr<A, decltype(noop_deleter)> p1;
- p1.reset(&getA(), noop_deleter);
+ p1.reset(&getA());
std::shared_ptr<A> p2;
- p2.reset(&getA(), noop_deleter);
+ // FIXME: mock shared_ptr must support reset with custom deleter
+ // p2.reset(&getA(), noop_deleter);
}
void test_nullptr_reset_ok() {
- std::shared_ptr<A> a;
- a.reset(nullptr);
std::unique_ptr<A> b;
b.reset(nullptr);
}
+void test_reset_ok() {
+ std::shared_ptr<A> a;
+ a.reset();
+ std::unique_ptr<A> b;
+ b.reset();
+}
+
//
// Edge case: should trigger for array new with wrong smart pointer
void test_array_new() {
@@ -137,8 +160,9 @@ void test_array_new() {
}
void test_array_release(std::shared_ptr<A[]> spa) {
- std::shared_ptr<A> sp(spa.release()); // This is actually wrong but not our check's concern
- sp.reset(spa.release());
+// TODO:
+ // std::shared_ptr<A> sp(spa.release()); // This is actually wrong but not our check's concern
+ // sp.reset(spa.release());
// This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
}
>From 4286d9c267d64d19825b3ef445ccfd04202ada8f Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 17:32:34 +0300
Subject: [PATCH 24/33] remove irrelevant tests
---
.../bugprone/smart-ptr-initialization-array-cxx17.cpp | 7 -------
.../checkers/bugprone/smart-ptr-initialization.cpp | 7 -------
2 files changed, 14 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
index 6bf78d20b3d58..69b220a7bdbfa 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
@@ -107,10 +107,3 @@ void test_array_new() {
sp.reset(new A);
// This would be caught by bugprone-shared-ptr-array-mismatch checks
}
-
-void test_array_release(std::shared_ptr<A> spa) {
- // TODO:
- // std::shared_ptr<A[]> sp(spa.release()); // This is actually wrong but not our check's concern
- // sp.reset(spa.release());
- // This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
-}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index 6dd36eb5f26d7..29aa32ab658d6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -159,13 +159,6 @@ void test_array_new() {
// This would be caught by bugprone-shared-ptr-array-mismatch checks
}
-void test_array_release(std::shared_ptr<A[]> spa) {
-// TODO:
- // std::shared_ptr<A> sp(spa.release()); // This is actually wrong but not our check's concern
- // sp.reset(spa.release());
- // This would be caught by bugprone-shared-ptr-array-mismatch checks (mismatched new/delete)
-}
-
template<typename T>
void test_shared_ptr_constructor_template() {
T a(&getA());
>From b31b13d9758c47a57144918fcc91ff35973a17f3 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 18:09:20 +0300
Subject: [PATCH 25/33] added tests with macro
---
.../smart-ptr-initialization-macro.cpp | 62 +++++++++++++++++++
1 file changed, 62 insertions(+)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp
new file mode 100644
index 0000000000000..ac952dde74d5c
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp
@@ -0,0 +1,62 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I %S/../modernize/Inputs/smart-ptr
+
+#include "shared_ptr.h"
+#include "unique_ptr.h"
+
+struct A {
+ int x;
+};
+
+A& getA();
+A* getAPtr();
+
+#define SHARED_PTR_A std::shared_ptr<A>
+#define UNIQUE_PTR_A std::unique_ptr<A>
+
+void test_shared_ptr_constructor_macro1() {
+ SHARED_PTR_A a(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+void test_unique_ptr_constructor_macro1() {
+ UNIQUE_PTR_A b(&getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+#define GET_REFERENCE_TO_GETA_RESULT &getA()
+
+void test_shared_ptr_constructor_macro2() {
+ std::shared_ptr<A> a(GET_REFERENCE_TO_GETA_RESULT);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+void test_unique_ptr_constructor_macro2() {
+ std::unique_ptr<A> b(GET_REFERENCE_TO_GETA_RESULT);
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+#define SHARED_PTR_THE_WHOLE_STATEMENT_IN_MACRO std::shared_ptr<A> a(&getA());
+#define UNIQUE_PTR_THE_WHOLE_STATEMENT_IN_MACRO std::unique_ptr<A> b(&getA());
+
+void test_shared_ptr_constructor_macro3() {
+ SHARED_PTR_THE_WHOLE_STATEMENT_IN_MACRO
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+void test_unique_ptr_constructor_macro3() {
+ UNIQUE_PTR_THE_WHOLE_STATEMENT_IN_MACRO
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+#define COMPLICATED_SOURCE_LOCATION_FOR_A a(&
+#define COMPLICATED_SOURCE_LOCATION_FOR_B b(&
+
+void test_shared_ptr_constructor_macro4() {
+ std::shared_ptr<A> COMPLICATED_SOURCE_LOCATION_FOR_A getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
+
+void test_unique_ptr_constructor_macro5() {
+ std::unique_ptr<A> COMPLICATED_SOURCE_LOCATION_FOR_B getA());
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+}
>From 663a300374d4bded7d89856b75a1d540e90b0997 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 18:19:40 +0300
Subject: [PATCH 26/33] review
---
.../clang-tidy/bugprone/SmartPtrInitializationCheck.cpp | 2 +-
.../clang-tidy/bugprone/SmartPtrInitializationCheck.h | 2 +-
.../clang-tidy/checks/bugprone/smart-ptr-initialization.md | 3 +--
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index d3edf45f9048c..88496f05571fa 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -138,7 +138,7 @@ void SmartPtrInitializationCheck::check(
std::string
SmartPtrInitializationCheck::getPointerDescription(const Expr *PointerExpr,
- ASTContext &Context) {
+ const ASTContext &Context) {
std::string Description;
llvm::raw_string_ostream OS(Description);
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
index e8814387d0bc4..767ff7c46efab 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -27,7 +27,7 @@ class SmartPtrInitializationCheck : public ClangTidyCheck {
private:
std::string getPointerDescription(const Expr *PointerExpr,
- ASTContext &Context);
+ const ASTContext &Context);
const std::vector<StringRef> SharedPointers;
const std::vector<StringRef> UniquePointers;
const std::vector<StringRef> DefaultDeleters;
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
index 4306e2090d090..bb595ca40584a 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
@@ -76,8 +76,7 @@ The check ignores legitimate cases:
- **UniquePointers**
A semicolon-separated list of (fully qualified) unique pointer type names
- that should be checked. Default value is
- `::std::unique_ptr`.
+ that should be checked. Default value is `::std::unique_ptr`.
- **DefaultDeleters**
>From 12fb65651f23e906599b0270e8c3a64595e994ed Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 21:05:44 +0300
Subject: [PATCH 27/33] more detailed diagnostic
---
.../bugprone/SmartPtrInitializationCheck.cpp | 23 ++++++++++++++-----
.../bugprone/SmartPtrInitializationCheck.h | 6 +++--
.../smart-ptr-initialization-array-cxx17.cpp | 10 ++++----
.../smart-ptr-initialization-array.cpp | 10 ++++----
.../smart-ptr-initialization-macro.cpp | 16 ++++++-------
.../bugprone/smart-ptr-initialization.cpp | 20 ++++++++--------
6 files changed, 49 insertions(+), 36 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 88496f05571fa..7046c39f57bd3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -129,16 +129,27 @@ void SmartPtrInitializationCheck::check(
const SourceLocation Loc = PointerArg->getBeginLoc();
if (Loc.isValid()) {
- const std::string TypeName = Record->getQualifiedNameAsString();
diag(Loc, "passing a raw pointer '%0' to %1%2 may cause double deletion")
- << getPointerDescription(PointerArg, *Result.Context) << TypeName
- << (isa<CXXConstructorDecl>(MethodDecl) ? " constructor" : "::reset()");
+ << getRawPointerDescription(PointerArg, *Result.Context)
+ << getSmartPointerDescription(Record, *Result.Context)
+ << (isa<CXXConstructorDecl>(MethodDecl) ? " constructor"
+ : "::reset(...)");
}
}
-std::string
-SmartPtrInitializationCheck::getPointerDescription(const Expr *PointerExpr,
- const ASTContext &Context) {
+std::string SmartPtrInitializationCheck::getSmartPointerDescription(
+ const CXXRecordDecl *recordDecl, const ASTContext &context) {
+ clang::PrintingPolicy policy = context.getPrintingPolicy();
+
+ std::string result;
+ llvm::raw_string_ostream os(result);
+ recordDecl->getNameForDiagnostic(os, policy, /*Qualified=*/true);
+
+ return result;
+}
+
+std::string SmartPtrInitializationCheck::getRawPointerDescription(
+ const Expr *PointerExpr, const ASTContext &Context) {
std::string Description;
llvm::raw_string_ostream OS(Description);
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
index 767ff7c46efab..adc62ec62d69d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -26,8 +26,10 @@ class SmartPtrInitializationCheck : public ClangTidyCheck {
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
private:
- std::string getPointerDescription(const Expr *PointerExpr,
- const ASTContext &Context);
+ std::string getSmartPointerDescription(const CXXRecordDecl *PointerExpr,
+ const ASTContext &Context);
+ std::string getRawPointerDescription(const Expr *PointerExpr,
+ const ASTContext &Context);
const std::vector<StringRef> SharedPointers;
const std::vector<StringRef> UniquePointers;
const std::vector<StringRef> DefaultDeleters;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
index 69b220a7bdbfa..53191742b414a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
@@ -30,13 +30,13 @@ A arr[10];
void test_shared_ptr_constructor() {
std::shared_ptr<A[]> a(arr);
- // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::shared_ptr<A[]> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_stack_variable() {
int x[10] = {5};
std::shared_ptr<int[]> ptr(x);
- // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer 'x' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer 'x' to std::shared_ptr<int[]> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
// Should trigger for member variables
@@ -44,7 +44,7 @@ struct S {
int member[10];
void test() {
std::shared_ptr<int[]> ptr(member);
- // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: passing a raw pointer 'this->member' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: passing a raw pointer 'this->member' to std::shared_ptr<int[]> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
};
@@ -73,14 +73,14 @@ void test_copy_move_constructor_ok(std::shared_ptr<A[]> sp) {
void test_shared_ptr_reset() {
std::shared_ptr<A[]> a;
a.reset(arr);
- // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::shared_ptr<A[]>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_stack_variable_reset() {
int x[10] = {5};
std::shared_ptr<int[]> ptr;
ptr.reset(x);
- // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::shared_ptr<int[]>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_new_expression_reset_ok() {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
index ebe7f3319c38f..ce2504f014ba5 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
@@ -30,13 +30,13 @@ A arr[10];
void test_unique_ptr_constructor() {
std::unique_ptr<A[]> b(arr);
- // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing a raw pointer 'arr' to std::unique_ptr<A[]> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_stack_variable() {
int x[10] = {5};
std::unique_ptr<int[]> ptr(x);
- // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer 'x' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer 'x' to std::unique_ptr<int[]> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
// Should trigger for member variables
@@ -44,7 +44,7 @@ struct S {
int member[10];
void test() {
std::unique_ptr<int[]> ptr(member);
- // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: passing a raw pointer 'this->member' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: passing a raw pointer 'this->member' to std::unique_ptr<int[]> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
};
@@ -78,14 +78,14 @@ void test_copy_move_constructor_ok(std::unique_ptr<A[]> up) {
void test_unique_ptr_reset() {
std::unique_ptr<A[]> b;
b.reset(arr);
- // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer 'arr' to std::unique_ptr<A[]>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_stack_variable_reset() {
int x[10] = {5};
std::unique_ptr<int[]> ptr;
ptr.reset(x);
- // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer 'x' to std::unique_ptr<int[]>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_new_expression_reset_ok() {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp
index ac952dde74d5c..8cdc6b5e0a1c7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-macro.cpp
@@ -15,24 +15,24 @@ A* getAPtr();
void test_shared_ptr_constructor_macro1() {
SHARED_PTR_A a(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing a raw pointer '&getA()' to std::shared_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_unique_ptr_constructor_macro1() {
UNIQUE_PTR_A b(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: passing a raw pointer '&getA()' to std::unique_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
#define GET_REFERENCE_TO_GETA_RESULT &getA()
void test_shared_ptr_constructor_macro2() {
std::shared_ptr<A> a(GET_REFERENCE_TO_GETA_RESULT);
- // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::shared_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_unique_ptr_constructor_macro2() {
std::unique_ptr<A> b(GET_REFERENCE_TO_GETA_RESULT);
- // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
#define SHARED_PTR_THE_WHOLE_STATEMENT_IN_MACRO std::shared_ptr<A> a(&getA());
@@ -40,12 +40,12 @@ void test_unique_ptr_constructor_macro2() {
void test_shared_ptr_constructor_macro3() {
SHARED_PTR_THE_WHOLE_STATEMENT_IN_MACRO
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: passing a raw pointer '&getA()' to std::shared_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_unique_ptr_constructor_macro3() {
UNIQUE_PTR_THE_WHOLE_STATEMENT_IN_MACRO
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: passing a raw pointer '&getA()' to std::unique_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
#define COMPLICATED_SOURCE_LOCATION_FOR_A a(&
@@ -53,10 +53,10 @@ void test_unique_ptr_constructor_macro3() {
void test_shared_ptr_constructor_macro4() {
std::shared_ptr<A> COMPLICATED_SOURCE_LOCATION_FOR_A getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: passing a raw pointer '&getA()' to std::shared_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_unique_ptr_constructor_macro5() {
std::unique_ptr<A> COMPLICATED_SOURCE_LOCATION_FOR_B getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: passing a raw pointer '&getA()' to std::unique_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index 29aa32ab658d6..981cbd7f43945 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -31,18 +31,18 @@ A* getAPtr();
void test_shared_ptr_constructor() {
std::shared_ptr<A> a(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::shared_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_unique_ptr_constructor() {
std::unique_ptr<A> b(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: passing a raw pointer '&getA()' to std::unique_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_stack_variable() {
int x = 5;
std::unique_ptr<int> ptr(&x);
- // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: passing a raw pointer '&x' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: passing a raw pointer '&x' to std::unique_ptr<int> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
// Should trigger for member variables
@@ -50,13 +50,13 @@ struct S {
int member;
void test() {
std::unique_ptr<int> ptr(&member);
- // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer '&this->member' to std::unique_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: passing a raw pointer '&this->member' to std::unique_ptr<int> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
};
void test_function_return() {
std::shared_ptr<A> sp(getAPtr());
- // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_new_expression_ok() {
@@ -94,26 +94,26 @@ void test_copy_move_constructor_ok(std::shared_ptr<A> sp, std::unique_ptr<A> up)
void test_shared_ptr_reset() {
std::shared_ptr<A> a;
a.reset(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::shared_ptr<A>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_unique_ptr_reset() {
std::unique_ptr<A> b;
b.reset(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: passing a raw pointer '&getA()' to std::unique_ptr<A>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_stack_variable_reset() {
int x = 5;
std::unique_ptr<int> ptr;
ptr.reset(&x);
- // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer '&x' to std::unique_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: passing a raw pointer '&x' to std::unique_ptr<int>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_function_return_reset() {
std::shared_ptr<A> sp;
sp.reset(getAPtr());
- // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr::reset() may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: passing a raw pointer 'getAPtr()' to std::shared_ptr<A>::reset(...) may cause double deletion [bugprone-smart-ptr-initialization]
}
void test_new_expression_reset_ok() {
@@ -162,7 +162,7 @@ void test_array_new() {
template<typename T>
void test_shared_ptr_constructor_template() {
T a(&getA());
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: passing a raw pointer '&getA()' to std::shared_ptr constructor may cause double deletion [bugprone-smart-ptr-initialization]
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: passing a raw pointer '&getA()' to std::shared_ptr<A> constructor may cause double deletion [bugprone-smart-ptr-initialization]
}
int a = (test_shared_ptr_constructor_template<std::shared_ptr<A>>(), 0);
>From 2a9db94dee6c6313d90ee18abc5c293b060911cc Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Fri, 7 Aug 2026 22:23:52 +0300
Subject: [PATCH 28/33] lint
---
.../bugprone/SmartPtrInitializationCheck.cpp | 12 ++++++------
.../bugprone/SmartPtrInitializationCheck.h | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 7046c39f57bd3..5ee4560240be3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -138,14 +138,14 @@ void SmartPtrInitializationCheck::check(
}
std::string SmartPtrInitializationCheck::getSmartPointerDescription(
- const CXXRecordDecl *recordDecl, const ASTContext &context) {
- clang::PrintingPolicy policy = context.getPrintingPolicy();
+ const CXXRecordDecl *RecordDecl, const ASTContext &Context) {
+ const PrintingPolicy Policy = Context.getPrintingPolicy();
- std::string result;
- llvm::raw_string_ostream os(result);
- recordDecl->getNameForDiagnostic(os, policy, /*Qualified=*/true);
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ RecordDecl->getNameForDiagnostic(OS, Policy, /*Qualified=*/true);
- return result;
+ return Result;
}
std::string SmartPtrInitializationCheck::getRawPointerDescription(
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
index adc62ec62d69d..f74df0521a453 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.h
@@ -26,7 +26,7 @@ class SmartPtrInitializationCheck : public ClangTidyCheck {
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
private:
- std::string getSmartPointerDescription(const CXXRecordDecl *PointerExpr,
+ std::string getSmartPointerDescription(const CXXRecordDecl *RecordDecl,
const ASTContext &Context);
std::string getRawPointerDescription(const Expr *PointerExpr,
const ASTContext &Context);
>From 92641025413a007f35ca84591bca077b44e3a4ab Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sat, 8 Aug 2026 12:20:27 +0300
Subject: [PATCH 29/33] refactoring
---
.../bugprone/SmartPtrInitializationCheck.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 5ee4560240be3..5e1ded5109958 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -150,16 +150,16 @@ std::string SmartPtrInitializationCheck::getSmartPointerDescription(
std::string SmartPtrInitializationCheck::getRawPointerDescription(
const Expr *PointerExpr, const ASTContext &Context) {
- std::string Description;
- llvm::raw_string_ostream OS(Description);
-
// Try to get a readable representation of the expression
PrintingPolicy Policy(Context.getLangOpts());
Policy.SuppressSpecifiers = false;
Policy.SuppressTagKeyword = true;
- PointerExpr->printPretty(OS, nullptr, Policy);
- return OS.str();
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ PointerExpr->printPretty(OS, /*PrinterHelper=*/nullptr, Policy);
+
+ return Result;
}
} // namespace clang::tidy::bugprone
>From 40473584c0e1c7da91d2f98c43403e57b0a96c67 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sat, 8 Aug 2026 13:58:01 +0300
Subject: [PATCH 30/33] Fix FP when ternary
---
.../bugprone/SmartPtrInitializationCheck.cpp | 6 ++--
.../bugprone/smart-ptr-initialization.md | 8 +++++
.../smart-ptr-initialization-ternary.cpp | 34 +++++++++++++++++++
3 files changed, 46 insertions(+), 2 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-ternary.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 5e1ded5109958..586b30ca67748 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -87,7 +87,8 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
.bind("method-decl")),
hasArgument(0, PointerArg), unless(HasCustomDeleter),
unless(hasArgument(0, cxxNewExpr())),
- unless(hasArgument(0, ReleaseCallMatcher)));
+ unless(hasArgument(0, ReleaseCallMatcher)),
+ unless(hasArgument(0, conditionalOperator())));
// Matcher for reset() calls
// Exclude reset() calls with custom deleters:
@@ -110,7 +111,8 @@ void SmartPtrInitializationCheck::registerMatchers(MatchFinder *Finder) {
.bind("method-decl")),
hasArgument(0, PointerArg), unless(HasCustomDeleterInReset),
unless(hasArgument(0, cxxNewExpr())),
- unless(hasArgument(0, ReleaseCallMatcher)));
+ unless(hasArgument(0, ReleaseCallMatcher)),
+ unless(hasArgument(0, conditionalOperator())));
Finder->addMatcher(SmartPtrConstructorMatcher, this);
Finder->addMatcher(ResetCallMatcher, this);
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
index bb595ca40584a..fffa564aff8f1 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smart-ptr-initialization.md
@@ -91,6 +91,14 @@ This check only supports smart pointers with shared and unique ownership
semantics. Smart pointers with different semantics, such as
`boost::scoped_ptr`, cannot be used with the current version of this check.
+This check unable to catch relevant cases inside a ternary operator:
+
+ ```cpp
+ std::shared_ptr<A> a(flag ? nullptr : &getA());
+ ```
+
+The warning will never be shown with the current version of this check.
+
## References
- [CERT C++ MEM56-CPP](https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM56-CPP.+Do+not+store+an+already-owned+pointer+value+in+an+unrelated+smart+pointer)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-ternary.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-ternary.cpp
new file mode 100644
index 0000000000000..f7e55f01fc174
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-ternary.cpp
@@ -0,0 +1,34 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-smart-ptr-initialization %t -- -- -I %S/../modernize/Inputs/smart-ptr
+
+
+#include "shared_ptr.h"
+#include "unique_ptr.h"
+
+struct A {
+ int x;
+};
+
+A& getA();
+A* getAPtr();
+bool flag = false;
+
+void test_new_expression_ok() {
+ std::shared_ptr<A> a(flag ? new A() : nullptr);
+ std::unique_ptr<A> b(flag ? nullptr : new A());
+}
+
+void test_release_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
+ std::unique_ptr<A> p2(flag ? p1.release() : nullptr);
+}
+
+void test_new_expression_reset_ok() {
+ std::shared_ptr<A> a;
+ a.reset(flag ? new A() : nullptr);
+ std::unique_ptr<A> b;
+ b.reset(flag ? nullptr : new A());
+}
+
+void test_release_reset_ok(std::unique_ptr<A> p1, std::shared_ptr<A> p3) {
+ std::unique_ptr<A> p2;
+ p2.reset(flag ? p1.release() : nullptr);
+}
>From e1e679bbe202e1f60f313381f8249d7c6c3b2351 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Sat, 8 Aug 2026 14:03:52 +0300
Subject: [PATCH 31/33] lint
---
.../clang-tidy/bugprone/SmartPtrInitializationCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
index 586b30ca67748..958fca36f8f15 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SmartPtrInitializationCheck.cpp
@@ -159,7 +159,7 @@ std::string SmartPtrInitializationCheck::getRawPointerDescription(
std::string Result;
llvm::raw_string_ostream OS(Result);
- PointerExpr->printPretty(OS, /*PrinterHelper=*/nullptr, Policy);
+ PointerExpr->printPretty(OS, /*Helper=*/nullptr, Policy);
return Result;
}
>From 7b9537f398f301278c6791ac7853cef2caaac3b7 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Wed, 12 Aug 2026 12:58:41 +0300
Subject: [PATCH 32/33] more tests
---
.../bugprone/smart-ptr-initialization-array-cxx17.cpp | 4 ++++
.../bugprone/smart-ptr-initialization-array.cpp | 9 +++++++++
.../checkers/bugprone/smart-ptr-initialization.cpp | 10 ++++++++++
3 files changed, 23 insertions(+)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
index 53191742b414a..b02f6309ed6f9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array-cxx17.cpp
@@ -65,6 +65,10 @@ void test_nullptr_ok() {
std::shared_ptr<A[]> a(nullptr);
}
+void test_zero_ok() {
+ std::shared_ptr<A[]> a(0);
+}
+
void test_copy_move_constructor_ok(std::shared_ptr<A[]> sp) {
auto sp2 = sp;
auto sp3 = std::move(sp);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
index ce2504f014ba5..d2224290fb415 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization-array.cpp
@@ -71,6 +71,10 @@ void test_nullptr_ok() {
std::unique_ptr<A[]> b(nullptr);
}
+void test_zero_ok() {
+ std::unique_ptr<A[]> b(0);
+}
+
void test_copy_move_constructor_ok(std::unique_ptr<A[]> up) {
auto up3 = std::move(up);
}
@@ -112,6 +116,11 @@ void test_nullptr_reset_ok() {
b.reset(nullptr);
}
+void test_zero_reset_ok() {
+ std::unique_ptr<A[]> b;
+ b.reset(0);
+}
+
//
// Edge case: should trigger for array new with wrong smart pointer
void test_array_new() {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
index 981cbd7f43945..50f27343a5f3a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smart-ptr-initialization.cpp
@@ -84,6 +84,11 @@ void test_nullptr_ok() {
std::unique_ptr<A> b(nullptr);
}
+void test_zero_ok() {
+ std::shared_ptr<A> a(0);
+ std::unique_ptr<A> b(0);
+}
+
void test_copy_move_constructor_ok(std::shared_ptr<A> sp, std::unique_ptr<A> up) {
auto sp2 = sp;
@@ -144,6 +149,11 @@ void test_nullptr_reset_ok() {
b.reset(nullptr);
}
+void test_zero_reset_ok() {
+ std::unique_ptr<A> b;
+ b.reset(0);
+}
+
void test_reset_ok() {
std::shared_ptr<A> a;
a.reset();
>From 33ca1c3689bc812b05f6b213378fd08cf23ce424 Mon Sep 17 00:00:00 2001
From: denzor200 <denismikhaylov38 at gmail.com>
Date: Wed, 12 Aug 2026 18:34:15 +0300
Subject: [PATCH 33/33] convert rst to md
---
.../docs/clang-tidy/checks/cert/mem56-cpp.md | 10 ++++++++++
.../docs/clang-tidy/checks/cert/mem56-cpp.rst | 10 ----------
2 files changed, 10 insertions(+), 10 deletions(-)
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.md
delete mode 100644 clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.md b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.md
new file mode 100644
index 0000000000000..a83ec0612bea2
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.md
@@ -0,0 +1,10 @@
+```{title} clang-tidy - cert-mem56-cpp
+```
+
+# cert-mem56-cpp
+
+The `cert-mem56-cpp` check is an alias, please see
+[bugprone-smart-ptr-initialization](../bugprone/smart-ptr-initialization.md) for more information.
+
+This check corresponds to the CERT C++ Coding Standard rule
+[MEM56-CPP. Do not store an already-owned pointer value in an unrelated smart pointer](https://cmu-sei.github.io/secure-coding-standards/sei-cert-cpp-coding-standard/rules/memory-management-mem/mem56-cpp).
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
deleted file mode 100644
index c822756ad921b..0000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/cert/mem56-cpp.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-.. title:: clang-tidy - cert-mem56-cpp
-.. meta::
- :http-equiv=refresh: 5;URL=../bugprone/smart-ptr-initialization.html
-
-cert-mem56-cpp
-==============
-
-The `cert-mem56-cpp` check is an alias, please see
-:doc:`bugprone-smart-ptr-initialization <../bugprone/smart-ptr-initialization>`
-for more information.
More information about the cfe-commits
mailing list