https://github.com/vbvictor updated https://github.com/llvm/llvm-project/pull/121291
>From 42e03bb9cc9bd815476b0a3f06ac5f58826e3708 Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Fri, 31 Jan 2025 19:29:05 +0300 Subject: [PATCH 1/6] [clang-tidy] add new check bugprone-reset-ambiguous-call --- .../bugprone/BugproneTidyModule.cpp | 3 + .../clang-tidy/bugprone/CMakeLists.txt | 1 + .../SmartptrResetAmbiguousCallCheck.cpp | 146 +++++++++++ .../SmartptrResetAmbiguousCallCheck.h | 37 +++ clang-tools-extra/docs/ReleaseNotes.rst | 6 + .../smartptr-reset-ambiguous-call.rst | 47 ++++ .../docs/clang-tidy/checks/list.rst | 1 + ...r-reset-ambiguous-call-custom-pointers.cpp | 72 ++++++ .../smartptr-reset-ambiguous-call.cpp | 239 ++++++++++++++++++ 9 files changed, 552 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index c5f0b5b28418f..a01d0e384ab73 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -64,6 +64,7 @@ #include "SignedCharMisuseCheck.h" #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" +#include "SmartptrResetAmbiguousCallCheck.h" #include "SpuriouslyWakeUpFunctionsCheck.h" #include "StandaloneEmptyCheck.h" #include "StringConstructorCheck.h" @@ -207,6 +208,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-sizeof-container"); CheckFactories.registerCheck<SizeofExpressionCheck>( "bugprone-sizeof-expression"); + CheckFactories.registerCheck<SmartptrResetAmbiguousCallCheck>( + "bugprone-smartptr-reset-ambiguous-call"); CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>( "bugprone-spuriously-wake-up-functions"); CheckFactories.registerCheck<StandaloneEmptyCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index e8309c68b7fca..7fd6f4994f537 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -65,6 +65,7 @@ add_clang_library(clangTidyBugproneModule STATIC SizeofContainerCheck.cpp SizeofExpressionCheck.cpp SmartPtrArrayMismatchCheck.cpp + SmartptrResetAmbiguousCallCheck.cpp SpuriouslyWakeUpFunctionsCheck.cpp StandaloneEmptyCheck.cpp StringConstructorCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.cpp new file mode 100644 index 0000000000000..326a5665179d7 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.cpp @@ -0,0 +1,146 @@ +//===--- SmartptrResetAmbiguousCallCheck.cpp - clang-tidy -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SmartptrResetAmbiguousCallCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +namespace { + +AST_MATCHER_P(CallExpr, everyArgumentMatches, + ast_matchers::internal::Matcher<Expr>, InnerMatcher) { + for (const auto *Arg : Node.arguments()) { + if (!InnerMatcher.matches(*Arg, Finder, Builder)) + return false; + } + + return true; +} + +AST_MATCHER(CXXMethodDecl, hasOnlyDefaultParameters) { + for (const auto *Param : Node.parameters()) { + if (!Param->hasDefaultArg()) + return false; + } + + return true; +} + +const auto DefaultSmartPointers = "::std::shared_ptr;::std::unique_ptr"; +} // namespace + +SmartptrResetAmbiguousCallCheck::SmartptrResetAmbiguousCallCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + SmartPointers(utils::options::parseStringList( + Options.get("SmartPointers", DefaultSmartPointers))) {} + +void SmartptrResetAmbiguousCallCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "SmartPointers", + utils::options::serializeStringList(SmartPointers)); +} + +void SmartptrResetAmbiguousCallCheck::registerMatchers(MatchFinder *Finder) { + const auto IsSmartptr = hasAnyName(SmartPointers); + + const auto ResetMethod = + cxxMethodDecl(hasName("reset"), hasOnlyDefaultParameters()); + + const auto TypeWithReset = + anyOf(cxxRecordDecl(hasMethod(ResetMethod)), + classTemplateSpecializationDecl( + hasSpecializedTemplate(classTemplateDecl(has(ResetMethod))))); + + const auto SmartptrWithBugproneReset = classTemplateSpecializationDecl( + IsSmartptr, + hasTemplateArgument( + 0, templateArgument(refersToType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(TypeWithReset))))))); + + // Find a.reset() calls + Finder->addMatcher( + cxxMemberCallExpr(callee(memberExpr(member(hasName("reset")))), + everyArgumentMatches(cxxDefaultArgExpr()), + on(expr(hasType(SmartptrWithBugproneReset)))) + .bind("smartptrResetCall"), + this); + + // Find a->reset() calls + Finder->addMatcher( + cxxMemberCallExpr( + callee(memberExpr( + member(ResetMethod), + hasObjectExpression( + cxxOperatorCallExpr( + hasOverloadedOperatorName("->"), + hasArgument( + 0, expr(hasType( + classTemplateSpecializationDecl(IsSmartptr))))) + .bind("OpCall")))), + everyArgumentMatches(cxxDefaultArgExpr())) + .bind("objectResetCall"), + this); +} + +void SmartptrResetAmbiguousCallCheck::check( + const MatchFinder::MatchResult &Result) { + + if (const auto *SmartptrResetCall = + Result.Nodes.getNodeAs<CXXMemberCallExpr>("smartptrResetCall")) { + const auto *Member = cast<MemberExpr>(SmartptrResetCall->getCallee()); + + diag(SmartptrResetCall->getBeginLoc(), + "be explicit when calling 'reset()' on a smart pointer with a " + "pointee that has a 'reset()' method"); + + diag(SmartptrResetCall->getBeginLoc(), "assign the pointer to 'nullptr'", + DiagnosticIDs::Note) + << FixItHint::CreateReplacement( + SourceRange(Member->getOperatorLoc(), + Member->getOperatorLoc().getLocWithOffset(0)), + " =") + << FixItHint::CreateReplacement( + SourceRange(Member->getMemberLoc(), + SmartptrResetCall->getEndLoc()), + " nullptr"); + return; + } + + if (const auto *ObjectResetCall = + Result.Nodes.getNodeAs<CXXMemberCallExpr>("objectResetCall")) { + const auto *Arrow = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("OpCall"); + + const CharSourceRange SmartptrSourceRange = + Lexer::getAsCharRange(Arrow->getArg(0)->getSourceRange(), + *Result.SourceManager, getLangOpts()); + + diag(ObjectResetCall->getBeginLoc(), + "be explicit when calling 'reset()' on a pointee of a smart pointer"); + + diag(ObjectResetCall->getBeginLoc(), + "use dereference to call 'reset' method of the pointee", + DiagnosticIDs::Note) + << FixItHint::CreateInsertion(SmartptrSourceRange.getBegin(), "(*") + << FixItHint::CreateInsertion(SmartptrSourceRange.getEnd(), ")") + << FixItHint::CreateReplacement( + CharSourceRange::getCharRange( + Arrow->getOperatorLoc(), + Arrow->getOperatorLoc().getLocWithOffset(2)), + "."); + } +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.h b/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.h new file mode 100644 index 0000000000000..474bcf1804581 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.h @@ -0,0 +1,37 @@ +//===--- SmartptrResetAmbiguousCallCheck.h - clang-tidy ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRRESETAMBIGUOUSCALLCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRRESETAMBIGUOUSCALLCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Finds potentially erroneous calls to 'reset' method on smart pointers when +/// the pointee type also has a 'reset' method +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.html +class SmartptrResetAmbiguousCallCheck : public ClangTidyCheck { +public: + SmartptrResetAmbiguousCallCheck(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; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + +private: + const std::vector<StringRef> SmartPointers; +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRRESETAMBIGUOUSCALLCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 3bddeeda06e06..ef48acf958c9e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -91,6 +91,12 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ +- New :doc:`bugprone-smartptr-reset-ambiguous-call + <clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call>` check. + + Finds potentially erroneous calls to ``reset`` method on smart pointers when + the pointee type also has a ``reset`` method. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.rst new file mode 100644 index 0000000000000..263105e420813 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.rst @@ -0,0 +1,47 @@ +.. title:: clang-tidy - bugprone-smartptr-reset-ambiguous-call + +bugprone-smartptr-reset-ambiguous-call +====================================== + +Finds potentially erroneous calls to ``reset`` method on smart pointers when +the pointee type also has a ``reset`` method. Having a ``reset`` method in +both classes makes it easy to accidentally make the pointer null when +intending to reset the underlying object. + +.. code-block:: c++ + + struct Resettable { + void reset() { /* Own reset logic */ } + }; + + auto ptr = std::make_unique<Resettable>(); + + ptr->reset(); // Calls underlying reset method + ptr.reset(); // Makes the pointer null + +Both calls are valid C++ code, but the second one might not be what the +developer intended, as it destroys the pointed-to object rather than resetting +its state. It's easy to make such a typo because the difference between +``.`` and ``->`` is really small. + +The recommended approach is to make the intent explicit by using either member +access or direct assignment: + +.. code-block:: c++ + + std::unique_ptr<Resettable> ptr = std::make_unique<Resettable>(); + + (*ptr).reset(); // Clearly calls underlying reset method + ptr = nullptr; // Clearly makes the pointer null + +The default smart pointers that are considered are ``std::unique_ptr``, +``std::shared_ptr``. To specify other smart pointers or other classes use the +:option:`SmartPointers` option. + +Options +------- + +.. option:: SmartPointers + + Semicolon-separated list of class names of custom smart pointers. + Default value is `::std::unique_ptr;::std::shared_ptr`. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 7b9b905ef7671..ec6dd26b78977 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -132,6 +132,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-smartptr-reset-ambiguous-call <bugprone/smartptr-reset-ambiguous-call>`, "Yes" :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`, :doc:`bugprone-standalone-empty <bugprone/standalone-empty>`, "Yes" :doc:`bugprone-string-constructor <bugprone/string-constructor>`, "Yes" diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp new file mode 100644 index 0000000000000..bcb2498bd2043 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp @@ -0,0 +1,72 @@ +// RUN: %check_clang_tidy %s bugprone-smartptr-reset-ambiguous-call %t \ +// RUN: -config='{CheckOptions: \ +// RUN: {bugprone-smartptr-reset-ambiguous-call.SmartPointers: "::std::unique_ptr;boost::shared_ptr"}}' \ +// RUN: --fix-notes -- + +namespace std { + +template <typename T> +struct unique_ptr { + T& operator*() const; + T* operator->() const; + void reset(T* p = nullptr); +}; + +template <typename T> +struct shared_ptr { + T& operator*() const; + T* operator->() const; + void reset(); + void reset(T*); +}; + +} // namespace std + +namespace boost { + +template <typename T> +struct shared_ptr { + T& operator*() const; + T* operator->() const; + void reset(); +}; + +} // namespace boost + +struct Resettable { + void reset(); + void doSomething(); +}; + +void Positive() { + std::unique_ptr<Resettable> u; + u.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: u = nullptr; + u->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*u).reset(); + + boost::shared_ptr<Resettable> s; + s.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: s = nullptr; + s->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*s).reset(); +} + +void Negative() { + std::shared_ptr<Resettable> s_ptr; + s_ptr.reset(); + s_ptr->reset(); + s_ptr->doSomething(); + + std::unique_ptr<Resettable> u_ptr; + u_ptr.reset(nullptr); + u_ptr->doSomething(); +} \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp new file mode 100644 index 0000000000000..4227733404f6b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp @@ -0,0 +1,239 @@ +// RUN: %check_clang_tidy %s bugprone-smartptr-reset-ambiguous-call %t --fix-notes -- + +namespace std { + +template <typename T> +struct unique_ptr { + T& operator*() const; + T* operator->() const; + void reset(T* p = nullptr); +}; + +template <typename T> +struct shared_ptr { + T& operator*() const; + T* operator->() const; + void reset(); + void reset(T*); +}; + +} // namespace std + +struct Resettable { + void reset(); + void doSomething(); +}; + +struct ResettableWithParam { + void reset(int a); + void doSomething(); +}; + +struct ResettableWithDefaultParams { + void reset(int a = 0, double b = 0.0); + void doSomething(); +}; + +struct NonResettable { + void doSomething(); +}; + +void Positive() { + std::unique_ptr<Resettable> u; + u.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: u = nullptr; + u->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*u).reset(); + + std::shared_ptr<Resettable> s; + s.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: s = nullptr; + s->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*s).reset(); + + std::unique_ptr<std::unique_ptr<int>> uu_ptr; + uu_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: uu_ptr = nullptr; + uu_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*uu_ptr).reset(); + + std::unique_ptr<std::shared_ptr<int>> su_ptr; + su_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: su_ptr = nullptr; + su_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*su_ptr).reset(); + + std::unique_ptr<ResettableWithDefaultParams> rd; + rd.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: rd = nullptr; + rd->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*rd).reset(); + + std::unique_ptr<std::shared_ptr<std::unique_ptr<Resettable>>> nested_ptr; + nested_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: nested_ptr = nullptr; + nested_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*nested_ptr).reset(); + (*nested_ptr).reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: (*nested_ptr) = nullptr; + (*nested_ptr)->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*(*nested_ptr)).reset(); + (**nested_ptr).reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: (**nested_ptr) = nullptr; + (**nested_ptr)->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*(**nested_ptr)).reset(); +} + +void Negative() { + std::unique_ptr<Resettable> u_ptr; + u_ptr.reset(nullptr); + u_ptr->doSomething(); + + std::shared_ptr<Resettable> s_ptr; + s_ptr.reset(nullptr); + s_ptr->doSomething(); + + Resettable* raw_ptr; + raw_ptr->reset(); + raw_ptr->doSomething(); + + Resettable resettable; + resettable.reset(); + resettable.doSomething(); + + std::unique_ptr<ResettableWithParam> u_ptr_param; + u_ptr_param.reset(); + u_ptr_param.reset(nullptr); + u_ptr_param->reset(0); + + std::unique_ptr<NonResettable> u_ptr_no_reset; + u_ptr_no_reset.reset(); + + std::shared_ptr<ResettableWithParam> s_ptr_param; + s_ptr_param.reset(); + s_ptr_param->reset(0); + s_ptr_param->doSomething(); + + std::shared_ptr<NonResettable> s_ptr_no_reset; + s_ptr_no_reset.reset(); + + std::unique_ptr<ResettableWithDefaultParams> u_ptr_default_params; + u_ptr_default_params.reset(nullptr); + u_ptr_default_params->reset(1); + u_ptr_default_params->reset(1, 2.0); +} + +template <typename T> +void TemplatePositiveTest() { + std::unique_ptr<T> u_ptr; + + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*u_ptr).reset(); + + std::shared_ptr<T> s_ptr; + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' + // CHECK-FIXES: s_ptr = nullptr; + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*s_ptr).reset(); +} + +template <typename T> +void TemplatNegativeTestTypeWithReset() { + std::unique_ptr<T> u_ptr; + u_ptr.reset(); + u_ptr->reset(0); + + std::shared_ptr<T> s_ptr; + s_ptr.reset(); + s_ptr->reset(0); +} + +template <typename T> +void TemplatNegativeTestTypeWithoutReset() { + std::unique_ptr<T> u_ptr; + u_ptr.reset(); + + std::unique_ptr<T> s_ptr; + s_ptr.reset(); +} + +void instantiate() { + TemplatePositiveTest<Resettable>(); + TemplatePositiveTest<std::unique_ptr<int>>(); + TemplatePositiveTest<std::shared_ptr<int>>(); + TemplatNegativeTestTypeWithReset<ResettableWithParam>(); + TemplatNegativeTestTypeWithoutReset<NonResettable>(); +} + +struct S { + void foo() { + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: assign the pointer to 'nullptr' + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*u_ptr).reset(); + u_ptr.reset(nullptr); + u_ptr->doSomething(); + + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: assign the pointer to 'nullptr' + // CHECK-FIXES: s_ptr = nullptr; + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a pointee of a smart pointer + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: use dereference to call 'reset' method of the pointee + // CHECK-FIXES: (*s_ptr).reset(); + s_ptr.reset(nullptr); + + ptr.reset(); + } + + std::unique_ptr<Resettable> u_ptr; + std::unique_ptr<std::shared_ptr<int>> s_ptr; + std::unique_ptr<NonResettable> ptr; +}; >From 851afcc804ad3c55e3bd837e6dadeb8166c4c6ad Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Fri, 31 Jan 2025 19:33:02 +0300 Subject: [PATCH 2/6] [clang-tidy] add newline in test file --- .../bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp index bcb2498bd2043..2b8944c39619d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp @@ -69,4 +69,4 @@ void Negative() { std::unique_ptr<Resettable> u_ptr; u_ptr.reset(nullptr); u_ptr->doSomething(); -} \ No newline at end of file +} >From 21a6fdce045ed7d88fff38812fd568a4342ed845 Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Mon, 17 Feb 2025 12:00:06 +0300 Subject: [PATCH 3/6] [clang-tidy] renamed bugprone-smartptr-reset-ambiguous-call to readability-ambiguous-smartptr-reset-call, fixed pr comments --- .../bugprone/BugproneTidyModule.cpp | 3 - .../clang-tidy/bugprone/CMakeLists.txt | 1 - .../AmbiguousSmartptrResetCallCheck.cpp} | 29 ++- .../AmbiguousSmartptrResetCallCheck.h} | 18 +- .../clang-tidy/readability/CMakeLists.txt | 1 + .../readability/ReadabilityTidyModule.cpp | 3 + clang-tools-extra/docs/ReleaseNotes.rst | 4 +- .../docs/clang-tidy/checks/list.rst | 2 +- .../ambiguous-smartptr-reset-call.rst} | 15 +- ...r-reset-ambiguous-call-custom-pointers.cpp | 72 ------ .../smartptr-reset-ambiguous-call.cpp | 239 ------------------ ...us-smartptr-reset-call-custom-pointers.cpp | 68 +++++ .../ambiguous-smartptr-reset-call.cpp | 239 ++++++++++++++++++ 13 files changed, 347 insertions(+), 347 deletions(-) rename clang-tools-extra/clang-tidy/{bugprone/SmartptrResetAmbiguousCallCheck.cpp => readability/AmbiguousSmartptrResetCallCheck.cpp} (83%) rename clang-tools-extra/clang-tidy/{bugprone/SmartptrResetAmbiguousCallCheck.h => readability/AmbiguousSmartptrResetCallCheck.h} (59%) rename clang-tools-extra/docs/clang-tidy/checks/{bugprone/smartptr-reset-ambiguous-call.rst => readability/ambiguous-smartptr-reset-call.rst} (70%) delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call-custom-pointers.cpp create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index a01d0e384ab73..c5f0b5b28418f 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -64,7 +64,6 @@ #include "SignedCharMisuseCheck.h" #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" -#include "SmartptrResetAmbiguousCallCheck.h" #include "SpuriouslyWakeUpFunctionsCheck.h" #include "StandaloneEmptyCheck.h" #include "StringConstructorCheck.h" @@ -208,8 +207,6 @@ class BugproneModule : public ClangTidyModule { "bugprone-sizeof-container"); CheckFactories.registerCheck<SizeofExpressionCheck>( "bugprone-sizeof-expression"); - CheckFactories.registerCheck<SmartptrResetAmbiguousCallCheck>( - "bugprone-smartptr-reset-ambiguous-call"); CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>( "bugprone-spuriously-wake-up-functions"); CheckFactories.registerCheck<StandaloneEmptyCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index 7fd6f4994f537..e8309c68b7fca 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -65,7 +65,6 @@ add_clang_library(clangTidyBugproneModule STATIC SizeofContainerCheck.cpp SizeofExpressionCheck.cpp SmartPtrArrayMismatchCheck.cpp - SmartptrResetAmbiguousCallCheck.cpp SpuriouslyWakeUpFunctionsCheck.cpp StandaloneEmptyCheck.cpp StringConstructorCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.cpp b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp similarity index 83% rename from clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.cpp rename to clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp index 326a5665179d7..86dc9a33c0755 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp @@ -1,4 +1,4 @@ -//===--- SmartptrResetAmbiguousCallCheck.cpp - clang-tidy -----------------===// +//===--- AmbiguousSmartptrResetCallCheck.cpp - clang-tidy -----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "SmartptrResetAmbiguousCallCheck.h" +#include "AmbiguousSmartptrResetCallCheck.h" #include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -15,7 +15,7 @@ using namespace clang::ast_matchers; -namespace clang::tidy::bugprone { +namespace clang::tidy::readability { namespace { @@ -41,19 +41,19 @@ AST_MATCHER(CXXMethodDecl, hasOnlyDefaultParameters) { const auto DefaultSmartPointers = "::std::shared_ptr;::std::unique_ptr"; } // namespace -SmartptrResetAmbiguousCallCheck::SmartptrResetAmbiguousCallCheck( +AmbiguousSmartptrResetCallCheck::AmbiguousSmartptrResetCallCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), SmartPointers(utils::options::parseStringList( Options.get("SmartPointers", DefaultSmartPointers))) {} -void SmartptrResetAmbiguousCallCheck::storeOptions( +void AmbiguousSmartptrResetCallCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "SmartPointers", utils::options::serializeStringList(SmartPointers)); } -void SmartptrResetAmbiguousCallCheck::registerMatchers(MatchFinder *Finder) { +void AmbiguousSmartptrResetCallCheck::registerMatchers(MatchFinder *Finder) { const auto IsSmartptr = hasAnyName(SmartPointers); const auto ResetMethod = @@ -95,7 +95,7 @@ void SmartptrResetAmbiguousCallCheck::registerMatchers(MatchFinder *Finder) { this); } -void SmartptrResetAmbiguousCallCheck::check( +void AmbiguousSmartptrResetCallCheck::check( const MatchFinder::MatchResult &Result) { if (const auto *SmartptrResetCall = @@ -103,10 +103,11 @@ void SmartptrResetAmbiguousCallCheck::check( const auto *Member = cast<MemberExpr>(SmartptrResetCall->getCallee()); diag(SmartptrResetCall->getBeginLoc(), - "be explicit when calling 'reset()' on a smart pointer with a " - "pointee that has a 'reset()' method"); + "ambiguous call to 'reset()' on a smart pointer with pointee that " + "also has a 'reset()' method, prefer more explicit approach"); - diag(SmartptrResetCall->getBeginLoc(), "assign the pointer to 'nullptr'", + diag(SmartptrResetCall->getBeginLoc(), + "consider assigning the pointer to 'nullptr' here", DiagnosticIDs::Note) << FixItHint::CreateReplacement( SourceRange(Member->getOperatorLoc(), @@ -128,10 +129,12 @@ void SmartptrResetAmbiguousCallCheck::check( *Result.SourceManager, getLangOpts()); diag(ObjectResetCall->getBeginLoc(), - "be explicit when calling 'reset()' on a pointee of a smart pointer"); + "ambiguous call to 'reset()' on a pointee of a smart pointer, prefer " + "more explicit approach"); diag(ObjectResetCall->getBeginLoc(), - "use dereference to call 'reset' method of the pointee", + "consider dereferencing smart pointer to call 'reset' method " + "of the pointee here", DiagnosticIDs::Note) << FixItHint::CreateInsertion(SmartptrSourceRange.getBegin(), "(*") << FixItHint::CreateInsertion(SmartptrSourceRange.getEnd(), ")") @@ -143,4 +146,4 @@ void SmartptrResetAmbiguousCallCheck::check( } } -} // namespace clang::tidy::bugprone +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.h b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.h similarity index 59% rename from clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.h rename to clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.h index 474bcf1804581..05932e59e7928 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SmartptrResetAmbiguousCallCheck.h +++ b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.h @@ -1,4 +1,4 @@ -//===--- SmartptrResetAmbiguousCallCheck.h - clang-tidy ---------*- C++ -*-===// +//===--- AmbiguousSmartptrResetCallCheck.h - clang-tidy ---------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,21 +6,21 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRRESETAMBIGUOUSCALLCHECK_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRRESETAMBIGUOUSCALLCHECK_H +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AMBIGUOUSSMARTPTRRESETCALLCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AMBIGUOUSSMARTPTRRESETCALLCHECK_H #include "../ClangTidyCheck.h" -namespace clang::tidy::bugprone { +namespace clang::tidy::readability { /// Finds potentially erroneous calls to 'reset' method on smart pointers when /// the pointee type also has a 'reset' method /// /// For the user-facing documentation see: -/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.html -class SmartptrResetAmbiguousCallCheck : public ClangTidyCheck { +/// http://clang.llvm.org/extra/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.html +class AmbiguousSmartptrResetCallCheck : public ClangTidyCheck { public: - SmartptrResetAmbiguousCallCheck(StringRef Name, ClangTidyContext *Context); + AmbiguousSmartptrResetCallCheck(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; @@ -32,6 +32,6 @@ class SmartptrResetAmbiguousCallCheck : public ClangTidyCheck { const std::vector<StringRef> SmartPointers; }; -} // namespace clang::tidy::bugprone +} // namespace clang::tidy::readability -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRRESETAMBIGUOUSCALLCHECK_H +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AMBIGUOUSSMARTPTRRESETCALLCHECK_H diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index 8f303c51e1b0d..4be1a8f831339 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS ) add_clang_library(clangTidyReadabilityModule STATIC + AmbiguousSmartptrResetCallCheck.cpp AvoidConstParamsInDecls.cpp AvoidNestedConditionalOperatorCheck.cpp AvoidReturnWithVoidValueCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index d61c0ba39658e..4c0812f0e6793 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AmbiguousSmartptrResetCallCheck.h" #include "AvoidConstParamsInDecls.h" #include "AvoidNestedConditionalOperatorCheck.h" #include "AvoidReturnWithVoidValueCheck.h" @@ -68,6 +69,8 @@ namespace readability { class ReadabilityModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck<AmbiguousSmartptrResetCallCheck>( + "readability-ambiguous-smartptr-reset-call"); CheckFactories.registerCheck<AvoidConstParamsInDecls>( "readability-avoid-const-params-in-decls"); CheckFactories.registerCheck<AvoidNestedConditionalOperatorCheck>( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index ef48acf958c9e..ab3b1a1133038 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -91,8 +91,8 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ -- New :doc:`bugprone-smartptr-reset-ambiguous-call - <clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call>` check. +- New :doc:`readability-ambiguous-smartptr-reset-call + <clang-tidy/checks/readability/ambiguous-smartptr-reset-call>` check. Finds potentially erroneous calls to ``reset`` method on smart pointers when the pointee type also has a ``reset`` method. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index ec6dd26b78977..f205ca64523bf 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -132,7 +132,6 @@ 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-smartptr-reset-ambiguous-call <bugprone/smartptr-reset-ambiguous-call>`, "Yes" :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`, :doc:`bugprone-standalone-empty <bugprone/standalone-empty>`, "Yes" :doc:`bugprone-string-constructor <bugprone/string-constructor>`, "Yes" @@ -353,6 +352,7 @@ Clang-Tidy Checks :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" diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst similarity index 70% rename from clang-tools-extra/docs/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.rst rename to clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst index 263105e420813..a34f6767339bf 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/smartptr-reset-ambiguous-call.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst @@ -1,7 +1,7 @@ -.. title:: clang-tidy - bugprone-smartptr-reset-ambiguous-call +.. title:: clang-tidy - readability-ambiguous-smartptr-reset-call -bugprone-smartptr-reset-ambiguous-call -====================================== +readability-ambiguous-smartptr-reset-call +========================================= Finds potentially erroneous calls to ``reset`` method on smart pointers when the pointee type also has a ``reset`` method. Having a ``reset`` method in @@ -35,13 +35,14 @@ access or direct assignment: ptr = nullptr; // Clearly makes the pointer null The default smart pointers that are considered are ``std::unique_ptr``, -``std::shared_ptr``. To specify other smart pointers or other classes use the -:option:`SmartPointers` option. +``std::shared_ptr``, ``boost::unique_ptr``, ``boost::shared_ptr``. To specify +other smart pointers or other classes use the :option:`SmartPointers` option. Options ------- .. option:: SmartPointers - Semicolon-separated list of class names of custom smart pointers. - Default value is `::std::unique_ptr;::std::shared_ptr`. + Semicolon-separated list of fully qualified class names of custom smart + pointers. Default value is `::std::unique_ptr;::std::shared_ptr; + ::boost::unique_ptr;::boost::shared_ptr`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp deleted file mode 100644 index 2b8944c39619d..0000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call-custom-pointers.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// RUN: %check_clang_tidy %s bugprone-smartptr-reset-ambiguous-call %t \ -// RUN: -config='{CheckOptions: \ -// RUN: {bugprone-smartptr-reset-ambiguous-call.SmartPointers: "::std::unique_ptr;boost::shared_ptr"}}' \ -// RUN: --fix-notes -- - -namespace std { - -template <typename T> -struct unique_ptr { - T& operator*() const; - T* operator->() const; - void reset(T* p = nullptr); -}; - -template <typename T> -struct shared_ptr { - T& operator*() const; - T* operator->() const; - void reset(); - void reset(T*); -}; - -} // namespace std - -namespace boost { - -template <typename T> -struct shared_ptr { - T& operator*() const; - T* operator->() const; - void reset(); -}; - -} // namespace boost - -struct Resettable { - void reset(); - void doSomething(); -}; - -void Positive() { - std::unique_ptr<Resettable> u; - u.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: u = nullptr; - u->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*u).reset(); - - boost::shared_ptr<Resettable> s; - s.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: s = nullptr; - s->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*s).reset(); -} - -void Negative() { - std::shared_ptr<Resettable> s_ptr; - s_ptr.reset(); - s_ptr->reset(); - s_ptr->doSomething(); - - std::unique_ptr<Resettable> u_ptr; - u_ptr.reset(nullptr); - u_ptr->doSomething(); -} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp deleted file mode 100644 index 4227733404f6b..0000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/smartptr-reset-ambiguous-call.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// RUN: %check_clang_tidy %s bugprone-smartptr-reset-ambiguous-call %t --fix-notes -- - -namespace std { - -template <typename T> -struct unique_ptr { - T& operator*() const; - T* operator->() const; - void reset(T* p = nullptr); -}; - -template <typename T> -struct shared_ptr { - T& operator*() const; - T* operator->() const; - void reset(); - void reset(T*); -}; - -} // namespace std - -struct Resettable { - void reset(); - void doSomething(); -}; - -struct ResettableWithParam { - void reset(int a); - void doSomething(); -}; - -struct ResettableWithDefaultParams { - void reset(int a = 0, double b = 0.0); - void doSomething(); -}; - -struct NonResettable { - void doSomething(); -}; - -void Positive() { - std::unique_ptr<Resettable> u; - u.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: u = nullptr; - u->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*u).reset(); - - std::shared_ptr<Resettable> s; - s.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: s = nullptr; - s->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*s).reset(); - - std::unique_ptr<std::unique_ptr<int>> uu_ptr; - uu_ptr.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: uu_ptr = nullptr; - uu_ptr->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*uu_ptr).reset(); - - std::unique_ptr<std::shared_ptr<int>> su_ptr; - su_ptr.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: su_ptr = nullptr; - su_ptr->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*su_ptr).reset(); - - std::unique_ptr<ResettableWithDefaultParams> rd; - rd.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: rd = nullptr; - rd->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*rd).reset(); - - std::unique_ptr<std::shared_ptr<std::unique_ptr<Resettable>>> nested_ptr; - nested_ptr.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: nested_ptr = nullptr; - nested_ptr->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*nested_ptr).reset(); - (*nested_ptr).reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: (*nested_ptr) = nullptr; - (*nested_ptr)->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*(*nested_ptr)).reset(); - (**nested_ptr).reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: (**nested_ptr) = nullptr; - (**nested_ptr)->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*(**nested_ptr)).reset(); -} - -void Negative() { - std::unique_ptr<Resettable> u_ptr; - u_ptr.reset(nullptr); - u_ptr->doSomething(); - - std::shared_ptr<Resettable> s_ptr; - s_ptr.reset(nullptr); - s_ptr->doSomething(); - - Resettable* raw_ptr; - raw_ptr->reset(); - raw_ptr->doSomething(); - - Resettable resettable; - resettable.reset(); - resettable.doSomething(); - - std::unique_ptr<ResettableWithParam> u_ptr_param; - u_ptr_param.reset(); - u_ptr_param.reset(nullptr); - u_ptr_param->reset(0); - - std::unique_ptr<NonResettable> u_ptr_no_reset; - u_ptr_no_reset.reset(); - - std::shared_ptr<ResettableWithParam> s_ptr_param; - s_ptr_param.reset(); - s_ptr_param->reset(0); - s_ptr_param->doSomething(); - - std::shared_ptr<NonResettable> s_ptr_no_reset; - s_ptr_no_reset.reset(); - - std::unique_ptr<ResettableWithDefaultParams> u_ptr_default_params; - u_ptr_default_params.reset(nullptr); - u_ptr_default_params->reset(1); - u_ptr_default_params->reset(1, 2.0); -} - -template <typename T> -void TemplatePositiveTest() { - std::unique_ptr<T> u_ptr; - - u_ptr.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: u_ptr = nullptr; - u_ptr->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*u_ptr).reset(); - - std::shared_ptr<T> s_ptr; - s_ptr.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: assign the pointer to 'nullptr' - // CHECK-FIXES: s_ptr = nullptr; - s_ptr->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:3: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*s_ptr).reset(); -} - -template <typename T> -void TemplatNegativeTestTypeWithReset() { - std::unique_ptr<T> u_ptr; - u_ptr.reset(); - u_ptr->reset(0); - - std::shared_ptr<T> s_ptr; - s_ptr.reset(); - s_ptr->reset(0); -} - -template <typename T> -void TemplatNegativeTestTypeWithoutReset() { - std::unique_ptr<T> u_ptr; - u_ptr.reset(); - - std::unique_ptr<T> s_ptr; - s_ptr.reset(); -} - -void instantiate() { - TemplatePositiveTest<Resettable>(); - TemplatePositiveTest<std::unique_ptr<int>>(); - TemplatePositiveTest<std::shared_ptr<int>>(); - TemplatNegativeTestTypeWithReset<ResettableWithParam>(); - TemplatNegativeTestTypeWithoutReset<NonResettable>(); -} - -struct S { - void foo() { - u_ptr.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:5: note: assign the pointer to 'nullptr' - // CHECK-FIXES: u_ptr = nullptr; - u_ptr->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:5: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*u_ptr).reset(); - u_ptr.reset(nullptr); - u_ptr->doSomething(); - - s_ptr.reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a smart pointer with a pointee that has a 'reset()' method - // CHECK-MESSAGES: :[[@LINE-2]]:5: note: assign the pointer to 'nullptr' - // CHECK-FIXES: s_ptr = nullptr; - s_ptr->reset(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: be explicit when calling 'reset()' on a pointee of a smart pointer - // CHECK-MESSAGES: :[[@LINE-2]]:5: note: use dereference to call 'reset' method of the pointee - // CHECK-FIXES: (*s_ptr).reset(); - s_ptr.reset(nullptr); - - ptr.reset(); - } - - std::unique_ptr<Resettable> u_ptr; - std::unique_ptr<std::shared_ptr<int>> s_ptr; - std::unique_ptr<NonResettable> ptr; -}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call-custom-pointers.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call-custom-pointers.cpp new file mode 100644 index 0000000000000..7dc6745ada16b --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call-custom-pointers.cpp @@ -0,0 +1,68 @@ +// RUN: %check_clang_tidy %s readability-ambiguous-smartptr-reset-call %t \ +// RUN: -config='{CheckOptions: \ +// RUN: {readability-ambiguous-smartptr-reset-call.SmartPointers: "::std::unique_ptr;::other_ptr"}}' \ +// RUN: --fix-notes -- + +namespace std { + +template <typename T> +struct unique_ptr { + T& operator*() const; + T* operator->() const; + void reset(T* p = nullptr); +}; + +template <typename T> +struct shared_ptr { + T& operator*() const; + T* operator->() const; + void reset(); + void reset(T*); +}; + +} // namespace std + +template <typename T> +struct other_ptr { + T& operator*() const; + T* operator->() const; + void reset(); +}; + +struct Resettable { + void reset(); + void doSomething(); +}; + +void Positive() { + std::unique_ptr<Resettable> u; + u.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u = nullptr; + u->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u).reset(); + + other_ptr<Resettable> s; + s.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s = nullptr; + s->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s).reset(); +} + +void Negative() { + std::shared_ptr<Resettable> s_ptr; + s_ptr.reset(); + s_ptr->reset(); + s_ptr->doSomething(); + + std::unique_ptr<Resettable> u_ptr; + u_ptr.reset(nullptr); + u_ptr->doSomething(); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp new file mode 100644 index 0000000000000..8b74e287af46e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp @@ -0,0 +1,239 @@ +// RUN: %check_clang_tidy %s readability-ambiguous-smartptr-reset-call %t --fix-notes -- + +namespace std { + +template <typename T> +struct unique_ptr { + T& operator*() const; + T* operator->() const; + void reset(T* p = nullptr); +}; + +template <typename T> +struct shared_ptr { + T& operator*() const; + T* operator->() const; + void reset(); + void reset(T*); +}; + +} // namespace std + +struct Resettable { + void reset(); + void doSomething(); +}; + +struct ResettableWithParam { + void reset(int a); + void doSomething(); +}; + +struct ResettableWithDefaultParams { + void reset(int a = 0, double b = 0.0); + void doSomething(); +}; + +struct NonResettable { + void doSomething(); +}; + +void Positive() { + std::unique_ptr<Resettable> u; + u.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u = nullptr; + u->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u).reset(); + + std::shared_ptr<Resettable> s; + s.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s = nullptr; + s->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s).reset(); + + std::unique_ptr<std::unique_ptr<int>> uu_ptr; + uu_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: uu_ptr = nullptr; + uu_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*uu_ptr).reset(); + + std::unique_ptr<std::shared_ptr<int>> su_ptr; + su_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: su_ptr = nullptr; + su_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*su_ptr).reset(); + + std::unique_ptr<ResettableWithDefaultParams> rd; + rd.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: rd = nullptr; + rd->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*rd).reset(); + + std::unique_ptr<std::shared_ptr<std::unique_ptr<Resettable>>> nested_ptr; + nested_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: nested_ptr = nullptr; + nested_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*nested_ptr).reset(); + (*nested_ptr).reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: (*nested_ptr) = nullptr; + (*nested_ptr)->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*(*nested_ptr)).reset(); + (**nested_ptr).reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: (**nested_ptr) = nullptr; + (**nested_ptr)->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*(**nested_ptr)).reset(); +} + +void Negative() { + std::unique_ptr<Resettable> u_ptr; + u_ptr.reset(nullptr); + u_ptr->doSomething(); + + std::shared_ptr<Resettable> s_ptr; + s_ptr.reset(nullptr); + s_ptr->doSomething(); + + Resettable* raw_ptr; + raw_ptr->reset(); + raw_ptr->doSomething(); + + Resettable resettable; + resettable.reset(); + resettable.doSomething(); + + std::unique_ptr<ResettableWithParam> u_ptr_param; + u_ptr_param.reset(); + u_ptr_param.reset(nullptr); + u_ptr_param->reset(0); + + std::unique_ptr<NonResettable> u_ptr_no_reset; + u_ptr_no_reset.reset(); + + std::shared_ptr<ResettableWithParam> s_ptr_param; + s_ptr_param.reset(); + s_ptr_param->reset(0); + s_ptr_param->doSomething(); + + std::shared_ptr<NonResettable> s_ptr_no_reset; + s_ptr_no_reset.reset(); + + std::unique_ptr<ResettableWithDefaultParams> u_ptr_default_params; + u_ptr_default_params.reset(nullptr); + u_ptr_default_params->reset(1); + u_ptr_default_params->reset(1, 2.0); +} + +template <typename T> +void TemplatePositiveTest() { + std::unique_ptr<T> u_ptr; + + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u_ptr).reset(); + + std::shared_ptr<T> s_ptr; + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s_ptr = nullptr; + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s_ptr).reset(); +} + +template <typename T> +void TemplatNegativeTestTypeWithReset() { + std::unique_ptr<T> u_ptr; + u_ptr.reset(); + u_ptr->reset(0); + + std::shared_ptr<T> s_ptr; + s_ptr.reset(); + s_ptr->reset(0); +} + +template <typename T> +void TemplatNegativeTestTypeWithoutReset() { + std::unique_ptr<T> u_ptr; + u_ptr.reset(); + + std::unique_ptr<T> s_ptr; + s_ptr.reset(); +} + +void instantiate() { + TemplatePositiveTest<Resettable>(); + TemplatePositiveTest<std::unique_ptr<int>>(); + TemplatePositiveTest<std::shared_ptr<int>>(); + TemplatNegativeTestTypeWithReset<ResettableWithParam>(); + TemplatNegativeTestTypeWithoutReset<NonResettable>(); +} + +struct S { + void foo() { + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u_ptr).reset(); + u_ptr.reset(nullptr); + u_ptr->doSomething(); + + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s_ptr = nullptr; + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s_ptr).reset(); + s_ptr.reset(nullptr); + + ptr.reset(); + } + + std::unique_ptr<Resettable> u_ptr; + std::unique_ptr<std::shared_ptr<int>> s_ptr; + std::unique_ptr<NonResettable> ptr; +}; >From 2ad06940391f3d0d8bbacc94f305f763fdf6ec93 Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Mon, 17 Feb 2025 23:23:16 +0300 Subject: [PATCH 4/6] [clang-tidy] add typedef and using processing, enchances docs with std:optional --- .../AmbiguousSmartptrResetCallCheck.cpp | 26 +-- .../ambiguous-smartptr-reset-call.rst | 9 +- .../ambiguous-smartptr-reset-call.cpp | 174 ++++++++++++++++++ 3 files changed, 192 insertions(+), 17 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp index 86dc9a33c0755..b84fefd2c2814 100644 --- a/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp @@ -38,7 +38,9 @@ AST_MATCHER(CXXMethodDecl, hasOnlyDefaultParameters) { return true; } -const auto DefaultSmartPointers = "::std::shared_ptr;::std::unique_ptr"; +const auto DefaultSmartPointers = + "::std::shared_ptr;::std::unique_ptr;::std::optional;" + "::boost::shared_ptr;::boost::scoped_ptr"; } // namespace AmbiguousSmartptrResetCallCheck::AmbiguousSmartptrResetCallCheck( @@ -64,17 +66,18 @@ void AmbiguousSmartptrResetCallCheck::registerMatchers(MatchFinder *Finder) { classTemplateSpecializationDecl( hasSpecializedTemplate(classTemplateDecl(has(ResetMethod))))); - const auto SmartptrWithBugproneReset = classTemplateSpecializationDecl( - IsSmartptr, - hasTemplateArgument( - 0, templateArgument(refersToType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(TypeWithReset))))))); + const auto SmartptrWithReset = hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(classTemplateSpecializationDecl( + IsSmartptr, + hasTemplateArgument( + 0, templateArgument(refersToType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(TypeWithReset))))))))))); // Find a.reset() calls Finder->addMatcher( - cxxMemberCallExpr(callee(memberExpr(member(hasName("reset")))), + cxxMemberCallExpr(callee(memberExpr(member(ResetMethod))), everyArgumentMatches(cxxDefaultArgExpr()), - on(expr(hasType(SmartptrWithBugproneReset)))) + on(expr(SmartptrWithReset))) .bind("smartptrResetCall"), this); @@ -84,11 +87,8 @@ void AmbiguousSmartptrResetCallCheck::registerMatchers(MatchFinder *Finder) { callee(memberExpr( member(ResetMethod), hasObjectExpression( - cxxOperatorCallExpr( - hasOverloadedOperatorName("->"), - hasArgument( - 0, expr(hasType( - classTemplateSpecializationDecl(IsSmartptr))))) + cxxOperatorCallExpr(hasOverloadedOperatorName("->"), + hasArgument(0, expr(SmartptrWithReset))) .bind("OpCall")))), everyArgumentMatches(cxxDefaultArgExpr())) .bind("objectResetCall"), diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst index a34f6767339bf..e76aeb93796ab 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst @@ -34,9 +34,10 @@ access or direct assignment: (*ptr).reset(); // Clearly calls underlying reset method ptr = nullptr; // Clearly makes the pointer null -The default smart pointers that are considered are ``std::unique_ptr``, -``std::shared_ptr``, ``boost::unique_ptr``, ``boost::shared_ptr``. To specify -other smart pointers or other classes use the :option:`SmartPointers` option. +The default smart pointers and classes that are considered are +``std::unique_ptr``, ``std::shared_ptr``, ``std::optional``, +``boost::shared_ptr``, ``boost::scoped_ptr``. To specify other smart pointers +or other classes use the :option:`SmartPointers` option. Options ------- @@ -45,4 +46,4 @@ Options Semicolon-separated list of fully qualified class names of custom smart pointers. Default value is `::std::unique_ptr;::std::shared_ptr; - ::boost::unique_ptr;::boost::shared_ptr`. + ::std::optional;::boost::unique_ptr;::boost::shared_ptr`. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp index 8b74e287af46e..1175bfd95ad11 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp @@ -237,3 +237,177 @@ struct S { std::unique_ptr<std::shared_ptr<int>> s_ptr; std::unique_ptr<NonResettable> ptr; }; + + +typedef std::unique_ptr<Resettable> TypedefResettableUniquePtr; +typedef std::shared_ptr<Resettable> TypedefResettableSharedPtr; + +void TypedefPositive() { + TypedefResettableUniquePtr u_ptr; + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u_ptr).reset(); + + TypedefResettableSharedPtr s_ptr; + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s_ptr = nullptr; + + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s_ptr).reset(); +} + +using UsingResettableUniquePtr = std::unique_ptr<Resettable>; +using UsingResettableSharedPtr = std::shared_ptr<Resettable>; + +void UsingPositive() { + UsingResettableUniquePtr u_ptr; + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u_ptr).reset(); + + UsingResettableSharedPtr s_ptr; + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s_ptr = nullptr; + + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s_ptr).reset(); +} + +template<typename T> +using UsingUniquePtr = std::unique_ptr<T>; +template<typename T> +using UsingSharedPtr = std::shared_ptr<T>; + +void UsingTemplatePositive() { + UsingUniquePtr<Resettable> u_ptr; + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u_ptr).reset(); + + UsingSharedPtr<Resettable> s_ptr; + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s_ptr = nullptr; + + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s_ptr).reset(); +} + +template<typename T> +void UsingByTemplatePositive() { + UsingUniquePtr<T> u_ptr; + u_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: u_ptr = nullptr; + u_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*u_ptr).reset(); + + UsingSharedPtr<T> s_ptr; + s_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: s_ptr = nullptr; + + s_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*s_ptr).reset(); +} + +void instantiate2() { + UsingByTemplatePositive<Resettable>(); +} + + +// Check other default pointers and classes. +namespace std { + +template <typename T> +struct optional { + T& operator*() const; + T* operator->() const; + void reset(); +}; + +} // namespace std + +namespace boost { + +template <typename T> +struct scoped_ptr { + T& operator*() const; + T* operator->() const; + void reset(T* p = 0); +}; + +template <typename T> +struct shared_ptr { + T& operator*() const; + T* operator->() const; + void reset(); + void reset(T*); +}; + +} // namespace boost + +void PositiveOtherClasses() { + boost::scoped_ptr<Resettable> sc; + sc.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: sc = nullptr; + sc->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*sc).reset(); + + boost::shared_ptr<Resettable> sh; + sh.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: sh = nullptr; + sh->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*sh).reset(); + + std::optional<Resettable> o; + o.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: o = nullptr; + o->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*o).reset(); +} + >From 1ad9edae69b6e1076c1899577c1f07b1fba70b28 Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Tue, 18 Feb 2025 12:01:33 +0300 Subject: [PATCH 5/6] [clang-tidy] refactored matchers and enchances tests --- .../AmbiguousSmartptrResetCallCheck.cpp | 90 ++++++++----------- .../ambiguous-smartptr-reset-call.cpp | 38 ++++++++ 2 files changed, 74 insertions(+), 54 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp index b84fefd2c2814..87784b4883458 100644 --- a/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/AmbiguousSmartptrResetCallCheck.cpp @@ -12,6 +12,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Lex/Lexer.h" +#include <utility> using namespace clang::ast_matchers; @@ -19,16 +20,6 @@ namespace clang::tidy::readability { namespace { -AST_MATCHER_P(CallExpr, everyArgumentMatches, - ast_matchers::internal::Matcher<Expr>, InnerMatcher) { - for (const auto *Arg : Node.arguments()) { - if (!InnerMatcher.matches(*Arg, Finder, Builder)) - return false; - } - - return true; -} - AST_MATCHER(CXXMethodDecl, hasOnlyDefaultParameters) { for (const auto *Param : Node.parameters()) { if (!Param->hasDefaultArg()) @@ -66,63 +57,32 @@ void AmbiguousSmartptrResetCallCheck::registerMatchers(MatchFinder *Finder) { classTemplateSpecializationDecl( hasSpecializedTemplate(classTemplateDecl(has(ResetMethod))))); - const auto SmartptrWithReset = hasType(hasUnqualifiedDesugaredType( + const auto SmartptrWithReset = expr(hasType(hasUnqualifiedDesugaredType( recordType(hasDeclaration(classTemplateSpecializationDecl( IsSmartptr, hasTemplateArgument( 0, templateArgument(refersToType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(TypeWithReset))))))))))); + recordType(hasDeclaration(TypeWithReset)))))))))))); - // Find a.reset() calls - Finder->addMatcher( - cxxMemberCallExpr(callee(memberExpr(member(ResetMethod))), - everyArgumentMatches(cxxDefaultArgExpr()), - on(expr(SmartptrWithReset))) - .bind("smartptrResetCall"), - this); - - // Find a->reset() calls Finder->addMatcher( cxxMemberCallExpr( - callee(memberExpr( - member(ResetMethod), - hasObjectExpression( - cxxOperatorCallExpr(hasOverloadedOperatorName("->"), - hasArgument(0, expr(SmartptrWithReset))) - .bind("OpCall")))), - everyArgumentMatches(cxxDefaultArgExpr())) - .bind("objectResetCall"), + callee(ResetMethod), + unless(hasAnyArgument(expr(unless(cxxDefaultArgExpr())))), + anyOf(on(SmartptrWithReset), + on(cxxOperatorCallExpr(hasOverloadedOperatorName("->"), + hasArgument(0, SmartptrWithReset)) + .bind("ArrowOp")))) + .bind("MemberCall"), this); } void AmbiguousSmartptrResetCallCheck::check( const MatchFinder::MatchResult &Result) { - if (const auto *SmartptrResetCall = - Result.Nodes.getNodeAs<CXXMemberCallExpr>("smartptrResetCall")) { - const auto *Member = cast<MemberExpr>(SmartptrResetCall->getCallee()); - - diag(SmartptrResetCall->getBeginLoc(), - "ambiguous call to 'reset()' on a smart pointer with pointee that " - "also has a 'reset()' method, prefer more explicit approach"); - - diag(SmartptrResetCall->getBeginLoc(), - "consider assigning the pointer to 'nullptr' here", - DiagnosticIDs::Note) - << FixItHint::CreateReplacement( - SourceRange(Member->getOperatorLoc(), - Member->getOperatorLoc().getLocWithOffset(0)), - " =") - << FixItHint::CreateReplacement( - SourceRange(Member->getMemberLoc(), - SmartptrResetCall->getEndLoc()), - " nullptr"); - return; - } - - if (const auto *ObjectResetCall = - Result.Nodes.getNodeAs<CXXMemberCallExpr>("objectResetCall")) { - const auto *Arrow = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("OpCall"); + if (const auto *Arrow = + Result.Nodes.getNodeAs<CXXOperatorCallExpr>("ArrowOp")) { + const auto *ObjectResetCall = + Result.Nodes.getNodeAs<CXXMemberCallExpr>("MemberCall"); const CharSourceRange SmartptrSourceRange = Lexer::getAsCharRange(Arrow->getArg(0)->getSourceRange(), @@ -143,6 +103,28 @@ void AmbiguousSmartptrResetCallCheck::check( Arrow->getOperatorLoc(), Arrow->getOperatorLoc().getLocWithOffset(2)), "."); + return; + } + + if (const auto *SmartptrResetCall = + Result.Nodes.getNodeAs<CXXMemberCallExpr>("MemberCall")) { + const auto *Member = cast<MemberExpr>(SmartptrResetCall->getCallee()); + + diag(SmartptrResetCall->getBeginLoc(), + "ambiguous call to 'reset()' on a smart pointer with pointee that " + "also has a 'reset()' method, prefer more explicit approach"); + + diag(SmartptrResetCall->getBeginLoc(), + "consider assigning the pointer to 'nullptr' here", + DiagnosticIDs::Note) + << FixItHint::CreateReplacement( + SourceRange(Member->getOperatorLoc(), + Member->getOperatorLoc().getLocWithOffset(0)), + " =") + << FixItHint::CreateReplacement( + SourceRange(Member->getMemberLoc(), + SmartptrResetCall->getEndLoc()), + " nullptr"); } } diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp index 1175bfd95ad11..5eb2aefd2c8fe 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/ambiguous-smartptr-reset-call.cpp @@ -19,6 +19,13 @@ struct shared_ptr { } // namespace std +template <typename T> +struct non_default_reset_ptr { + T& operator*() const; + T* operator->() const; + void reset(T* p); +}; + struct Resettable { void reset(); void doSomething(); @@ -153,6 +160,10 @@ void Negative() { u_ptr_default_params.reset(nullptr); u_ptr_default_params->reset(1); u_ptr_default_params->reset(1, 2.0); + + non_default_reset_ptr<Resettable> non_default_reset_ptr; + non_default_reset_ptr.reset(new Resettable); + non_default_reset_ptr->reset(); } template <typename T> @@ -347,6 +358,33 @@ void instantiate2() { UsingByTemplatePositive<Resettable>(); } +void NestedUsingPositive() { + UsingUniquePtr<UsingSharedPtr<TypedefResettableUniquePtr>> nested_ptr; + nested_ptr.reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: nested_ptr = nullptr; + nested_ptr->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*nested_ptr).reset(); + (*nested_ptr).reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: (*nested_ptr) = nullptr; + (*nested_ptr)->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*(*nested_ptr)).reset(); + (**nested_ptr).reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a smart pointer with pointee that also has a 'reset()' method, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider assigning the pointer to 'nullptr' here + // CHECK-FIXES: (**nested_ptr) = nullptr; + (**nested_ptr)->reset(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: ambiguous call to 'reset()' on a pointee of a smart pointer, prefer more explicit approach + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: consider dereferencing smart pointer to call 'reset' method of the pointee here + // CHECK-FIXES: (*(**nested_ptr)).reset(); +} // Check other default pointers and classes. namespace std { >From 9e9cd4ee3bd9050687a5b1eb0757790639abc560 Mon Sep 17 00:00:00 2001 From: Victor Baranov <bar.victor.2...@gmail.com> Date: Fri, 21 Feb 2025 07:59:40 +0300 Subject: [PATCH 6/6] fix review --- .../checks/readability/ambiguous-smartptr-reset-call.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst index e76aeb93796ab..a5df701013852 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/ambiguous-smartptr-reset-call.rst @@ -46,4 +46,4 @@ Options Semicolon-separated list of fully qualified class names of custom smart pointers. Default value is `::std::unique_ptr;::std::shared_ptr; - ::std::optional;::boost::unique_ptr;::boost::shared_ptr`. + ::std::optional;::boost::scoped_ptr;::boost::shared_ptr`. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits