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 @@ -83,13 +83,19 @@ // 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. - return cxxMemberCallExpr( - callee(cxxMethodDecl( - returns(hasCanonicalType(matchers::isReferenceToConst()))) - .bind(MethodDeclId)), - on(declRefExpr(to(varDecl().bind(ObjectArgId)))), - thisPointerType(namedDecl( - unless(matchers::matchesAnyListedName(ExcludedContainerTypes))))); + const auto MethodDecl = + cxxMethodDecl(returns(hasCanonicalType(matchers::isReferenceToConst()))) + .bind(MethodDeclId); + const auto ReceiverExpr = declRefExpr(to(varDecl().bind(ObjectArgId))); + const auto ReceiverTypeDecl = + namedDecl(unless(matchers::matchesAnyListedName(ExcludedContainerTypes))); + + return expr(anyOf( + cxxMemberCallExpr(callee(MethodDecl), on(ReceiverExpr), + thisPointerType(ReceiverTypeDecl)), + cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, ReceiverExpr), + hasArgument(0, hasType(recordType(hasDeclaration( + ReceiverTypeDecl))))))); } AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) { 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 @@ -24,6 +24,11 @@ operator int() const; // Implicit conversion to int. }; +struct ExpensiveToCopyContainer { + const ExpensiveToCopyType &operator[](int) const; + const ExpensiveToCopyType &operator[](int); +}; + struct TrivialToCopyType { const TrivialToCopyType &reference() const; }; @@ -138,6 +143,50 @@ VarCopyConstructed.constMethod(); } +void PositiveOperatorCallConstReferenceParam(const ExpensiveToCopyContainer &C) { + const auto AutoAssigned = C[42]; + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' + // CHECK-FIXES: const auto& AutoAssigned = C[42]; + AutoAssigned.constMethod(); + + const auto AutoCopyConstructed(C[42]); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' + // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); + AutoCopyConstructed.constMethod(); + + const ExpensiveToCopyType VarAssigned = C[42]; + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' + // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; + VarAssigned.constMethod(); + + const ExpensiveToCopyType VarCopyConstructed(C[42]); + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' + // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); + VarCopyConstructed.constMethod(); +} + +void PositiveOperatorCallConstValueParam(const ExpensiveToCopyContainer C) { + const auto AutoAssigned = C[42]; + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' + // CHECK-FIXES: const auto& AutoAssigned = C[42]; + AutoAssigned.constMethod(); + + const auto AutoCopyConstructed(C[42]); + // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' + // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); + AutoCopyConstructed.constMethod(); + + const ExpensiveToCopyType VarAssigned = C[42]; + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' + // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; + VarAssigned.constMethod(); + + const ExpensiveToCopyType VarCopyConstructed(C[42]); + // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' + // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); + VarCopyConstructed.constMethod(); +} + void PositiveLocalConstValue() { const ExpensiveToCopyType Obj; const auto UnnecessaryCopy = Obj.reference();