balazske updated this revision to Diff 402439. balazske added a comment. Fixed small issues.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D117306/new/ https://reviews.llvm.org/D117306 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/SharedPtrArrayMismatchCheck.cpp clang-tools-extra/clang-tidy/bugprone/SharedPtrArrayMismatchCheck.h clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.cpp clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-shared-ptr-array-mismatch.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-shared-ptr-array-mismatch.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-shared-ptr-array-mismatch.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-shared-ptr-array-mismatch.cpp @@ -0,0 +1,93 @@ +// RUN: %check_clang_tidy %s bugprone-shared-ptr-array-mismatch %t + +namespace std { + +template <typename T> +struct shared_ptr { + template <class Y> + explicit shared_ptr(Y *) {} + template <class Y, class Deleter> + shared_ptr(Y *, Deleter) {} +}; + +} // namespace std + +struct A {}; + +void f1() { + std::shared_ptr<int> P1{new int}; + std::shared_ptr<int> P2{new int[10]}; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + // CHECK-FIXES: std::shared_ptr<int[]> P2{new int[10]}; + std::shared_ptr< int > P3{new int[10]}; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + // CHECK-FIXES: std::shared_ptr< int[] > P3{new int[10]}; + std::shared_ptr<int> P4(new int[10]); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + // CHECK-FIXES: std::shared_ptr<int[]> P4(new int[10]); + new std::shared_ptr<int>(new int[10]); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + std::shared_ptr<int[]> P5(new int[10]); + std::shared_ptr<int> P6(new int[10], [](const int *Ptr) {}); +} + +void f2() { + std::shared_ptr<A> P1(new A); + std::shared_ptr<A> P2(new A[10]); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + // CHECK-FIXES: std::shared_ptr<A[]> P2(new A[10]); + std::shared_ptr<A[]> P3(new A[10]); +} + +void f3() { + std::shared_ptr<int> P1{new int}, P2{new int[10]}, P3{new int[10]}; + // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + // CHECK-MESSAGES: :[[@LINE-2]]:57: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] +} + +struct S { + std::shared_ptr<int> P1; + std::shared_ptr<int> P2{new int[10]}; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + std::shared_ptr<int> P3{new int}, P4{new int[10]}; + // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + S() : P1{new int[10]} {} + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] +}; + +void f_parm(std::shared_ptr<int>); + +void f4() { + f_parm(std::shared_ptr<int>{new int[10]}); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] +} + +std::shared_ptr<int> f_ret() { + return std::shared_ptr<int>(new int[10]); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] +} + +template <class T> +void f_tmpl() { + std::shared_ptr<T> P1{new T[10]}; +} + +void f5() { + f_tmpl<char>(); +} + +#define CHAR_PTR_TYPE std::shared_ptr<char> +#define CHAR_PTR_VAR(X) \ + X { new char[10] } +#define CHAR_PTR_INIT(X, Y) \ + std::shared_ptr<char> X { Y } + +void f6() { + CHAR_PTR_TYPE P1{new char[10]}; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + std::shared_ptr<char> CHAR_PTR_VAR(P2); + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + // CHECK-FIXES: std::shared_ptr<char[]> CHAR_PTR_VAR(P2); + CHAR_PTR_INIT(P3, new char[10]); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] +} Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -84,6 +84,7 @@ `bugprone-posix-return <bugprone-posix-return.html>`_, "Yes" `bugprone-redundant-branch-condition <bugprone-redundant-branch-condition.html>`_, "Yes" `bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_, "Yes" + `bugprone-shared-ptr-array-mismatch <bugprone-shared-ptr-array-mismatch.html>`_, "Yes" `bugprone-signal-handler <bugprone-signal-handler.html>`_, `bugprone-signed-char-misuse <bugprone-signed-char-misuse.html>`_, `bugprone-sizeof-container <bugprone-sizeof-container.html>`_, Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-shared-ptr-array-mismatch.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-shared-ptr-array-mismatch.rst @@ -0,0 +1,31 @@ +.. title:: clang-tidy - bugprone-shared-ptr-array-mismatch + +bugprone-shared-ptr-array-mismatch +================================== + +Finds initializations of C++ shared pointers to non-array type that are +initialized with an array. + +If a shared pointer ``std::shared_ptr<T>`` is initialized with a new-expression +``new T[]`` the memory is not deallocated correctly. The pointer uses plain +``delete`` in this case to deallocate the target memory. Instead a ``delete[]`` +call is needed. A ``std::shared_ptr<T[]>`` calls the correct delete operator. + +The check offers replacement of ``shared_ptr<T>`` to ``shared_ptr<T[]>`` if it +is used at a single variable declaration (one variable in one statement). + +Example: + +.. code-block:: c++ + + std::shared_ptr<Foo> x(new Foo[10]); // -> std::shared_ptr<Foo[]> x(new Foo[10]); + // ^ warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + std::shared_ptr<Foo> x1(new Foo), x2(new Foo[10]); // no replacement + // ^ warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + + std::shared_ptr<Foo> x3(new Foo[10], [](const Foo *ptr) { delete[] ptr; }); // no warning + + struct S { + std::shared_ptr<Foo> x(new Foo[10]); // no replacement in this case + // ^ warning: shared pointer to non-array is initialized with array [bugprone-shared-ptr-array-mismatch] + }; Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -92,6 +92,10 @@ instances from the factory function to class template argument deduction (CTAD), in C++17 and higher. +- New :doc:`bugprone-shared-ptr-array-mismatch <clang-tidy/checks/bugprone-shared-ptr-array-mismatch>` check. + + Finds initializations of C++ shared pointers to non-array type that are initialized with an array. + - New :doc:`bugprone-suspicious-memory-comparison <clang-tidy/checks/bugprone-suspicious-memory-comparison>` check. Index: clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.h @@ -0,0 +1,52 @@ +//===--- SharedPtrArrayMismatchCheck.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_SMARTPTRARRAYMISMATCHCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRARRAYMISMATCHCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Find constructions of smart (unique or shared) pointers where the pointer +/// is declared with non-array target type and an array (created with a +/// new-expression) is passed to it. +class SmartPtrArrayMismatchCheck : public ClangTidyCheck { +public: + SmartPtrArrayMismatchCheck(StringRef Name, ClangTidyContext *Context, + StringRef SmartPointerName); + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus11; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +protected: + using SmartPtrClassMatcher = ast_matchers::internal::BindableMatcher<Decl>; + + /// Returns matcher that match with different smart pointer classes. + /// + /// Requires to bind pointer type (qualType) with PointerTypeN string declared + /// in this class. + virtual SmartPtrClassMatcher getSmartPointerClassMatcher() const = 0; + + static const char PointerTypeN[]; + +private: + StringRef const SmartPointerName; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SMARTPTRARRAYMISMATCHCHECK_H Index: clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SmartPtrArrayMismatchCheck.cpp @@ -0,0 +1,125 @@ +//===--- SmartPtrArrayMismatchCheck.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 "SmartPtrArrayMismatchCheck.h" +#include "../utils/ASTUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +namespace { + +constexpr char ConstructExprN[] = "found_construct_expr"; +constexpr char NewExprN[] = "found_new_expr"; +constexpr char ConstructorN[] = "found_constructor"; + +bool isInSingleDeclStmt(const DeclaratorDecl *D) { + const DynTypedNodeList Parents = + D->getASTContext().getParentMapContext().getParents(*D); + for (const DynTypedNode &PNode : Parents) + if (const auto *PDecl = PNode.get<DeclStmt>()) + return PDecl->isSingleDecl(); + return false; +} + +const DeclaratorDecl *getConstructedVarOrField(const Expr *FoundConstructExpr, + ASTContext &Ctx) { + const DynTypedNodeList ConstructParents = + Ctx.getParentMapContext().getParents(*FoundConstructExpr); + if (ConstructParents.size() != 1) + return nullptr; + const Decl *ParentDecl = ConstructParents.begin()->get<Decl>(); + if (!ParentDecl) + return nullptr; + if (const auto *ParentVar = dyn_cast<VarDecl>(ParentDecl)) + return ParentVar; + if (const auto *ParentField = dyn_cast<FieldDecl>(ParentDecl)) + return ParentField; + + return nullptr; +} + +} // namespace + +const char SmartPtrArrayMismatchCheck::PointerTypeN[] = "pointer_type"; + +SmartPtrArrayMismatchCheck::SmartPtrArrayMismatchCheck( + StringRef Name, ClangTidyContext *Context, StringRef SmartPointerName) + : ClangTidyCheck(Name, Context), SmartPointerName(SmartPointerName) {} + +void SmartPtrArrayMismatchCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) {} + +void SmartPtrArrayMismatchCheck::registerMatchers(MatchFinder *Finder) { + // For both shared and unique pointers, we need to find constructor with + // exactly one parameter that has the pointer type. Other constructors are + // not applicable for this check. + auto FindConstructor = + cxxConstructorDecl(ofClass(getSmartPointerClassMatcher()), + parameterCountIs(1), isExplicit()) + .bind(ConstructorN); + auto FindConstructExpr = + cxxConstructExpr( + hasDeclaration(FindConstructor), argumentCountIs(1), + hasArgument( + 0, cxxNewExpr(isArray(), hasType(pointerType(pointee( + equalsBoundNode(PointerTypeN))))) + .bind(NewExprN))) + .bind(ConstructExprN); + Finder->addMatcher(FindConstructExpr, this); +} + +void SmartPtrArrayMismatchCheck::check(const MatchFinder::MatchResult &Result) { + const auto *FoundNewExpr = Result.Nodes.getNodeAs<CXXNewExpr>(NewExprN); + const auto *FoundConstructExpr = + Result.Nodes.getNodeAs<CXXConstructExpr>(ConstructExprN); + const auto *FoundConstructorDecl = + Result.Nodes.getNodeAs<CXXConstructorDecl>(ConstructorN); + + ASTContext &Ctx = FoundConstructorDecl->getASTContext(); + const DeclaratorDecl *VarOrField = + getConstructedVarOrField(FoundConstructExpr, Ctx); + + auto D = diag(FoundNewExpr->getBeginLoc(), + "%0 pointer to non-array is initialized with array") + << SmartPointerName; + D << FoundNewExpr->getSourceRange(); + + if (VarOrField) { + auto TSTypeLoc = VarOrField->getTypeSourceInfo() + ->getTypeLoc() + .getAsAdjusted<clang::TemplateSpecializationTypeLoc>(); + assert(TSTypeLoc.getNumArgs() >= 1 && + "Matched type should have at least 1 template argument."); + + SourceRange TemplateArgumentRange = TSTypeLoc.getArgLoc(0) + .getTypeSourceInfo() + ->getTypeLoc() + .getLocalSourceRange(); + D << TemplateArgumentRange; + + if (isInSingleDeclStmt(VarOrField)) { + const SourceManager &SM = Ctx.getSourceManager(); + if (!utils::rangeCanBeFixed(TemplateArgumentRange, &SM)) + return; + + SourceLocation InsertLoc = Lexer::getLocForEndOfToken( + TemplateArgumentRange.getEnd(), 0, SM, Ctx.getLangOpts()); + D << FixItHint::CreateInsertion(InsertLoc, "[]"); + } + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/bugprone/SharedPtrArrayMismatchCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SharedPtrArrayMismatchCheck.h @@ -0,0 +1,38 @@ +//===--- SharedPtrArrayMismatchCheck.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_SHAREDPTRARRAYMISMATCHCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SHAREDPTRARRAYMISMATCHCHECK_H + +#include "SmartPtrArrayMismatchCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Find `std::shared_ptr<T>(new T[...])`, replace it (if applicable) with +/// `std::shared_ptr<T[]>(new T[...])`. +/// +/// Example: +/// +/// \code +/// std::shared_ptr<int> PtrArr{new int[10]}; +/// \endcode +class SharedPtrArrayMismatchCheck : public SmartPtrArrayMismatchCheck { +public: + SharedPtrArrayMismatchCheck(StringRef Name, ClangTidyContext *Context); + +protected: + virtual SmartPtrClassMatcher getSmartPointerClassMatcher() const; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SHAREDPTRARRAYMISMATCHCHECK_H Index: clang-tools-extra/clang-tidy/bugprone/SharedPtrArrayMismatchCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/SharedPtrArrayMismatchCheck.cpp @@ -0,0 +1,31 @@ +//===--- SharedPtrArrayMismatchCheck.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 "SharedPtrArrayMismatchCheck.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +SharedPtrArrayMismatchCheck::SharedPtrArrayMismatchCheck( + StringRef Name, ClangTidyContext *Context) + : SmartPtrArrayMismatchCheck(Name, Context, "shared") {} + +SharedPtrArrayMismatchCheck::SmartPtrClassMatcher +SharedPtrArrayMismatchCheck::getSmartPointerClassMatcher() const { + return classTemplateSpecializationDecl( + hasName("::std::shared_ptr"), templateArgumentCountIs(1), + hasTemplateArgument( + 0, templateArgument(refersToType(qualType().bind(PointerTypeN))))); +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -37,6 +37,8 @@ PosixReturnCheck.cpp RedundantBranchConditionCheck.cpp ReservedIdentifierCheck.cpp + SharedPtrArrayMismatchCheck.cpp + SmartPtrArrayMismatchCheck.cpp SignalHandlerCheck.cpp SignedCharMisuseCheck.cpp SizeofContainerCheck.cpp Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -42,6 +42,7 @@ #include "PosixReturnCheck.h" #include "RedundantBranchConditionCheck.h" #include "ReservedIdentifierCheck.h" +#include "SharedPtrArrayMismatchCheck.h" #include "SignalHandlerCheck.h" #include "SignedCharMisuseCheck.h" #include "SizeofContainerCheck.h" @@ -143,6 +144,8 @@ "bugprone-posix-return"); CheckFactories.registerCheck<ReservedIdentifierCheck>( "bugprone-reserved-identifier"); + CheckFactories.registerCheck<SharedPtrArrayMismatchCheck>( + "bugprone-shared-ptr-array-mismatch"); CheckFactories.registerCheck<SignalHandlerCheck>("bugprone-signal-handler"); CheckFactories.registerCheck<SignedCharMisuseCheck>( "bugprone-signed-char-misuse");
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits