Index: clang-tidy/performance/UnnecessaryCopyInitialization.h =================================================================== --- clang-tidy/performance/UnnecessaryCopyInitialization.h +++ clang-tidy/performance/UnnecessaryCopyInitialization.h @@ -33,6 +33,7 @@ private: void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt, + const VarDecl *ObjectArg, ASTContext &Context); void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt, ASTContext &Context); Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp =================================================================== --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -42,14 +42,14 @@ unless(allOf(pointerType(), unless(pointerType(pointee( qualType(isConstQualified()))))))); - // Match method call expressions where the this argument is a const - // type or const reference. This returned const reference is highly likely to - // outlive the local const reference of the variable being declared. - // The assumption is that the const reference being returned either points - // to a global static variable or to a member of the called object. - auto ConstRefReturningMethodCallOfConstParam = cxxMemberCallExpr( + // Match method call expressions where the 'this' argument is only used as + // const, this will be checked in check() part. This returned const reference + // is highly likely to outlive the local const reference of the variable being + // declared. The assumption is that the const reference being returned either + // points to a global static variable or to a member of the called object. + auto ConstRefReturningMethodCall = cxxMemberCallExpr( callee(cxxMethodDecl(returns(ConstReference))), - on(declRefExpr(to(varDecl(hasType(qualType(ConstOrConstReference))))))); + on(declRefExpr(to(varDecl().bind("objectArg"))))); auto ConstRefReturningFunctionCall = callExpr(callee(functionDecl(returns(ConstReference))), unless(callee(cxxMethodDecl()))); @@ -70,7 +70,7 @@ Finder->addMatcher( localVarCopiedFrom(anyOf(ConstRefReturningFunctionCall, - ConstRefReturningMethodCallOfConstParam)), + ConstRefReturningMethodCall)), this); Finder->addMatcher(localVarCopiedFrom(declRefExpr( @@ -82,6 +82,7 @@ const MatchFinder::MatchResult &Result) { const auto *NewVar = Result.Nodes.getNodeAs("newVarDecl"); const auto *OldVar = Result.Nodes.getNodeAs("oldVarDecl"); + const auto *ObjectArg = Result.Nodes.getNodeAs("objectArg"); const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt"); const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall"); @@ -93,17 +94,21 @@ return; if (OldVar == nullptr) { - handleCopyFromMethodReturn(*NewVar, *BlockStmt, *Result.Context); + handleCopyFromMethodReturn(*NewVar, *BlockStmt, ObjectArg, *Result.Context); } else { handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, *Result.Context); } } void UnnecessaryCopyInitialization::handleCopyFromMethodReturn( - const VarDecl &Var, const Stmt &BlockStmt, ASTContext &Context) { + const VarDecl &Var, const Stmt &BlockStmt, const VarDecl *ObjectArg, + ASTContext &Context) { bool IsConstQualified = Var.getType().isConstQualified(); if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context)) return; + if (ObjectArg != nullptr && + !isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context)) + return; auto Diagnostic = diag(Var.getLocation(), Index: test/clang-tidy/performance-unnecessary-copy-initialization.cpp =================================================================== --- test/clang-tidy/performance-unnecessary-copy-initialization.cpp +++ test/clang-tidy/performance-unnecessary-copy-initialization.cpp @@ -174,33 +174,57 @@ } } -void NegativeMethodCallNonConstRef(ExpensiveToCopyType &Obj) { +void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) { const auto AutoAssigned = Obj.reference(); - const auto AutoCopyConstructed(Obj.reference()); - const ExpensiveToCopyType VarAssigned = Obj.reference(); - const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); } -void NegativeMethodCallNonConst(ExpensiveToCopyType Obj) { +void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) { const auto AutoAssigned = Obj.reference(); const auto AutoCopyConstructed(Obj.reference()); const ExpensiveToCopyType VarAssigned = Obj.reference(); const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); + mutate(&Obj); +} + +void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) { + const auto AutoAssigned = Obj.reference(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); +} + +void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) { + Obj.nonConstMethod(); + const auto AutoAssigned = Obj.reference(); } -void NegativeMethodCallNonConstPointer(ExpensiveToCopyType *const Obj) { +void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) { + const auto AutoAssigned = Obj->reference(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); + Obj->constMethod(); +} + +void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) { const auto AutoAssigned = Obj->reference(); const auto AutoCopyConstructed(Obj->reference()); const ExpensiveToCopyType VarAssigned = Obj->reference(); const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); + mutate(Obj); +} + +void PositiveLocalVarIsNotModified() { + ExpensiveToCopyType LocalVar; + const auto AutoAssigned = LocalVar.reference(); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const + // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference(); } -void NegativeObjIsNotParam() { +void NegativeLocalVarIsModified() { ExpensiveToCopyType Obj; const auto AutoAssigned = Obj.reference(); - const auto AutoCopyConstructed(Obj.reference()); - ExpensiveToCopyType VarAssigned = Obj.reference(); - ExpensiveToCopyType VarCopyConstructed(Obj.reference()); + Obj = AutoAssigned; } struct NegativeConstructor {