diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -19,6 +19,10 @@ namespace performance { namespace { +using namespace ::clang::ast_matchers; +using ::clang::ast_matchers::internal::Matcher; +using utils::decl_ref_expr::isOnlyUsedAsConst; + void recordFixes(const VarDecl &Var, ASTContext &Context, DiagnosticBuilder &Diagnostic) { Diagnostic << utils::fixit::changeVarDeclToReference(Var, Context); @@ -29,10 +33,17 @@ } } -} // namespace +// Always allow std::function to be copied. Since its call operator is const but +// can modify the state of the underlying functor we cannot ell whether the copy +// is unnecessary. +AST_MATCHER(NamedDecl, isStdFunction) { + // First use the fast getName() method to avoid unnecessary calls to the + // slow getQualifiedNameAsString(). + return Node.getName() == "function" && + Node.getQualifiedNameAsString() == "std::function"; +} -using namespace ::clang::ast_matchers; -using utils::decl_ref_expr::isOnlyUsedAsConst; +} // namespace UnnecessaryCopyInitialization::UnnecessaryCopyInitialization( StringRef Name, ClangTidyContext *Context) @@ -57,7 +68,7 @@ unless(callee(cxxMethodDecl()))) .bind("initFunctionCall"); - auto localVarCopiedFrom = [this](const internal::Matcher &CopyCtorArg) { + auto localVarCopiedFrom = [this](const Matcher &CopyCtorArg) { return compoundStmt( forEachDescendant( declStmt( @@ -66,8 +77,9 @@ hasCanonicalType( matchers::isExpensiveToCopy()), unless(hasDeclaration(namedDecl( - matchers::matchesAnyListedName( - AllowedTypes)))))), + anyOf(matchers::matchesAnyListedName( + AllowedTypes), + isStdFunction())))))), unless(isImplicit()), hasInitializer(traverse( ast_type_traits::TK_AsIs, diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -405,3 +405,23 @@ ExpensiveToCopyType Orig; const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(&Orig); } + +namespace std { + +template +class function; +template +class function { +public: + function(); + function(const function &other); + R operator()(Args... args) const; +}; + +} // namespace std + +void negativeStdFunction() { + std::function Orig; + std::function Copy = Orig; + int i = Orig(); +}