This revision was automatically updated to reflect the committed changes. Closed by commit rGba4411e7c6a5: [clang-tidy] performance-unnecessary-copy-initialization: Fix false negative. (authored by courbet).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D114249/new/ https://reviews.llvm.org/D114249 Files: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -3,11 +3,19 @@ template <typename T> struct Iterator { void operator++(); - const T &operator*() const; + T &operator*() const; bool operator!=(const Iterator &) const; typedef const T &const_reference; }; +template <typename T> +struct ConstIterator { + void operator++(); + const T &operator*() const; + bool operator!=(const ConstIterator &) const; + typedef const T &const_reference; +}; + struct ExpensiveToCopyType { ExpensiveToCopyType(); virtual ~ExpensiveToCopyType(); @@ -15,8 +23,6 @@ using ConstRef = const ExpensiveToCopyType &; ConstRef referenceWithAlias() const; const ExpensiveToCopyType *pointer() const; - Iterator<ExpensiveToCopyType> begin() const; - Iterator<ExpensiveToCopyType> end() const; void nonConstMethod(); bool constMethod() const; template <typename A> @@ -24,6 +30,21 @@ operator int() const; // Implicit conversion to int. }; +template <typename T> +struct Container { + bool empty() const; + const T& operator[](int) const; + const T& operator[](int); + Iterator<T> begin(); + Iterator<T> end(); + ConstIterator<T> begin() const; + ConstIterator<T> end() const; + void nonConstMethod(); + bool constMethod() const; +}; + +using ExpensiveToCopyContainerAlias = Container<ExpensiveToCopyType>; + struct TrivialToCopyType { const TrivialToCopyType &reference() const; }; @@ -138,6 +159,94 @@ VarCopyConstructed.constMethod(); } +void PositiveOperatorCallConstReferenceParam(const Container<ExpensiveToCopyType> &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 Container<ExpensiveToCopyType> 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 PositiveOperatorCallConstValueParamAlias(const ExpensiveToCopyContainerAlias 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 Container<ExpensiveToCopyType>* C) { + const auto AutoAssigned = (*C)[42]; + // TODO-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' + // TODO-FIXES: const auto& AutoAssigned = (*C)[42]; + AutoAssigned.constMethod(); + + const auto AutoCopyConstructed((*C)[42]); + // TODO-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' + // TODO-FIXES: const auto& AutoCopyConstructed((*C)[42]); + AutoCopyConstructed.constMethod(); + + const ExpensiveToCopyType VarAssigned = C->operator[](42); + // TODO-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' + // TODO-FIXES: const ExpensiveToCopyType& VarAssigned = C->operator[](42); + VarAssigned.constMethod(); + + const ExpensiveToCopyType VarCopyConstructed(C->operator[](42)); + // TODO-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' + // TODO-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C->operator[](42)); + VarCopyConstructed.constMethod(); +} + void PositiveLocalConstValue() { const ExpensiveToCopyType Obj; const auto UnnecessaryCopy = Obj.reference(); @@ -443,21 +552,9 @@ } class Element {}; -class Container { -public: - class Iterator { - public: - void operator++(); - Element operator*(); - bool operator!=(const Iterator &); - WeirdCopyCtorType c; - }; - const Iterator &begin() const; - const Iterator &end() const; -}; void implicitVarFalsePositive() { - for (const Element &E : Container()) { + for (const Element &E : Container<Element>()) { } } @@ -621,8 +718,30 @@ // CHECK-FIXES: // Comments on a new line should not be deleted. } -void negativeloopedOverObjectIsModified() { - ExpensiveToCopyType Orig; +void positiveLoopedOverObjectIsConst() { + const Container<ExpensiveToCopyType> Orig; + for (const auto &Element : Orig) { + const auto Copy = Element; + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: local copy 'Copy' + // CHECK-FIXES: const auto& Copy = Element; + Orig.constMethod(); + Copy.constMethod(); + } + + auto Lambda = []() { + const Container<ExpensiveToCopyType> Orig; + for (const auto &Element : Orig) { + const auto Copy = Element; + // CHECK-MESSAGES: [[@LINE-1]]:18: warning: local copy 'Copy' + // CHECK-FIXES: const auto& Copy = Element; + Orig.constMethod(); + Copy.constMethod(); + } + }; +} + +void negativeLoopedOverObjectIsModified() { + Container<ExpensiveToCopyType> Orig; for (const auto &Element : Orig) { const auto Copy = Element; Orig.nonConstMethod(); @@ -630,7 +749,7 @@ } auto Lambda = []() { - ExpensiveToCopyType Orig; + Container<ExpensiveToCopyType> Orig; for (const auto &Element : Orig) { const auto Copy = Element; Orig.nonConstMethod(); Index: clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp +++ clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization-excluded-container-types.cpp @@ -21,6 +21,7 @@ struct ConstInCorrectType { const ExpensiveToCopy &secretlyMutates() const; + const ExpensiveToCopy &operator[](int) const; }; using NSVTE = ns::ViewType<ExpensiveToCopy>; @@ -59,12 +60,28 @@ E.constMethod(); } +void excludedConstIncorrectTypeOperator() { + ConstInCorrectType C; + const auto E = C[42]; + E.constMethod(); +} + void excludedConstIncorrectTypeAsPointer(ConstInCorrectType *C) { const auto E = C->secretlyMutates(); E.constMethod(); } +void excludedConstIncorrectTypeAsPointerOperator(ConstInCorrectType *C) { + const auto E = (*C)[42]; + E.constMethod(); +} + void excludedConstIncorrectTypeAsReference(const ConstInCorrectType &C) { const auto E = C.secretlyMutates(); E.constMethod(); } + +void excludedConstIncorrectTypeAsReferenceOperator(const ConstInCorrectType &C) { + const auto E = C[42]; + E.constMethod(); +} Index: clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp =================================================================== --- clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ 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 ReceiverType = + hasCanonicalType(recordType(hasDeclaration(namedDecl( + unless(matchers::matchesAnyListedName(ExcludedContainerTypes)))))); + + return expr(anyOf( + cxxMemberCallExpr(callee(MethodDecl), on(ReceiverExpr), + thisPointerType(ReceiverType)), + cxxOperatorCallExpr(callee(MethodDecl), hasArgument(0, ReceiverExpr), + hasArgument(0, hasType(ReceiverType))))); } AST_MATCHER_FUNCTION(StatementMatcher, isConstRefReturningFunctionCall) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits