diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index bab1167fb15ff..67eaf01eb9155 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -23,6 +23,7 @@ add_clang_library(clangTidyModernizeModule STATIC RedundantVoidArgCheck.cpp ReplaceAutoPtrCheck.cpp ReplaceDisallowCopyAndAssignMacroCheck.cpp + ReplaceWithStdCopyCheck.cpp ReplaceRandomShuffleCheck.cpp ReturnBracedInitListCheck.cpp ShrinkToFitCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index fc46c72982fdc..c1c3f8f0f5a72 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -25,6 +25,7 @@ #include "ReplaceAutoPtrCheck.h" #include "ReplaceDisallowCopyAndAssignMacroCheck.h" #include "ReplaceRandomShuffleCheck.h" +#include "ReplaceWithStdCopyCheck.h" #include "ReturnBracedInitListCheck.h" #include "ShrinkToFitCheck.h" #include "TypeTraitsCheck.h" @@ -94,6 +95,8 @@ class ModernizeModule : public ClangTidyModule { "modernize-replace-auto-ptr"); CheckFactories.registerCheck( "modernize-replace-disallow-copy-and-assign-macro"); + CheckFactories.registerCheck( + "modernize-replace-with-std-copy"); CheckFactories.registerCheck( "modernize-replace-random-shuffle"); CheckFactories.registerCheck( @@ -110,11 +113,11 @@ class ModernizeModule : public ClangTidyModule { CheckFactories.registerCheck( "modernize-use-default-member-init"); CheckFactories.registerCheck("modernize-use-emplace"); - CheckFactories.registerCheck("modernize-use-equals-default"); + CheckFactories.registerCheck( + "modernize-use-equals-default"); CheckFactories.registerCheck( "modernize-use-equals-delete"); - CheckFactories.registerCheck( - "modernize-use-nodiscard"); + CheckFactories.registerCheck("modernize-use-nodiscard"); CheckFactories.registerCheck("modernize-use-noexcept"); CheckFactories.registerCheck("modernize-use-nullptr"); CheckFactories.registerCheck("modernize-use-override"); diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceWithStdCopyCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceWithStdCopyCheck.cpp new file mode 100644 index 0000000000000..214183ccd0e49 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceWithStdCopyCheck.cpp @@ -0,0 +1,503 @@ +//===--- ReplaceWithStdCopyCheck.cpp - 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 +// +//===----------------------------------------------------------------------===// + +#include "ReplaceWithStdCopyCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/StringRef.h" +#include + +using namespace clang; +using namespace clang::ast_matchers; + +namespace clang::tidy { + +namespace modernize { +namespace { + +constexpr llvm::StringLiteral ExpressionRef = "ReplaceWithStdCopyCheckRef"; +constexpr llvm::StringLiteral ReturnValueDiscardedRef = + "ReturnValueDiscardedRef"; + +namespace ptrarg { + +struct Refs { + llvm::StringLiteral AsContainer; + llvm::StringLiteral AsCArray; + size_t FallbackParameterIdx; + llvm::StringLiteral ValueType; + llvm::StringLiteral PtrCastFnReturnType; +}; + +template auto createPtrArgMatcher() { + constexpr Refs Refs = RefsT::Refs; + + auto AllowedContainerNamesM = + hasAnyName("::std::vector", "::std::basic_string", "::std::array", + "::std::basic_string_view", "::std::span"); + + // Note: a problem with this matcher is that it automatically desugars the + // template argument type, so e.g. std::vector will bind + // ValueType to int and not std::int32_t + auto AllowedContainerTypeM = hasUnqualifiedDesugaredType( + recordType(hasDeclaration(recordDecl(classTemplateSpecializationDecl( + AllowedContainerNamesM, + hasTemplateArgument(0, templateArgument(refersToType( + qualType().bind(Refs.ValueType))))))))); + + auto CArrayTypeM = + constantArrayType(hasElementType(qualType().bind(Refs.ValueType))); + + auto VariantContainerM = + expr(hasType(AllowedContainerTypeM)).bind(Refs.AsContainer); + + auto VariantCArrayM = expr(hasType(hasUnqualifiedDesugaredType(CArrayTypeM))) + .bind(Refs.AsCArray); + + auto StdDataReturnM = + returns(pointerType(pointee(qualType().bind(Refs.PtrCastFnReturnType)))); + + auto StdDataMemberDeclM = cxxMethodDecl(hasAnyName("data", "c_str"), + parameterCountIs(0), StdDataReturnM); + + auto StdDataFreeDeclM = functionDecl(hasAnyName("::std::data", "::data"), + parameterCountIs(1), StdDataReturnM); + + auto StdDataMemberCallM = cxxMemberCallExpr( + callee(StdDataMemberDeclM), argumentCountIs(0), + on(expr(hasType(AllowedContainerTypeM)).bind(Refs.AsContainer))); + + auto ArrayOrContainerM = expr(anyOf(VariantCArrayM, VariantContainerM)); + + auto StdDataFreeCallM = callExpr(callee(StdDataFreeDeclM), argumentCountIs(1), + hasArgument(0, ArrayOrContainerM)); + + return expr(anyOf(StdDataMemberCallM, StdDataFreeCallM, VariantCArrayM)); +} + +namespace tag { +struct RawPtr {}; +struct Container {}; +struct CArray {}; +} // namespace tag +struct PtrArg { + std::variant Tag; + const Expr &Node; +}; + +template +PtrArg extractNode(const CallExpr &CallNode, + const MatchFinder::MatchResult &Result) { + constexpr Refs Refs = RefT::Refs; + if (const auto *Node = Result.Nodes.getNodeAs(Refs.AsCArray); + Node != nullptr) + return {tag::CArray{}, *Node}; + if (const auto *Node = Result.Nodes.getNodeAs(Refs.AsContainer); + Node != nullptr) + return {tag::Container{}, *Node}; + return {tag::RawPtr{}, *CallNode.getArg(Refs.FallbackParameterIdx)}; +} + +template +const QualType *extractValueType(const MatchFinder::MatchResult &Result) { + constexpr Refs Refs = RefT::Refs; + + // checking equality is done here as opposed to when matching because the + // equalsBoundNode matcher depends on the match order. + // Already considered swapping the role of the node + // matchers, having one bind and the other match using equalsBoundNode, but + // PtrCastFnReturnType is only present in some scenarios, + // so it's not applicable. + const auto *MaybeRetType = + Result.Nodes.getNodeAs(Refs.PtrCastFnReturnType); + const auto *ValueType = Result.Nodes.getNodeAs(Refs.ValueType); + + // stripping qualifiers is necessary in cases like when matching a call + // to const T* vector::data() const; + // the container value_type (char) is not const qualified, + // but the return type of data() is. + if (MaybeRetType != nullptr and + MaybeRetType->getCanonicalType().getUnqualifiedType() != + ValueType->getCanonicalType().getUnqualifiedType()) + return nullptr; + return ValueType; +} +} // namespace ptrarg + +namespace dst { +constexpr size_t ArgIndex = 0; +struct RefT { + static constexpr ptrarg::Refs Refs = {"Dst::AsContainer", "Dst::AsCArray", + ArgIndex, "Dst::ValueType", + "Dst::PtrCastFnReturnType"}; +}; + +auto createMatcher() { return ptrarg::createPtrArgMatcher(); } +auto extractNode(const CallExpr &CallNode, + const MatchFinder::MatchResult &Result) { + return ptrarg::extractNode(CallNode, Result); +} +auto extractValueType(const MatchFinder::MatchResult &Result) { + return ptrarg::extractValueType(Result); +} +} // namespace dst + +namespace src { +constexpr size_t ArgIndex = 1; + +struct SrcRefsT { + static constexpr ptrarg::Refs Refs = {"Src::AsContainer", "Src::AsCArray", + ArgIndex, "Src::ValueType", + "Src::PtrCastFnReturnType"}; +}; + +auto createMatcher() { return ptrarg::createPtrArgMatcher(); } +auto extractNode(const CallExpr &CallNode, + const MatchFinder::MatchResult &Result) { + return ptrarg::extractNode(CallNode, Result); +} +auto extractValueType(const MatchFinder::MatchResult &Result) { + return ptrarg::extractValueType(Result); +} +} // namespace src + +namespace size { +constexpr size_t ArgIndex = 2; + +namespace variant { +struct SizeOfCArray { + const Expr &Array; +}; +struct NSizeOfType { + const Expr &N; + const QualType &Arg; +}; +struct SizeOfDivSizeOf { + const Expr &Array; + const QualType &DivSizeOfType; +}; +} // namespace variant +using SizeArg = std::variant; + +static constexpr struct Refs { + llvm::StringLiteral SizeOfCArray; + llvm::StringLiteral NSizeOfTypeN; + llvm::StringLiteral NSizeOfTypeArg; + llvm::StringLiteral SizeOfDivSizeOfArray; + llvm::StringLiteral SizeOfDivSizeOfArg; +} Refs = {"Size::SizeOfCArray", "Size::NSizeOfTypeN", "Size::NSizeOfTypeArg", + "Size::SizeOfDivSizeOfArray", "Size::SizeOfDivSizeOfArg"}; + +auto createMatcher() { + // NOTE: this check does not detect common, invalid patterns + // like sizeof(_) * sizeof(_), etc. since other checks exist for those. + + // patterns of the size argument that may be modified : + // 1. sizeof(arr) + // - invalid if callee is a wide variant, + // should be sizeof(arr) / sizeof(wchar_like) + // - otherwise -> std::size(arr) + // 2. N * sizeof(value_like) + // - invalid if callee is a wide variant, should just be N + // - otherwise when sizeof(value_like) == sizeof(value_type) -> N + // 3. sizeof(arr) / sizeof(value_like) + // - valid if callee is a wide variant -> std::size(arr) + // - valid if sizeof(value_like) == 1 + // - invalid otherwise, will fall back to (expr) / sizeof(value_type) + + constexpr auto SizeOfCArray = [](llvm::StringLiteral Ref) { + return sizeOfExpr( + has(expr(hasType(hasUnqualifiedDesugaredType(constantArrayType()))) + .bind(Ref))); + }; + + constexpr auto SizeOfType = [](llvm::StringLiteral Ref) { + return sizeOfExpr(hasArgumentOfType(qualType().bind(Ref))); + }; + + auto NSizeOfTypeM = binaryOperator( + hasOperatorName("*"), hasOperands(expr().bind(Refs.NSizeOfTypeN), + SizeOfType(Refs.NSizeOfTypeArg))); + + auto SizeOfDivSizeOfM = binaryOperator( + hasOperatorName("/"), hasOperands(SizeOfCArray(Refs.SizeOfDivSizeOfArray), + SizeOfType(Refs.SizeOfDivSizeOfArg))); + + return expr( + anyOf(NSizeOfTypeM, SizeOfCArray(Refs.SizeOfCArray), SizeOfDivSizeOfM)); +} + +SizeArg extractNode(const CallExpr &CallNode, + const MatchFinder::MatchResult &Result) { + auto TryExtractFromBoundTags = + [&Nodes = Result.Nodes]() -> std::optional { + if (const auto *Array = Nodes.getNodeAs(Refs.SizeOfCArray); + Array != nullptr) + return variant::SizeOfCArray{*Array}; + llvm::errs() << __LINE__ << '\n'; + if (const auto *N = Nodes.getNodeAs(Refs.NSizeOfTypeN); + N != nullptr) { + if (const auto *Arg = Nodes.getNodeAs(Refs.NSizeOfTypeArg); + Arg != nullptr) + return variant::NSizeOfType{*N, *Arg}; + return std::nullopt; + } + if (const auto *Array = Nodes.getNodeAs(Refs.SizeOfDivSizeOfArray); + Array != nullptr) { + if (const auto *SizeOfArg = + Nodes.getNodeAs(Refs.SizeOfDivSizeOfArg); + SizeOfArg != nullptr) + return variant::SizeOfDivSizeOf{*Array, *SizeOfArg}; + return std::nullopt; + } + return std::nullopt; + }; + + if (auto MaybeSize = TryExtractFromBoundTags(); MaybeSize.has_value()) + return *MaybeSize; + return CallNode.getArg(ArgIndex); +} +} // namespace size + +auto createCalleeMatcher(bool FlagMemcpy) { + if (FlagMemcpy) + return hasAnyName("::memmove", "::std::memmove", "::memcpy", + "::std::memcpy", "::wmemmove", "::std::wmemmove", + "::wmemcpy", "::std::wmemcpy"); + return hasAnyName("::memmove", "::std::memmove", "::wmemmove", + "::std::wmemmove"); +} + +} // namespace + +ReplaceWithStdCopyCheck::ReplaceWithStdCopyCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + Inserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()), + FlagMemcpy(Options.getLocalOrGlobal("FlagMemcpy", false)) {} + +void ReplaceWithStdCopyCheck::registerMatchers(MatchFinder *Finder) { + const auto ReturnValueUsedM = + hasParent(compoundStmt().bind(ReturnValueDiscardedRef)); + + const auto OffendingDeclM = + functionDecl(parameterCountIs(3), createCalleeMatcher(FlagMemcpy)); + + const auto ExpressionM = callExpr( + callee(OffendingDeclM), optionally(ReturnValueUsedM), + allOf(optionally(hasArgument(dst::ArgIndex, dst::createMatcher())), + optionally(hasArgument(src::ArgIndex, src::createMatcher())), + optionally(hasArgument(size::ArgIndex, size::createMatcher())))); + Finder->addMatcher(ExpressionM.bind(ExpressionRef), this); +} + +void ReplaceWithStdCopyCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + Inserter.registerPreprocessor(PP); +} + +void ReplaceWithStdCopyCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IncludeStyle", Inserter.getStyle()); + Options.store(Opts, "FlagMemcpy", FlagMemcpy); +} + +void ReplaceWithStdCopyCheck::check(const MatchFinder::MatchResult &Result) { + const auto &CallNode = *Result.Nodes.getNodeAs(ExpressionRef); + + auto Dst = dst::extractNode(CallNode, Result); + auto Src = src::extractNode(CallNode, Result); + auto Size = size::extractNode(CallNode, Result); + + const auto *DstVT = dst::extractValueType(Result); + if (DstVT == nullptr) + return; + const auto *SrcVT = src::extractValueType(Result); + if (SrcVT == nullptr) + return; + + auto ExprAsString = [&](const Expr &Node) { + return Lexer::getSourceText( + CharSourceRange::getTokenRange(Node.getSourceRange()), + *Result.SourceManager, getLangOpts()) + .str(); + }; + + bool DstIsRawPtr = std::holds_alternative(Dst.Tag); + bool SrcIsRawPtr = std::holds_alternative(Src.Tag); + + auto CheckIsFalsePositive = [&]() { + // This case could be supported but it requires a robust heuristic + // over the form of the size argument + // to deduce we are dealing with pointers to collections + // When only one of the arguments is a raw pointer, then there are still + // valid scenarios in which it is a singleton to be memmoved over, like + // [de]serialization. + return DstIsRawPtr or SrcIsRawPtr; + }; + if (CheckIsFalsePositive()) + return; + + auto Diag = diag(CallNode.getExprLoc(), "prefer std::copy_n to %0") + << cast(CallNode.getCalleeDecl()); + + // the value type widths are helpful when translating the size argument + // from byte units (memcpy etc.) to element units (std::copy_n), + auto DstTypeWidth = Result.Context->getTypeSizeInChars(*DstVT); + auto SrcTypeWidth = Result.Context->getTypeSizeInChars(*SrcVT); + + auto CalleeIsWideVariant = [&]() { + const auto *Callee = CallNode.getDirectCallee(); + if (Callee == nullptr) + return false; + auto *ParamDecl = Callee->getParamDecl(0); + if (ParamDecl == nullptr) + return false; + return ParamDecl->getType()->getPointeeType()->isWideCharType(); + }(); + + auto CalleeUnit = [&]() { + if (CalleeIsWideVariant) + return Result.Context->getTypeSizeInChars( + (Result.Context->getWideCharType())); + return CharUnits::One(); + }(); + + auto CheckIsFixable = [&]() { + // If the width types differ, it's hard to reason about what would be a + // helpful replacement, so just don't issue a fixit in this case + if (DstTypeWidth != SrcTypeWidth) + return false; + + // don't issue a fixit if the result of the call is used + if (bool IsReturnValueUsed = + Result.Nodes.getNodeAs(ReturnValueDiscardedRef) == nullptr; + IsReturnValueUsed) + return false; + + // for widechar variants assume that the value types are also + // of wchar_t width, to make analysis easier. + if (CalleeIsWideVariant and DstTypeWidth != CalleeUnit) + return false; + + return true; + }; + if (not CheckIsFixable()) + return; + + assert(DstTypeWidth == SrcTypeWidth); + const auto &ValueTypeWidth = DstTypeWidth; + + auto SrcFixit = [&]() { + auto AsString = ExprAsString(Src.Node); + if (SrcIsRawPtr) + return AsString; + return (llvm::Twine() + "std::cbegin(" + AsString + ")").str(); + }(); + + auto DstFixit = [&]() { + auto AsString = ExprAsString(Dst.Node); + if (DstIsRawPtr) + return AsString; + return (llvm::Twine() + "std::begin(" + AsString + ")").str(); + }(); + + // This function is used to specify when a type from a sizeof(_) call is + // considered equivalent to the value type of the collection. + // For now it is relaxed because the matcher desugars + // the container value types automatically. + auto CheckIsEquivValueType = [&DstVT](QualType SizeArgType) { + return SizeArgType->getCanonicalTypeUnqualified() == + (*DstVT)->getCanonicalTypeUnqualified(); + }; + + auto ByteModifySizeArg = [&]() -> std::string { + if (const auto *SizeOfCArray = + std::get_if(&Size); + SizeOfCArray != nullptr) { + // simply replaces sizeof(arr) with std::size(arr) + return (llvm::Twine() + "std::size(" + ExprAsString(SizeOfCArray->Array) + + ")") + .str(); + } + if (const auto *NSizeofExprNode = + std::get_if(&Size); + NSizeofExprNode != nullptr) { + auto &[N, Arg] = *NSizeofExprNode; + // In this case it is easy to factor out the byte multiplier + // by just dropping the sizeof expression from the size computation + if (CheckIsEquivValueType(Arg)) + return ExprAsString(N); + } + if (const auto *SizeOfDivSizeOf = + std::get_if(&Size); + SizeOfDivSizeOf != nullptr) { + auto &[Array, DivSizeOfType] = *SizeOfDivSizeOf; + if (CheckIsEquivValueType(DivSizeOfType) and ValueTypeWidth == CalleeUnit) + return (llvm::Twine() + "std::size(" + ExprAsString(Array) + ")").str(); + } + + // In the specific case where the collections' value types are byte-wide, + // no unit conversion of the size argument is necessary + if (ValueTypeWidth == CalleeUnit) + return ExprAsString(*CallNode.getArg(size::ArgIndex)); + + // For all other cases where the value type is wider than one byte, + // and the size argument is of a form that is not easy to factor the unit + // out of, perform explicit division to ensure it is in element units + return (llvm::Twine() + "(" + + ExprAsString(*CallNode.getArg(size::ArgIndex)) + ") / sizeof(" + + DstVT->getAsString() + ")") + .str(); + }; + + auto WideModifySizeArg = [&]() { + if (const auto *SizeOfDivSizeOf = + std::get_if(&Size); + SizeOfDivSizeOf != nullptr) { + auto &[Array, DivSizeOfType] = *SizeOfDivSizeOf; + if (CheckIsEquivValueType(DivSizeOfType)) + return (llvm::Twine() + "std::size(" + ExprAsString(Array) + ")").str(); + } + // Since we assume wide variants' value type width equals wchar_t, + // the units should already be unified and no modifications to the size + // argument are necessary + return ExprAsString(*CallNode.getArg(size::ArgIndex)); + }; + + auto SizeFixit = + CalleeIsWideVariant ? WideModifySizeArg() : ByteModifySizeArg(); + + Diag << FixItHint::CreateRemoval(CallNode.getSourceRange()) + << FixItHint::CreateInsertion(CallNode.getBeginLoc(), + (llvm::Twine() + "std::copy_n(" + + SrcFixit + ", " + SizeFixit + ", " + + DstFixit + ")") + .str()) + << Inserter.createIncludeInsertion( + Result.SourceManager->getFileID(CallNode.getBeginLoc()), + ""); + + // All containers will contain an std::[c]begin declaration with their + // definition, with the exception of constant c-arrays + if (std::holds_alternative(Dst.Tag) and + std::holds_alternative(Src.Tag)) + Diag << Inserter.createIncludeInsertion( + Result.SourceManager->getFileID(CallNode.getBeginLoc()), ""); +} + +} // namespace modernize +} // namespace clang::tidy \ No newline at end of file diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceWithStdCopyCheck.h b/clang-tools-extra/clang-tidy/modernize/ReplaceWithStdCopyCheck.h new file mode 100644 index 0000000000000..e3e317bf7fb5e --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceWithStdCopyCheck.h @@ -0,0 +1,49 @@ +//===--- ReplaceMemcpyWithStdCopy.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_MODERNIZE_REPLACE_WITH_STDCOPY_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_WITH_STDCOPY_H + +#include "../ClangTidyCheck.h" +#include "../utils/IncludeInserter.h" +#include "clang/AST/ASTTypeTraits.h" +#include "clang/Basic/LangOptions.h" + +namespace clang::tidy::modernize { + +// Replace C-style calls to functions like memmove and memcpy with analogous +// calls to std::copy or std::copy_n, depending on the context +class ReplaceWithStdCopyCheck : public ClangTidyCheck { +public: + ReplaceWithStdCopyCheck(StringRef Name, ClangTidyContext *Context); + ~ReplaceWithStdCopyCheck() override = default; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + void storeOptions(ClangTidyOptions::OptionMap &Options) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus11; + } + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void tryIssueFixIt(const ast_matchers::MatchFinder::MatchResult &Result, + const DiagnosticBuilder &Diag, const CallExpr &CallNode); + + utils::IncludeInserter Inserter; + + const bool FlagMemcpy; +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REPLACE_WITH_STDCOPY_H diff --git a/clang-tools-extra/clangd/TidyFastChecks.inc b/clang-tools-extra/clangd/TidyFastChecks.inc index de1a025602fa9..9076779cacc01 100644 --- a/clang-tools-extra/clangd/TidyFastChecks.inc +++ b/clang-tools-extra/clangd/TidyFastChecks.inc @@ -7,436 +7,444 @@ #define SLOW(CHECK, DELTA) #endif -FAST(abseil-cleanup-ctad, -2.0) -FAST(abseil-duration-addition, 0.0) +FAST(abseil-cleanup-ctad, 3.0) +FAST(abseil-duration-addition, 2.0) FAST(abseil-duration-comparison, -1.0) -FAST(abseil-duration-conversion-cast, -1.0) -FAST(abseil-duration-division, 0.0) -FAST(abseil-duration-factory-float, 2.0) -FAST(abseil-duration-factory-scale, 1.0) -FAST(abseil-duration-subtraction, -1.0) -FAST(abseil-duration-unnecessary-conversion, -0.0) -FAST(abseil-faster-strsplit-delimiter, 3.0) -FAST(abseil-no-internal-dependencies, 1.0) -FAST(abseil-no-namespace, -0.0) +FAST(abseil-duration-conversion-cast, 1.0) +FAST(abseil-duration-division, 4.0) +FAST(abseil-duration-factory-float, -0.0) +FAST(abseil-duration-factory-scale, -2.0) +FAST(abseil-duration-subtraction, -0.0) +FAST(abseil-duration-unnecessary-conversion, 2.0) +FAST(abseil-faster-strsplit-delimiter, -3.0) +FAST(abseil-no-internal-dependencies, -2.0) +FAST(abseil-no-namespace, 2.0) FAST(abseil-redundant-strcat-calls, 1.0) -FAST(abseil-str-cat-append, -0.0) -FAST(abseil-string-find-startswith, -1.0) +FAST(abseil-str-cat-append, 1.0) +FAST(abseil-string-find-startswith, -2.0) FAST(abseil-string-find-str-contains, 4.0) -FAST(abseil-time-comparison, -1.0) -FAST(abseil-time-subtraction, 1.0) -FAST(abseil-upgrade-duration-conversions, 2.0) -SLOW(altera-id-dependent-backward-branch, 13.0) -FAST(altera-kernel-name-restriction, 4.0) -FAST(altera-single-work-item-barrier, 1.0) -FAST(altera-struct-pack-align, -0.0) -FAST(altera-unroll-loops, 2.0) -FAST(android-cloexec-accept, 0.0) -FAST(android-cloexec-accept4, 1.0) -FAST(android-cloexec-creat, 1.0) +FAST(abseil-time-comparison, 1.0) +FAST(abseil-time-subtraction, 2.0) +FAST(abseil-upgrade-duration-conversions, 1.0) +SLOW(altera-id-dependent-backward-branch, 9.0) +FAST(altera-kernel-name-restriction, -0.0) +FAST(altera-single-work-item-barrier, -3.0) +FAST(altera-struct-pack-align, 1.0) +FAST(altera-unroll-loops, 3.0) +FAST(android-cloexec-accept, 1.0) +FAST(android-cloexec-accept4, 3.0) +FAST(android-cloexec-creat, 4.0) FAST(android-cloexec-dup, 0.0) FAST(android-cloexec-epoll-create, 2.0) -FAST(android-cloexec-epoll-create1, 0.0) -FAST(android-cloexec-fopen, -1.0) -FAST(android-cloexec-inotify-init, 2.0) -FAST(android-cloexec-inotify-init1, -0.0) -FAST(android-cloexec-memfd-create, -1.0) -FAST(android-cloexec-open, 1.0) -FAST(android-cloexec-pipe, -0.0) +FAST(android-cloexec-epoll-create1, -1.0) +FAST(android-cloexec-fopen, 1.0) +FAST(android-cloexec-inotify-init, 0.0) +FAST(android-cloexec-inotify-init1, -1.0) +FAST(android-cloexec-memfd-create, -4.0) +FAST(android-cloexec-open, -0.0) +FAST(android-cloexec-pipe, 0.0) FAST(android-cloexec-pipe2, 0.0) -FAST(android-cloexec-socket, 1.0) +FAST(android-cloexec-socket, -1.0) FAST(android-comparison-in-temp-failure-retry, 1.0) -FAST(boost-use-ranges, 2.0) -FAST(boost-use-to-string, 2.0) -FAST(bugprone-argument-comment, 4.0) -FAST(bugprone-assert-side-effect, 1.0) -FAST(bugprone-assignment-in-if-condition, 2.0) -FAST(bugprone-bad-signal-to-kill-thread, 1.0) -FAST(bugprone-bool-pointer-implicit-conversion, 0.0) +FAST(boost-use-ranges, 3.0) +FAST(boost-use-to-string, 0.0) +FAST(bugprone-argument-comment, 2.0) +FAST(bugprone-assert-side-effect, 2.0) +FAST(bugprone-assignment-in-if-condition, -5.0) +FAST(bugprone-bad-signal-to-kill-thread, -0.0) +FAST(bugprone-bitwise-pointer-cast, -2.0) +FAST(bugprone-bool-pointer-implicit-conversion, 4.0) FAST(bugprone-branch-clone, 1.0) -FAST(bugprone-casting-through-void, 1.0) -FAST(bugprone-chained-comparison, 1.0) -FAST(bugprone-compare-pointer-to-member-virtual-function, -0.0) -FAST(bugprone-copy-constructor-init, 1.0) -FAST(bugprone-crtp-constructor-accessibility, 0.0) -FAST(bugprone-dangling-handle, -0.0) -FAST(bugprone-dynamic-static-initializers, 0.0) -FAST(bugprone-easily-swappable-parameters, 2.0) -FAST(bugprone-empty-catch, 1.0) -FAST(bugprone-exception-escape, 0.0) -FAST(bugprone-fold-init-type, 1.0) -FAST(bugprone-forward-declaration-namespace, 0.0) -FAST(bugprone-forwarding-reference-overload, -1.0) -FAST(bugprone-implicit-widening-of-multiplication-result, 2.0) -FAST(bugprone-inaccurate-erase, -0.0) -FAST(bugprone-inc-dec-in-conditions, 3.0) -FAST(bugprone-incorrect-enable-if, -1.0) -FAST(bugprone-incorrect-roundings, 1.0) -FAST(bugprone-infinite-loop, 1.0) -FAST(bugprone-integer-division, -0.0) -FAST(bugprone-lambda-function-name, 0.0) -FAST(bugprone-macro-parentheses, 1.0) -FAST(bugprone-macro-repeated-side-effects, 1.0) -FAST(bugprone-misplaced-operator-in-strlen-in-alloc, 0.0) -FAST(bugprone-misplaced-pointer-arithmetic-in-alloc, -0.0) -FAST(bugprone-misplaced-widening-cast, -1.0) -FAST(bugprone-move-forwarding-reference, -1.0) +FAST(bugprone-casting-through-void, -1.0) +FAST(bugprone-chained-comparison, 2.0) +FAST(bugprone-compare-pointer-to-member-virtual-function, -4.0) +FAST(bugprone-copy-constructor-init, -0.0) +FAST(bugprone-crtp-constructor-accessibility, 1.0) +FAST(bugprone-dangling-handle, 1.0) +FAST(bugprone-dynamic-static-initializers, 1.0) +FAST(bugprone-easily-swappable-parameters, 1.0) +FAST(bugprone-empty-catch, 3.0) +FAST(bugprone-exception-escape, -0.0) +FAST(bugprone-fold-init-type, -1.0) +FAST(bugprone-forward-declaration-namespace, -1.0) +FAST(bugprone-forwarding-reference-overload, -4.0) +FAST(bugprone-implicit-widening-of-multiplication-result, 3.0) +FAST(bugprone-inaccurate-erase, 1.0) +FAST(bugprone-inc-dec-in-conditions, 5.0) +FAST(bugprone-incorrect-enable-if, 2.0) +FAST(bugprone-incorrect-roundings, 2.0) +FAST(bugprone-infinite-loop, 7.0) +FAST(bugprone-integer-division, 3.0) +FAST(bugprone-lambda-function-name, 2.0) +FAST(bugprone-macro-parentheses, 2.0) +FAST(bugprone-macro-repeated-side-effects, 2.0) +FAST(bugprone-misplaced-operator-in-strlen-in-alloc, 1.0) +FAST(bugprone-misplaced-pointer-arithmetic-in-alloc, 2.0) +FAST(bugprone-misplaced-widening-cast, 1.0) +FAST(bugprone-move-forwarding-reference, -0.0) FAST(bugprone-multi-level-implicit-pointer-conversion, -1.0) -FAST(bugprone-multiple-new-in-one-expression, 0.0) -FAST(bugprone-multiple-statement-macro, 2.0) +FAST(bugprone-multiple-new-in-one-expression, -1.0) +FAST(bugprone-multiple-statement-macro, -3.0) FAST(bugprone-narrowing-conversions, 2.0) -FAST(bugprone-no-escape, 1.0) -FAST(bugprone-non-zero-enum-to-bool-conversion, 0.0) -FAST(bugprone-not-null-terminated-result, 0.0) -FAST(bugprone-optional-value-conversion, 1.0) -FAST(bugprone-parent-virtual-call, 1.0) -FAST(bugprone-pointer-arithmetic-on-polymorphic-object, 0.0) -FAST(bugprone-posix-return, -0.0) -FAST(bugprone-redundant-branch-condition, -0.0) -FAST(bugprone-reserved-identifier, -1.0) -FAST(bugprone-return-const-ref-from-parameter, -2.0) -FAST(bugprone-shared-ptr-array-mismatch, 0.0) -FAST(bugprone-signal-handler, -1.0) -FAST(bugprone-signed-char-misuse, -2.0) -FAST(bugprone-sizeof-container, -1.0) -FAST(bugprone-sizeof-expression, 1.0) -FAST(bugprone-spuriously-wake-up-functions, 1.0) -FAST(bugprone-standalone-empty, 7.0) -FAST(bugprone-string-constructor, 3.0) -FAST(bugprone-string-integer-assignment, -0.0) -FAST(bugprone-string-literal-with-embedded-nul, 1.0) -FAST(bugprone-stringview-nullptr, 4.0) +FAST(bugprone-no-escape, 2.0) +FAST(bugprone-non-zero-enum-to-bool-conversion, 1.0) +FAST(bugprone-nondeterministic-pointer-iteration-order, 2.0) +FAST(bugprone-not-null-terminated-result, 1.0) +FAST(bugprone-optional-value-conversion, 2.0) +FAST(bugprone-parent-virtual-call, -2.0) +FAST(bugprone-pointer-arithmetic-on-polymorphic-object, 1.0) +FAST(bugprone-posix-return, 2.0) +FAST(bugprone-redundant-branch-condition, 1.0) +FAST(bugprone-reserved-identifier, 2.0) +FAST(bugprone-return-const-ref-from-parameter, 2.0) +FAST(bugprone-shared-ptr-array-mismatch, 3.0) +FAST(bugprone-signal-handler, 2.0) +FAST(bugprone-signed-char-misuse, -1.0) +FAST(bugprone-sizeof-container, -2.0) +FAST(bugprone-sizeof-expression, 6.0) +FAST(bugprone-spuriously-wake-up-functions, 0.0) +FAST(bugprone-standalone-empty, 5.0) +FAST(bugprone-string-constructor, 0.0) +FAST(bugprone-string-integer-assignment, 1.0) +FAST(bugprone-string-literal-with-embedded-nul, 0.0) +FAST(bugprone-stringview-nullptr, 2.0) FAST(bugprone-suspicious-enum-usage, 2.0) FAST(bugprone-suspicious-include, 0.0) -FAST(bugprone-suspicious-memory-comparison, 0.0) -FAST(bugprone-suspicious-memset-usage, 0.0) -FAST(bugprone-suspicious-missing-comma, -2.0) -FAST(bugprone-suspicious-realloc-usage, -0.0) -FAST(bugprone-suspicious-semicolon, 6.0) -FAST(bugprone-suspicious-string-compare, 1.0) -FAST(bugprone-suspicious-stringview-data-usage, 1.0) -FAST(bugprone-swapped-arguments, 1.0) -FAST(bugprone-switch-missing-default-case, 2.0) -FAST(bugprone-terminating-continue, -1.0) -FAST(bugprone-throw-keyword-missing, 0.0) -FAST(bugprone-too-small-loop-variable, 0.0) +FAST(bugprone-suspicious-memory-comparison, -0.0) +FAST(bugprone-suspicious-memset-usage, 1.0) +FAST(bugprone-suspicious-missing-comma, -3.0) +FAST(bugprone-suspicious-realloc-usage, 2.0) +FAST(bugprone-suspicious-semicolon, 3.0) +FAST(bugprone-suspicious-string-compare, 3.0) +FAST(bugprone-suspicious-stringview-data-usage, -0.0) +FAST(bugprone-swapped-arguments, 2.0) +FAST(bugprone-switch-missing-default-case, 0.0) +FAST(bugprone-tagged-union-member-count, -2.0) +FAST(bugprone-terminating-continue, 3.0) +FAST(bugprone-throw-keyword-missing, -1.0) +FAST(bugprone-too-small-loop-variable, 3.0) FAST(bugprone-unchecked-optional-access, 2.0) FAST(bugprone-undefined-memory-manipulation, 1.0) -FAST(bugprone-undelegated-constructor, 1.0) -FAST(bugprone-unhandled-exception-at-new, -1.0) -FAST(bugprone-unhandled-self-assignment, 0.0) -FAST(bugprone-unique-ptr-array-mismatch, 0.0) -FAST(bugprone-unsafe-functions, 1.0) -FAST(bugprone-unused-local-non-trivial-variable, -1.0) -FAST(bugprone-unused-raii, 1.0) +FAST(bugprone-undelegated-constructor, 4.0) +FAST(bugprone-unhandled-exception-at-new, 2.0) +FAST(bugprone-unhandled-self-assignment, 4.0) +FAST(bugprone-unique-ptr-array-mismatch, 5.0) +FAST(bugprone-unsafe-functions, 0.0) +FAST(bugprone-unused-local-non-trivial-variable, 2.0) +FAST(bugprone-unused-raii, 3.0) FAST(bugprone-unused-return-value, 4.0) -FAST(bugprone-use-after-move, 4.0) -FAST(bugprone-virtual-near-miss, 0.0) -FAST(cert-con36-c, 1.0) -FAST(cert-con54-cpp, 2.0) -FAST(cert-ctr56-cpp, 0.0) -FAST(cert-dcl03-c, 0.0) -FAST(cert-dcl16-c, 1.0) -FAST(cert-dcl37-c, 1.0) -FAST(cert-dcl50-cpp, -1.0) -FAST(cert-dcl51-cpp, -1.0) -FAST(cert-dcl54-cpp, 0.0) -FAST(cert-dcl58-cpp, -0.0) -FAST(cert-dcl59-cpp, 1.0) -FAST(cert-env33-c, 1.0) -FAST(cert-err09-cpp, -0.0) +FAST(bugprone-use-after-move, -0.0) +FAST(bugprone-virtual-near-miss, -1.0) +FAST(cert-arr39-c, 1.0) +FAST(cert-con36-c, 2.0) +FAST(cert-con54-cpp, 3.0) +FAST(cert-ctr56-cpp, 4.0) +FAST(cert-dcl03-c, 4.0) +FAST(cert-dcl16-c, 2.0) +FAST(cert-dcl37-c, 2.0) +FAST(cert-dcl50-cpp, 1.0) +FAST(cert-dcl51-cpp, 0.0) +FAST(cert-dcl54-cpp, 3.0) +FAST(cert-dcl58-cpp, -1.0) +FAST(cert-dcl59-cpp, -4.0) +FAST(cert-env33-c, 2.0) +FAST(cert-err09-cpp, 2.0) FAST(cert-err33-c, 4.0) -FAST(cert-err34-c, -1.0) -FAST(cert-err52-cpp, -1.0) -FAST(cert-err58-cpp, -0.0) -FAST(cert-err60-cpp, -0.0) -FAST(cert-err61-cpp, 2.0) -FAST(cert-exp42-c, 1.0) -FAST(cert-fio38-c, 1.0) -FAST(cert-flp30-c, 3.0) -FAST(cert-flp37-c, 1.0) -FAST(cert-int09-c, -1.0) -FAST(cert-mem57-cpp, 0.0) +FAST(cert-err34-c, 1.0) +FAST(cert-err52-cpp, 0.0) +FAST(cert-err58-cpp, 2.0) +FAST(cert-err60-cpp, 1.0) +FAST(cert-err61-cpp, 4.0) +FAST(cert-exp42-c, 2.0) +FAST(cert-fio38-c, -0.0) +FAST(cert-flp30-c, 2.0) +FAST(cert-flp37-c, 2.0) +FAST(cert-int09-c, 2.0) +FAST(cert-mem57-cpp, 2.0) FAST(cert-msc24-c, 0.0) -FAST(cert-msc30-c, 0.0) -FAST(cert-msc32-c, -0.0) +FAST(cert-msc30-c, 1.0) +FAST(cert-msc32-c, -1.0) FAST(cert-msc33-c, 2.0) -FAST(cert-msc50-cpp, -0.0) -FAST(cert-msc51-cpp, 2.0) -FAST(cert-msc54-cpp, -0.0) -FAST(cert-oop11-cpp, -0.0) -FAST(cert-oop54-cpp, 2.0) -FAST(cert-oop57-cpp, -0.0) -FAST(cert-oop58-cpp, 0.0) -FAST(cert-pos44-c, 2.0) -FAST(cert-pos47-c, 0.0) -FAST(cert-sig30-c, 1.0) -FAST(cert-str34-c, 2.0) -FAST(concurrency-mt-unsafe, 3.0) -FAST(concurrency-thread-canceltype-asynchronous, 1.0) -FAST(cppcoreguidelines-avoid-c-arrays, 0.0) +FAST(cert-msc50-cpp, 3.0) +FAST(cert-msc51-cpp, -0.0) +FAST(cert-msc54-cpp, 0.0) +FAST(cert-oop11-cpp, -3.0) +FAST(cert-oop54-cpp, 1.0) +FAST(cert-oop57-cpp, -1.0) +FAST(cert-oop58-cpp, 8.0) +FAST(cert-pos44-c, 1.0) +FAST(cert-pos47-c, 4.0) +FAST(cert-sig30-c, 3.0) +FAST(cert-str34-c, 1.0) +FAST(concurrency-mt-unsafe, -2.0) +FAST(concurrency-thread-canceltype-asynchronous, -1.0) +FAST(cppcoreguidelines-avoid-c-arrays, 2.0) FAST(cppcoreguidelines-avoid-capturing-lambda-coroutines, -1.0) -FAST(cppcoreguidelines-avoid-const-or-ref-data-members, -2.0) -FAST(cppcoreguidelines-avoid-do-while, -1.0) -FAST(cppcoreguidelines-avoid-goto, -1.0) -FAST(cppcoreguidelines-avoid-magic-numbers, -2.0) -FAST(cppcoreguidelines-avoid-non-const-global-variables, -0.0) -FAST(cppcoreguidelines-avoid-reference-coroutine-parameters, -0.0) -FAST(cppcoreguidelines-c-copy-assignment-signature, 1.0) -FAST(cppcoreguidelines-explicit-virtual-functions, 0.0) -FAST(cppcoreguidelines-init-variables, 1.0) +FAST(cppcoreguidelines-avoid-const-or-ref-data-members, 1.0) +FAST(cppcoreguidelines-avoid-do-while, 6.0) +FAST(cppcoreguidelines-avoid-goto, -0.0) +FAST(cppcoreguidelines-avoid-magic-numbers, 4.0) +FAST(cppcoreguidelines-avoid-non-const-global-variables, -1.0) +FAST(cppcoreguidelines-avoid-reference-coroutine-parameters, 1.0) +FAST(cppcoreguidelines-c-copy-assignment-signature, -1.0) +FAST(cppcoreguidelines-explicit-virtual-functions, -1.0) +FAST(cppcoreguidelines-init-variables, 4.0) FAST(cppcoreguidelines-interfaces-global-init, 1.0) -FAST(cppcoreguidelines-macro-to-enum, 0.0) -FAST(cppcoreguidelines-macro-usage, -0.0) -FAST(cppcoreguidelines-misleading-capture-default-by-value, -1.0) -FAST(cppcoreguidelines-missing-std-forward, 0.0) -FAST(cppcoreguidelines-narrowing-conversions, 2.0) -FAST(cppcoreguidelines-no-malloc, -1.0) -FAST(cppcoreguidelines-no-suspend-with-lock, 1.0) -FAST(cppcoreguidelines-noexcept-destructor, -0.0) -FAST(cppcoreguidelines-noexcept-move-operations, 2.0) -FAST(cppcoreguidelines-noexcept-swap, -2.0) -FAST(cppcoreguidelines-non-private-member-variables-in-classes, 1.0) -FAST(cppcoreguidelines-owning-memory, 3.0) +FAST(cppcoreguidelines-macro-to-enum, 3.0) +FAST(cppcoreguidelines-macro-usage, -2.0) +FAST(cppcoreguidelines-misleading-capture-default-by-value, 1.0) +FAST(cppcoreguidelines-missing-std-forward, 3.0) +FAST(cppcoreguidelines-narrowing-conversions, 3.0) +FAST(cppcoreguidelines-no-malloc, -2.0) +FAST(cppcoreguidelines-no-suspend-with-lock, 2.0) +FAST(cppcoreguidelines-noexcept-destructor, 3.0) +FAST(cppcoreguidelines-noexcept-move-operations, 4.0) +FAST(cppcoreguidelines-noexcept-swap, 0.0) +FAST(cppcoreguidelines-non-private-member-variables-in-classes, 2.0) +FAST(cppcoreguidelines-owning-memory, 2.0) FAST(cppcoreguidelines-prefer-member-initializer, 2.0) FAST(cppcoreguidelines-pro-bounds-array-to-pointer-decay, 2.0) FAST(cppcoreguidelines-pro-bounds-constant-array-index, 1.0) -FAST(cppcoreguidelines-pro-bounds-pointer-arithmetic, 0.0) -FAST(cppcoreguidelines-pro-type-const-cast, -1.0) -FAST(cppcoreguidelines-pro-type-cstyle-cast, 2.0) -FAST(cppcoreguidelines-pro-type-member-init, 1.0) -FAST(cppcoreguidelines-pro-type-reinterpret-cast, -1.0) -FAST(cppcoreguidelines-pro-type-static-cast-downcast, 0.0) -FAST(cppcoreguidelines-pro-type-union-access, 0.0) -FAST(cppcoreguidelines-pro-type-vararg, -1.0) -FAST(cppcoreguidelines-rvalue-reference-param-not-moved, 1.0) -FAST(cppcoreguidelines-slicing, 1.0) -FAST(cppcoreguidelines-special-member-functions, -1.0) -FAST(cppcoreguidelines-use-default-member-init, 0.0) -FAST(cppcoreguidelines-virtual-class-destructor, -0.0) -FAST(darwin-avoid-spinlock, 2.0) -FAST(darwin-dispatch-once-nonstatic, 0.0) -FAST(fuchsia-default-arguments-calls, 1.0) -FAST(fuchsia-default-arguments-declarations, -0.0) -FAST(fuchsia-header-anon-namespaces, -0.0) -FAST(fuchsia-multiple-inheritance, 0.0) -FAST(fuchsia-overloaded-operator, 4.0) -FAST(fuchsia-statically-constructed-objects, -0.0) -FAST(fuchsia-trailing-return, 1.0) -FAST(fuchsia-virtual-inheritance, 1.0) -FAST(google-build-explicit-make-pair, 3.0) +FAST(cppcoreguidelines-pro-bounds-pointer-arithmetic, 1.0) +FAST(cppcoreguidelines-pro-type-const-cast, 1.0) +FAST(cppcoreguidelines-pro-type-cstyle-cast, -3.0) +FAST(cppcoreguidelines-pro-type-member-init, 5.0) +FAST(cppcoreguidelines-pro-type-reinterpret-cast, 1.0) +FAST(cppcoreguidelines-pro-type-static-cast-downcast, 2.0) +FAST(cppcoreguidelines-pro-type-union-access, 2.0) +FAST(cppcoreguidelines-pro-type-vararg, -0.0) +FAST(cppcoreguidelines-rvalue-reference-param-not-moved, 0.0) +FAST(cppcoreguidelines-slicing, -2.0) +FAST(cppcoreguidelines-special-member-functions, 1.0) +FAST(cppcoreguidelines-use-default-member-init, 1.0) +FAST(cppcoreguidelines-virtual-class-destructor, 2.0) +FAST(darwin-avoid-spinlock, 5.0) +FAST(darwin-dispatch-once-nonstatic, 3.0) +FAST(fuchsia-default-arguments-calls, 0.0) +FAST(fuchsia-default-arguments-declarations, 3.0) +FAST(fuchsia-header-anon-namespaces, 6.0) +FAST(fuchsia-multiple-inheritance, 2.0) +FAST(fuchsia-overloaded-operator, 3.0) +FAST(fuchsia-statically-constructed-objects, 1.0) +FAST(fuchsia-trailing-return, -0.0) +FAST(fuchsia-virtual-inheritance, 0.0) +FAST(google-build-explicit-make-pair, 2.0) FAST(google-build-namespaces, -1.0) -FAST(google-build-using-namespace, -0.0) -FAST(google-default-arguments, 0.0) -FAST(google-explicit-constructor, 2.0) -FAST(google-global-names-in-headers, 0.0) -FAST(google-objc-avoid-nsobject-new, 1.0) -FAST(google-objc-avoid-throwing-exception, -0.0) -FAST(google-objc-function-naming, -1.0) -FAST(google-objc-global-variable-declaration, 0.0) +FAST(google-build-using-namespace, 1.0) +FAST(google-default-arguments, -0.0) +FAST(google-explicit-constructor, 0.0) +FAST(google-global-names-in-headers, -0.0) +FAST(google-objc-avoid-nsobject-new, -0.0) +FAST(google-objc-avoid-throwing-exception, -3.0) +FAST(google-objc-function-naming, -2.0) +FAST(google-objc-global-variable-declaration, -1.0) FAST(google-readability-avoid-underscore-in-googletest-name, 1.0) -FAST(google-readability-braces-around-statements, 0.0) -FAST(google-readability-casting, -0.0) -FAST(google-readability-function-size, 3.0) -FAST(google-readability-namespace-comments, -0.0) -FAST(google-readability-todo, 1.0) -FAST(google-runtime-int, 0.0) -FAST(google-runtime-operator, 0.0) -FAST(google-upgrade-googletest-case, 1.0) -FAST(hicpp-avoid-c-arrays, 1.0) -FAST(hicpp-avoid-goto, -0.0) -FAST(hicpp-braces-around-statements, 0.0) -FAST(hicpp-deprecated-headers, 1.0) -FAST(hicpp-exception-baseclass, -1.0) -FAST(hicpp-explicit-conversions, 1.0) -FAST(hicpp-function-size, 1.0) -FAST(hicpp-ignored-remove-result, 3.0) +FAST(google-readability-braces-around-statements, -3.0) +FAST(google-readability-casting, 2.0) +FAST(google-readability-function-size, 4.0) +FAST(google-readability-namespace-comments, 2.0) +FAST(google-readability-todo, 2.0) +FAST(google-runtime-int, 2.0) +FAST(google-runtime-operator, -6.0) +FAST(google-upgrade-googletest-case, -0.0) +FAST(hicpp-avoid-c-arrays, -1.0) +FAST(hicpp-avoid-goto, -1.0) +FAST(hicpp-braces-around-statements, -0.0) +FAST(hicpp-deprecated-headers, -1.0) +FAST(hicpp-exception-baseclass, 1.0) +FAST(hicpp-explicit-conversions, 2.0) +FAST(hicpp-function-size, 2.0) +FAST(hicpp-ignored-remove-result, 2.0) FAST(hicpp-invalid-access-moved, 4.0) FAST(hicpp-member-init, 2.0) -FAST(hicpp-move-const-arg, 3.0) -FAST(hicpp-multiway-paths-covered, 0.0) -FAST(hicpp-named-parameter, 2.0) -FAST(hicpp-new-delete-operators, -0.0) -FAST(hicpp-no-array-decay, 4.0) +FAST(hicpp-move-const-arg, 1.0) +FAST(hicpp-multiway-paths-covered, -0.0) +FAST(hicpp-named-parameter, 1.0) +FAST(hicpp-new-delete-operators, 2.0) +FAST(hicpp-no-array-decay, 2.0) FAST(hicpp-no-assembler, 1.0) FAST(hicpp-no-malloc, 2.0) -FAST(hicpp-noexcept-move, -0.0) -FAST(hicpp-signed-bitwise, -1.0) -FAST(hicpp-special-member-functions, -2.0) -FAST(hicpp-static-assert, 4.0) -FAST(hicpp-undelegated-constructor, 6.0) -FAST(hicpp-uppercase-literal-suffix, 5.0) +FAST(hicpp-noexcept-move, 1.0) +FAST(hicpp-signed-bitwise, 5.0) +FAST(hicpp-special-member-functions, 0.0) +FAST(hicpp-static-assert, 5.0) +FAST(hicpp-undelegated-constructor, -1.0) +FAST(hicpp-uppercase-literal-suffix, 2.0) FAST(hicpp-use-auto, 0.0) -FAST(hicpp-use-emplace, 3.0) +FAST(hicpp-use-emplace, -0.0) FAST(hicpp-use-equals-default, 2.0) -FAST(hicpp-use-equals-delete, 1.0) -FAST(hicpp-use-noexcept, -0.0) -FAST(hicpp-use-nullptr, 1.0) -FAST(hicpp-use-override, -1.0) -FAST(hicpp-vararg, 0.0) -FAST(linuxkernel-must-check-errs, -0.0) -FAST(llvm-else-after-return, -1.0) -FAST(llvm-header-guard, 3.0) -FAST(llvm-include-order, 0.0) -FAST(llvm-namespace-comment, 0.0) -FAST(llvm-prefer-isa-or-dyn-cast-in-conditionals, 3.0) -FAST(llvm-prefer-register-over-unsigned, -0.0) -FAST(llvm-qualified-auto, 4.0) -FAST(llvm-twine-local, -0.0) -FAST(llvmlibc-callee-namespace, -0.0) -FAST(llvmlibc-implementation-in-namespace, 1.0) -FAST(llvmlibc-inline-function-decl, 3.0) +FAST(hicpp-use-equals-delete, 0.0) +FAST(hicpp-use-noexcept, -1.0) +FAST(hicpp-use-nullptr, 2.0) +FAST(hicpp-use-override, 1.0) +FAST(hicpp-vararg, -3.0) +FAST(linuxkernel-must-check-errs, 0.0) +FAST(llvm-else-after-return, 1.0) +FAST(llvm-header-guard, 2.0) +FAST(llvm-include-order, 1.0) +FAST(llvm-namespace-comment, 1.0) +FAST(llvm-prefer-isa-or-dyn-cast-in-conditionals, 1.0) +FAST(llvm-prefer-register-over-unsigned, -4.0) +FAST(llvm-qualified-auto, -1.0) +FAST(llvm-twine-local, -2.0) +FAST(llvmlibc-callee-namespace, 0.0) +FAST(llvmlibc-implementation-in-namespace, -0.0) +FAST(llvmlibc-inline-function-decl, 1.0) FAST(llvmlibc-restrict-system-libc-headers, 0.0) -FAST(misc-confusable-identifiers, -1.0) -SLOW(misc-const-correctness, 67.0) -FAST(misc-coroutine-hostile-raii, 1.0) +FAST(misc-confusable-identifiers, 1.0) +FAST(misc-const-correctness, 5.0) +FAST(misc-coroutine-hostile-raii, -2.0) FAST(misc-definitions-in-headers, -1.0) -SLOW(misc-header-include-cycle, 10.0) -FAST(misc-include-cleaner, 5.0) -FAST(misc-misleading-bidirectional, 1.0) -FAST(misc-misleading-identifier, 3.0) -FAST(misc-misplaced-const, -2.0) -FAST(misc-new-delete-overloads, 1.0) -FAST(misc-no-recursion, 0.0) -FAST(misc-non-copyable-objects, 0.0) -FAST(misc-non-private-member-variables-in-classes, -1.0) -FAST(misc-redundant-expression, 1.0) -FAST(misc-static-assert, 3.0) -FAST(misc-throw-by-value-catch-by-reference, -0.0) +FAST(misc-header-include-cycle, 2.0) +FAST(misc-include-cleaner, 15.0) +FAST(misc-misleading-bidirectional, 0.0) +FAST(misc-misleading-identifier, 1.0) +FAST(misc-misplaced-const, -1.0) +FAST(misc-new-delete-overloads, 2.0) +FAST(misc-no-recursion, 1.0) +FAST(misc-non-copyable-objects, 2.0) +FAST(misc-non-private-member-variables-in-classes, -0.0) +FAST(misc-redundant-expression, 2.0) +FAST(misc-static-assert, 2.0) +FAST(misc-throw-by-value-catch-by-reference, 0.0) FAST(misc-unconventional-assign-operator, 1.0) -FAST(misc-uniqueptr-reset-release, 2.0) -FAST(misc-unused-alias-decls, 2.0) -FAST(misc-unused-parameters, 3.0) -FAST(misc-unused-using-decls, 1.0) -FAST(misc-use-anonymous-namespace, 1.0) -FAST(misc-use-internal-linkage, 1.0) -FAST(modernize-avoid-bind, 1.0) -FAST(modernize-avoid-c-arrays, 2.0) -FAST(modernize-concat-nested-namespaces, -0.0) +FAST(misc-uniqueptr-reset-release, 1.0) +FAST(misc-unused-alias-decls, 3.0) +FAST(misc-unused-parameters, 2.0) +FAST(misc-unused-using-decls, 0.0) +FAST(misc-use-anonymous-namespace, 4.0) +FAST(misc-use-internal-linkage, 3.0) +FAST(modernize-avoid-bind, -2.0) +FAST(modernize-avoid-c-arrays, 3.0) +FAST(modernize-concat-nested-namespaces, 1.0) FAST(modernize-deprecated-headers, 0.0) FAST(modernize-deprecated-ios-base-aliases, 0.0) -FAST(modernize-loop-convert, 2.0) +FAST(modernize-loop-convert, 4.0) FAST(modernize-macro-to-enum, 0.0) -FAST(modernize-make-shared, 2.0) +FAST(modernize-make-shared, -2.0) FAST(modernize-make-unique, 1.0) -FAST(modernize-min-max-use-initializer-list, 1.0) -FAST(modernize-pass-by-value, 0.0) -FAST(modernize-raw-string-literal, 2.0) -FAST(modernize-redundant-void-arg, 1.0) -FAST(modernize-replace-auto-ptr, 0.0) -FAST(modernize-replace-disallow-copy-and-assign-macro, -0.0) -FAST(modernize-replace-random-shuffle, 1.0) -FAST(modernize-return-braced-init-list, 1.0) -FAST(modernize-shrink-to-fit, 1.0) -FAST(modernize-type-traits, 1.0) +FAST(modernize-min-max-use-initializer-list, -1.0) +FAST(modernize-pass-by-value, -1.0) +FAST(modernize-raw-string-literal, 1.0) +FAST(modernize-redundant-void-arg, -2.0) +FAST(modernize-replace-auto-ptr, 1.0) +FAST(modernize-replace-disallow-copy-and-assign-macro, -1.0) +FAST(modernize-replace-random-shuffle, 0.0) +FAST(modernize-replace-with-std-copy, 1.0) +FAST(modernize-return-braced-init-list, -1.0) +FAST(modernize-shrink-to-fit, -2.0) +FAST(modernize-type-traits, 3.0) FAST(modernize-unary-static-assert, 1.0) -FAST(modernize-use-auto, 0.0) -FAST(modernize-use-bool-literals, 1.0) -FAST(modernize-use-constraints, 1.0) -FAST(modernize-use-default-member-init, -0.0) +FAST(modernize-use-auto, -2.0) +FAST(modernize-use-bool-literals, -2.0) +FAST(modernize-use-constraints, -0.0) +FAST(modernize-use-default-member-init, 2.0) FAST(modernize-use-designated-initializers, 1.0) -FAST(modernize-use-emplace, 2.0) +FAST(modernize-use-emplace, 1.0) FAST(modernize-use-equals-default, 1.0) -FAST(modernize-use-equals-delete, 2.0) -FAST(modernize-use-nodiscard, -2.0) -FAST(modernize-use-noexcept, -2.0) -FAST(modernize-use-nullptr, 1.0) -FAST(modernize-use-override, 0.0) -FAST(modernize-use-ranges, 0.0) -FAST(modernize-use-starts-ends-with, 0.0) -FAST(modernize-use-std-format, -1.0) -FAST(modernize-use-std-numbers, 0.0) -FAST(modernize-use-std-print, -0.0) -FAST(modernize-use-trailing-return-type, 3.0) -FAST(modernize-use-transparent-functors, 0.0) -FAST(modernize-use-uncaught-exceptions, 0.0) -FAST(modernize-use-using, 1.0) -FAST(objc-assert-equals, 1.0) -FAST(objc-avoid-nserror-init, -0.0) -FAST(objc-dealloc-in-category, 0.0) -FAST(objc-forbidden-subclassing, 2.0) -FAST(objc-missing-hash, -0.0) -FAST(objc-nsdate-formatter, 0.0) -FAST(objc-nsinvocation-argument-lifetime, 0.0) -FAST(objc-property-declaration, -0.0) -FAST(objc-super-self, -2.0) -FAST(openmp-exception-escape, -1.0) -FAST(openmp-use-default-none, 2.0) -FAST(performance-avoid-endl, 2.0) -FAST(performance-enum-size, -1.0) -FAST(performance-faster-string-find, 1.0) -FAST(performance-for-range-copy, 1.0) -FAST(performance-implicit-conversion-in-loop, 0.0) -FAST(performance-inefficient-algorithm, 1.0) -FAST(performance-inefficient-string-concatenation, 1.0) -FAST(performance-inefficient-vector-operation, -0.0) -FAST(performance-move-const-arg, 2.0) -FAST(performance-move-constructor-init, 2.0) -FAST(performance-no-automatic-move, 2.0) -FAST(performance-no-int-to-ptr, 0.0) -FAST(performance-noexcept-destructor, -2.0) +FAST(modernize-use-equals-delete, -1.0) +FAST(modernize-use-integer-sign-comparison, 1.0) +FAST(modernize-use-nodiscard, -0.0) +FAST(modernize-use-noexcept, 0.0) +FAST(modernize-use-nullptr, 2.0) +FAST(modernize-use-override, -1.0) +FAST(modernize-use-ranges, -2.0) +FAST(modernize-use-starts-ends-with, 2.0) +FAST(modernize-use-std-format, -3.0) +FAST(modernize-use-std-numbers, 1.0) +FAST(modernize-use-std-print, -2.0) +FAST(modernize-use-trailing-return-type, -0.0) +FAST(modernize-use-transparent-functors, 1.0) +FAST(modernize-use-uncaught-exceptions, -3.0) +FAST(modernize-use-using, -1.0) +FAST(objc-assert-equals, 2.0) +FAST(objc-avoid-nserror-init, 1.0) +FAST(objc-dealloc-in-category, -1.0) +FAST(objc-forbidden-subclassing, 1.0) +FAST(objc-missing-hash, 3.0) +FAST(objc-nsdate-formatter, -1.0) +FAST(objc-nsinvocation-argument-lifetime, -0.0) +FAST(objc-property-declaration, 0.0) +FAST(objc-super-self, -1.0) +FAST(openmp-exception-escape, 1.0) +FAST(openmp-use-default-none, -1.0) +FAST(performance-avoid-endl, 3.0) +FAST(performance-enum-size, 1.0) +FAST(performance-faster-string-find, -1.0) +FAST(performance-for-range-copy, 3.0) +FAST(performance-implicit-conversion-in-loop, 1.0) +FAST(performance-inefficient-algorithm, 0.0) +FAST(performance-inefficient-string-concatenation, -2.0) +FAST(performance-inefficient-vector-operation, -1.0) +FAST(performance-move-const-arg, -2.0) +FAST(performance-move-constructor-init, 1.0) +FAST(performance-no-automatic-move, 0.0) +FAST(performance-no-int-to-ptr, -2.0) +FAST(performance-noexcept-destructor, 1.0) FAST(performance-noexcept-move-constructor, 1.0) -FAST(performance-noexcept-swap, -2.0) -FAST(performance-trivially-destructible, 3.0) -FAST(performance-type-promotion-in-math-fn, 2.0) -FAST(performance-unnecessary-copy-initialization, 2.0) -FAST(performance-unnecessary-value-param, 2.0) -FAST(portability-restrict-system-includes, 1.0) +FAST(performance-noexcept-swap, -3.0) +FAST(performance-trivially-destructible, -1.0) +FAST(performance-type-promotion-in-math-fn, 3.0) +FAST(performance-unnecessary-copy-initialization, 5.0) +FAST(performance-unnecessary-value-param, 0.0) +FAST(portability-restrict-system-includes, 0.0) FAST(portability-simd-intrinsics, 1.0) -FAST(portability-std-allocator-const, 3.0) -FAST(readability-avoid-const-params-in-decls, -0.0) -FAST(readability-avoid-nested-conditional-operator, -1.0) -FAST(readability-avoid-return-with-void-value, 0.0) -FAST(readability-avoid-unconditional-preprocessor-if, -1.0) -FAST(readability-braces-around-statements, 1.0) -FAST(readability-const-return-type, -1.0) -FAST(readability-container-contains, 3.0) -FAST(readability-container-data-pointer, -1.0) -SLOW(readability-container-size-empty, 13.0) -FAST(readability-convert-member-functions-to-static, 4.0) -FAST(readability-delete-null-pointer, -1.0) -FAST(readability-duplicate-include, 2.0) -FAST(readability-else-after-return, 0.0) -FAST(readability-enum-initial-value, 0.0) -FAST(readability-function-cognitive-complexity, 0.0) -FAST(readability-function-size, 0.0) +FAST(portability-std-allocator-const, 1.0) +FAST(portability-template-virtual-member-function, 3.0) +FAST(readability-avoid-const-params-in-decls, 2.0) +FAST(readability-avoid-nested-conditional-operator, 1.0) +FAST(readability-avoid-return-with-void-value, -1.0) +FAST(readability-avoid-unconditional-preprocessor-if, 4.0) +FAST(readability-braces-around-statements, -1.0) +FAST(readability-const-return-type, 0.0) +FAST(readability-container-contains, 9.0) +FAST(readability-container-data-pointer, 1.0) +FAST(readability-container-size-empty, 1.0) +FAST(readability-convert-member-functions-to-static, 1.0) +FAST(readability-delete-null-pointer, 0.0) +FAST(readability-duplicate-include, -0.0) +FAST(readability-else-after-return, 2.0) +FAST(readability-enum-initial-value, 4.0) +FAST(readability-function-cognitive-complexity, 3.0) +FAST(readability-function-size, -3.0) FAST(readability-identifier-length, 2.0) -FAST(readability-identifier-naming, 1.0) -FAST(readability-implicit-bool-conversion, 3.0) -FAST(readability-inconsistent-declaration-parameter-name, -0.0) -FAST(readability-isolate-declaration, 0.0) -FAST(readability-magic-numbers, 4.0) +FAST(readability-identifier-naming, 2.0) +FAST(readability-implicit-bool-conversion, 1.0) +FAST(readability-inconsistent-declaration-parameter-name, 2.0) +FAST(readability-isolate-declaration, -1.0) +FAST(readability-magic-numbers, -1.0) FAST(readability-make-member-function-const, 1.0) -FAST(readability-math-missing-parentheses, 1.0) +FAST(readability-math-missing-parentheses, 2.0) FAST(readability-misleading-indentation, 1.0) -FAST(readability-misplaced-array-index, 0.0) -FAST(readability-named-parameter, -0.0) +FAST(readability-misplaced-array-index, -1.0) +FAST(readability-named-parameter, -1.0) FAST(readability-non-const-parameter, 2.0) -FAST(readability-operators-representation, 0.0) -FAST(readability-qualified-auto, 0.0) -FAST(readability-redundant-access-specifiers, 1.0) -FAST(readability-redundant-casting, -0.0) +FAST(readability-operators-representation, -2.0) +FAST(readability-qualified-auto, 1.0) +FAST(readability-redundant-access-specifiers, -1.0) +FAST(readability-redundant-casting, -1.0) FAST(readability-redundant-control-flow, 1.0) -FAST(readability-redundant-declaration, 1.0) +FAST(readability-redundant-declaration, -2.0) FAST(readability-redundant-function-ptr-dereference, 0.0) -FAST(readability-redundant-inline-specifier, 0.0) +FAST(readability-redundant-inline-specifier, -0.0) FAST(readability-redundant-member-init, 1.0) FAST(readability-redundant-preprocessor, -0.0) -FAST(readability-redundant-smartptr-get, 4.0) -FAST(readability-redundant-string-cstr, 1.0) -FAST(readability-redundant-string-init, -0.0) -FAST(readability-reference-to-constructed-temporary, 3.0) -FAST(readability-simplify-boolean-expr, -0.0) -FAST(readability-simplify-subscript-expr, 1.0) -FAST(readability-static-accessed-through-instance, 0.0) -FAST(readability-static-definition-in-anonymous-namespace, 0.0) -FAST(readability-string-compare, -0.0) -FAST(readability-suspicious-call-argument, -1.0) -FAST(readability-uniqueptr-delete-release, 3.0) -FAST(readability-uppercase-literal-suffix, 0.0) -FAST(readability-use-anyofallof, 2.0) -FAST(readability-use-std-min-max, -1.0) -FAST(zircon-temporary-objects, 1.0) +FAST(readability-redundant-smartptr-get, -1.0) +FAST(readability-redundant-string-cstr, -1.0) +FAST(readability-redundant-string-init, 1.0) +FAST(readability-reference-to-constructed-temporary, -0.0) +FAST(readability-simplify-boolean-expr, 2.0) +FAST(readability-simplify-subscript-expr, 0.0) +FAST(readability-static-accessed-through-instance, 1.0) +FAST(readability-static-definition-in-anonymous-namespace, 1.0) +FAST(readability-string-compare, 1.0) +FAST(readability-suspicious-call-argument, 1.0) +FAST(readability-uniqueptr-delete-release, -0.0) +FAST(readability-uppercase-literal-suffix, -3.0) +FAST(readability-use-anyofallof, -1.0) +FAST(readability-use-std-min-max, 2.0) +FAST(zircon-temporary-objects, 0.0) #undef FAST #undef SLOW + diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 6350022ed9a8d..527bbe158a89f 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -176,6 +176,11 @@ New checks Finds cases when an uninstantiated virtual member function in a template class causes cross-compiler incompatibility. +- New :doc:`modernize-replace-with-std-copy + ` check. + + Tries to replace calls to ``memmove`` and ``memcpy`` with an equivalent call to ``std::copy_n``. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 7b9b905ef7671..a97f6f2f50dce 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -288,6 +288,7 @@ Clang-Tidy Checks :doc:`modernize-raw-string-literal `, "Yes" :doc:`modernize-redundant-void-arg `, "Yes" :doc:`modernize-replace-auto-ptr `, "Yes" + :doc:`modernize-replace-with-std-copy `, "Yes" :doc:`modernize-replace-disallow-copy-and-assign-macro `, "Yes" :doc:`modernize-replace-random-shuffle `, "Yes" :doc:`modernize-return-braced-init-list `, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/replace-with-std-copy.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/replace-with-std-copy.rst new file mode 100644 index 0000000000000..4f3060112fa5d --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/replace-with-std-copy.rst @@ -0,0 +1,40 @@ +.. title:: clang-tidy - modernize-replace-with-std-copy + +modernize-replace-with-std-copy +=================================== + +This check will flag all calls to ``memmove`` that can be possibly replaced with ``std::copy_n``. +In some specific cases it will provide a fix automatically. +``memcpy`` may also be flagged as opt-in. It is disabled by default because it performs no safety checks for overlapping ranges +in the way ``memmove`` and ``std::copy_n`` do. +``wmemmove`` and ``wmemcpy`` are also supported. + +Example: + +.. code-block:: c++ + std::vector dst(64); + memcpy(dst.data(), std::data(src), N); + +becomes + +.. code-block:: c++ + std::vector dst(64); + std::copy_n(std::cbegin(src), (N) / sizeof(int), std::begin(dst)); + +Known limitations +---------------- +For now, the check works only on a limited, recognizable subset of calls, where it can infer the arguments are pointers to valid collections +in the sense that ``std::copy_n`` understands. More specifically, source/destination should be one of: +- a call to ``std::data`` or the corresponding member method. +- a fixed-size C-array. + +Moreover, a fix will not be issued in more complicated cases, e.g. when source and destination are collections of types that have different sizes. + +Options +------- + +.. option:: IncludeStyle + A string specifying which include-style is used, `llvm` or `google`. Default is `llvm`. + +.. option:: FlagMemcpy + A boolean specifying whether to flag calls to ``memcpy`` as well. Default is `false`. \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy-nofix.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy-nofix.cpp new file mode 100644 index 0000000000000..6cdba0d0b8f74 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy-nofix.cpp @@ -0,0 +1,85 @@ +// RUN: %check_clang_tidy %s modernize-replace-with-std-copy %t -- \ +// RUN: -config='{CheckOptions: {modernize-replace-with-std-copy.FlagMemcpy: true}}' \ +// RUN: | FileCheck %s -implicit-check-not="{{FIX-IT}}" + +namespace std { +using size_t = decltype(sizeof(int)); + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t n); +void *memmove(void *__restrict dest, const void *__restrict src, size_t n); + +template struct vector { + vector(size_t); + + T *data(); + const T *data() const; + size_t size() const; + using value_type = T; +}; + +template +typename Container::value_type* data(Container& Arg) { + return Arg.data(); +} + +template +T* data(T Arg[]); + +template +const typename Container::value_type* data(const Container& Arg) { + return Arg.data(); +} + +template +const T* data(const T[]); + +} // namespace std + +namespace { +using size_t = std::size_t; + +void *memmove(void *__restrict dest, const void *__restrict src, size_t n) { + return nullptr; +} +} // namespace + +namespace { +void noFixItEx() { + { // different value type widths + int Source[10]; + std::vector Dest(5); + + memmove(Source, std::data(Dest), 1); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + std::memmove(Source, std::data(Dest), 1); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + memmove(std::data(Source), Dest.data(), 1); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + std::memmove(std::data(Source), Dest.data(), 1); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + memmove(std::data(Source), std::data(Dest), 1); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + std::memmove(std::data(Source), std::data(Dest), 1); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + } + + { // return value used + int Source[10]; + std::vector Dest(5); + + void* Vptr = nullptr; + if (memmove(Source, Dest.data(), 1) != nullptr) { + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: prefer std::copy_n to 'memmove' + Vptr = memmove(Source, Dest.data(), 1); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: prefer std::copy_n to 'memmove' + } + Vptr = [&]() { + return memmove(Source, Dest.data(), 1); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: prefer std::copy_n to 'memmove' + }(); + + for (;Vptr != nullptr; Vptr = memmove(Source, Dest.data(), 1)) {} + // CHECK-MESSAGES: [[@LINE-1]]:35: warning: prefer std::copy_n to 'memmove' + } +} +} // namespace \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy-small.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy-small.cpp new file mode 100644 index 0000000000000..469faef619619 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy-small.cpp @@ -0,0 +1,156 @@ +// RUN: %check_clang_tidy %s modernize-replace-with-std-copy %t + +//CHECK-FIXES: #include + +namespace { +using size_t = decltype(sizeof(int)); + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t n) { + return nullptr; +} +void *memmove(void *__restrict dest, const void *__restrict src, size_t n) { + return nullptr; +} +} // namespace + +namespace std { +using int64_t = long long ; +using int32_t = int ; +using int16_t = short ; +using int8_t = char ; + +using char32 = int32_t; +using char16 = int16_t; +using char8 = int8_t; + +template +class allocator {}; +template +class char_traits {}; +template +struct basic_string { + typedef basic_string _Type; + basic_string(); + basic_string(const C* p, const A& a = A()); + + const C* c_str() const; + const C* data() const; + + _Type& append(const C* s); + _Type& append(const C* s, size_t n); + _Type& assign(const C* s); + _Type& assign(const C* s, size_t n); + + int compare(const _Type&) const; + int compare(const C* s) const; + int compare(size_t pos, size_t len, const _Type&) const; + int compare(size_t pos, size_t len, const C* s) const; + + size_t find(const _Type& str, size_t pos = 0) const; + size_t find(const C* s, size_t pos = 0) const; + size_t find(const C* s, size_t pos, size_t n) const; + + _Type& insert(size_t pos, const _Type& str); + _Type& insert(size_t pos, const C* s); + _Type& insert(size_t pos, const C* s, size_t n); + + _Type& operator+=(const _Type& str); + _Type& operator+=(const C* s); + _Type& operator=(const _Type& str); + _Type& operator=(const C* s); +}; + +using string = basic_string, std::allocator>; +using wstring = basic_string,std::allocator>; +using u16string = basic_string, std::allocator>; +using u32string = basic_string, std::allocator>; + + + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t n); +void *memmove(void *__restrict dest, const void *__restrict src, size_t n); + +template struct vector { + vector(size_t); + + T *data(); + const T *data() const; + size_t size() const; + void resize(size_t); + using value_type = T; +}; + +template +T* data(vector&); + +template +T* data(T[]); + +template +const T* data(const vector&); + +template +const T* data(const T[]); + +size_t size(void *); + +size_t strlen(const char *); +} // namespace std + + +namespace { +void notSupportedEx() { + char Source[] = "once upon a daydream..."; + + auto *PrimitiveDest = new std::int8_t; + std::memmove(PrimitiveDest, Source, sizeof PrimitiveDest); + + double D = 0.1; + std::int64_t N; + // don't warn on calls over non-sequences + std::memmove(&N, &D, sizeof D); + + std::vector Dest(4); + + // don't warn on memcpy by default + memcpy(Dest.data(), Source, Dest.size()); + std::memcpy(std::data(Dest), Source, Dest.size()); +} + +void noFixItEx() { + // value type widths are different and so a fix is not straightforward + int Source[5]; + std::vector Dest(20); + + memmove(std::data(Dest), Source, 20); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' +} + +void supportedEx() { + { + char Source[] = "once upon a daydream..."; + char Dest[4]; + + std::memmove(Dest, Source, sizeof Dest); + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Source), std::size(Dest), std::begin(Dest)); + + memmove(std::data(Dest), std::data(Source), sizeof Dest); + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Source), std::size(Dest), std::begin(Dest)); + } + + { + char Source[] = "once upon a daydream..."; + std::vector Dest(4); + + std::memmove(Dest.data(), Source, Dest.size()); + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Source), Dest.size(), std::begin(Dest)); + + std::memmove(std::data(Dest), Source, Dest.size()); + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Source), Dest.size(), std::begin(Dest)); + } +} +} // namespace \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy.cpp new file mode 100644 index 0000000000000..2dc4efcc65971 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/replace-with-std-copy.cpp @@ -0,0 +1,345 @@ +// RUN: %check_clang_tidy %s modernize-replace-with-std-copy %t -- \ +// RUN: -config='{CheckOptions: {modernize-replace-with-std-copy.FlagMemcpy: true}}' + +namespace std { +using size_t = decltype(sizeof(int)); + +using int64_t = long long ; +using int32_t = int ; +using int16_t = short ; +using int8_t = char ; + +template +class allocator {}; +template +class char_traits {}; +template +struct basic_string { + typedef basic_string _Type; + using value_type = C; + basic_string(); + basic_string(const C* p, const A& a = A()); + + const C* data() const; + C* data(); + size_t size() const; +}; + +using string = basic_string, std::allocator>; +using wstring = basic_string,std::allocator>; +using u16string = basic_string, std::allocator>; +using u32string = basic_string, std::allocator>; + +template +class basic_string_view { +public: + basic_string_view(); + + basic_string_view(const CharT *); + + basic_string_view(const CharT *, size_t); + + basic_string_view(const basic_string_view &); + + basic_string_view &operator=(const basic_string_view &); + + const CharT* data() const; + + size_t size() const; +}; + +using string_view = basic_string_view; + + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t n); +void *memmove(void *__restrict dest, const void *__restrict src, size_t n); + +template struct vector { + vector(size_t); + + T *data(); + const T *data() const; + size_t size() const; + void resize(size_t); + using value_type = T; +}; + +template +struct array { + T* begin(); + T* end(); + const T* begin() const; + const T* end() const; + + size_t size() const; + + const T* data() const; + T* data(); + + T _data[N]; +}; + +template +struct span { + template + span(T (&arr)[N]); + + const T* data() const; + T* data(); + + using value_type = T; +}; + +template +typename Container::value_type* data(Container& Arg) { + return Arg.data(); +} + +template +const typename Container::value_type* data(const Container& Arg) { + return Arg.data(); +} + +template +constexpr T* data(T (&arr)[N]) { + return arr; +} + +template< class T, std::size_t N > +constexpr std::size_t size( const T (&array)[N] ) { + return N; +} + +template +size_t size(const Container& c) { + return c.size(); +} + +wchar_t* wmemcpy( wchar_t* dest, const wchar_t* src, size_t count ); +wchar_t* wmemmove( wchar_t* dest, const wchar_t* src, size_t count ); + +template +struct unique_ptr { + unique_ptr(T); + T &operator*() const; +}; +} // namespace std + +namespace { +using size_t = std::size_t; + +void *memcpy(void *__restrict dest, const void *__restrict src, size_t n) { + return nullptr; +} +void *memmove(void *__restrict dest, const void *__restrict src, size_t n) { + return nullptr; +} +wchar_t* wmemcpy( wchar_t* dest, const wchar_t* src, size_t count ) { + return nullptr; +} +wchar_t* wmemmove( wchar_t* dest, const wchar_t* src, size_t count ) { + return nullptr; +} +} // namespace + +namespace { +void notSupportedEx() { + + { // pointee is not a collection + char Source[] = "once upon a daydream..."; + auto *PrimitiveDest = new std::int8_t; + + std::memcpy(PrimitiveDest, Source, sizeof PrimitiveDest); + } + + { // reinterpretation + double D = 0.1; + std::int64_t N; + // don't warn on calls over non-sequences + std::memcpy(&N, &D, sizeof D); + } + + { // [de]serialization + struct ComplexObj { + int A; + float B; + }; + auto *Obj = new ComplexObj(); + + char Src[sizeof(ComplexObj)] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + std::memcpy(Obj, Src, sizeof(ComplexObj)); + char Dst[sizeof(ComplexObj)]; + std::memcpy(Dst, Obj, sizeof(ComplexObj)); + } + + { // incomplete array type (should be treated the same as a raw ptr) + char Src[] = "once upon a daydream..."; + auto CopySrc = [&Src](char Dst[], size_t sz) { + std::memcpy(Dst, Src, sz); + }; + + char Dst[4]; + CopySrc(Dst, 4); + } + + { // pointers + const char *Src = "once upon a daydream..."; + char *Dst = new char[64]; + + std::memcpy(Dst, Src, 24); + } +} + +void supportedEx() { + { // two wchar c-arrays + wchar_t Src[] = L"once upon a daydream..."; + wchar_t Dst[4]; + + std::wmemcpy(Dst, Src, sizeof(Dst) / sizeof(wchar_t)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'wmemcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(Dst), std::begin(Dst)); + + std::wmemcpy(Dst, Src, sizeof(Dst) / sizeof(wchar_t)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'wmemcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(Dst), std::begin(Dst)); + + wmemcpy(Dst, Src, std::size(Src)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'wmemcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(Src), std::begin(Dst)); + + wmemmove(Dst, Src, std::size(Src)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'wmemmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(Src), std::begin(Dst)); + } + + { // std::string + std::vector + std::string Src = "once upon a daydream..."; + std::vector Dst(4); + + std::memcpy(Dst.data(), Src.data(), Dst.size()); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), Dst.size(), std::begin(Dst)); + } + + { // std::string + std::vector + std::string Src = "once upon a daydream..."; + std::vector Dst(4); + + std::memmove(Dst.data(), Src.data(), Src.size()); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), Src.size(), std::begin(Dst)); + } + + { // reference to const c-array + const char Src[] = "once upon a daydream..."; + char Dst[7]; + decltype(Dst)& RefDst = Dst; + + memcpy(RefDst, Src, sizeof(RefDst)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(RefDst), std::begin(RefDst)); + } + + { // std::wstring + std::unique_ptr + std::wstring Src = L"once upon a daydream..."; + std::unique_ptr Dst(new wchar_t[7]); + + std::wmemcpy(*Dst, Src.data(), sizeof(*Dst) / sizeof(wchar_t)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'wmemcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(*Dst), std::begin(*Dst)); + } + + { // std::string_view + std::array + std::string_view Src = "once upon a daydream..."; + std::array Dst; + + std::memmove(Dst.data(), Src.data(), Dst.size() - 1); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), Dst.size() - 1, std::begin(Dst)); + } + + { // using namespace std; + using namespace std; + string_view Src = "once upon a daydream..."; + array Dst; + + memmove(Dst.data(), Src.data(), Src.size() - 2); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), Src.size() - 2, std::begin(Dst)); + } + + { // various size arg cases + std::int32_t Data[] = {1, 2, 3, 4, 1, 2, 3, 4}; + std::span Src{Data}; + std::vector Dst(8); + + memcpy(Dst.data(), Src.data(), Dst.size() * sizeof(std::int32_t)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), Dst.size(), std::begin(Dst)); + + memmove(std::data(Dst), std::data(Src), sizeof(int) * std::size(Dst)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(Dst), std::begin(Dst)); + + // If both arguments of the product match sizeOfExpr then the right one is lifted + std::memcpy(std::data(Dst), std::data(Src), sizeof(int) * sizeof(std::int32_t)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), sizeof(int), std::begin(Dst)); + + std::memcpy(std::data(Dst), std::data(Src), sizeof(decltype(Dst)::value_type) * 3); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), 3, std::begin(Dst)); + } + + { // default sizearg path + std::vector Src(64); + std::u32string Dst = U"once upon a daydream..."; + + // Don't factor out sizeof expressions that are unlikely to be related to the value type, + // this might lose semantic info + memmove(std::data(Dst), std::data(Src), sizeof(float) * 3); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), (sizeof(float) * 3) / sizeof(char32_t), std::begin(Dst)); + + // the sizeof(value_type) is nested too deep in the product expression, + // so currently the check will leave it as is + memmove(Dst.data(), Src.data(), 1 * 2 * sizeof(char32_t) * 4); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memmove' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), (1 * 2 * sizeof(char32_t) * 4) / sizeof(char32_t), std::begin(Dst)); + + std::memcpy(Dst.data(), Src.data(), sizeof(char32_t) + sizeof(int)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), (sizeof(char32_t) + sizeof(int)) / sizeof(char32_t), std::begin(Dst)); + } + + { // SizeOfDivSizeOf - width = char + const char Src[] = "once upon a daydream..."; + std::string DstStr = " "; + + // superfluous, can be simplified + std::memcpy(DstStr.data(), std::data(Src), sizeof(Src) / sizeof(char)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(Src), std::begin(DstStr)); + } + + { // SizeOfDivSizeOf - width = int + const int Src[] = {1, 2, 3, 4, 5, 6, 7, 8}; + std::vector DstVec(8); + + // this is probably a bug, but the check prefers not to change behaviour + std::memcpy(DstVec.data(), std::data(Src), sizeof(Src) / sizeof(int)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'memcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), (sizeof(Src) / sizeof(int)) / sizeof(int), std::begin(DstVec)); + } + + { // SizeOfDivSizeOf - width = wchar_t + const wchar_t Src[] = L"once upon a daydream..."; + std::wstring DstStr = L" "; + + // simplifies + std::wmemcpy(DstStr.data(), std::data(Src), sizeof(Src) / sizeof(wchar_t)); + // CHECK-MESSAGES: [[@LINE-1]]:5: warning: prefer std::copy_n to 'wmemcpy' + // CHECK-FIXES: std::copy_n(std::cbegin(Src), std::size(Src), std::begin(DstStr)); + } +} +} // namespace \ No newline at end of file