diff --git a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp @@ -68,6 +68,10 @@ "::std::unordered_map", "::std::array", "::std::deque"))); } +AST_MATCHER(Expr, hasSideEffects) { + return Node.HasSideEffects(Finder->getASTContext()); +} + } // namespace InefficientVectorOperationCheck::InefficientVectorOperationCheck( @@ -145,7 +149,10 @@ // FIXME: Support more complex range-expressions. Finder->addMatcher( cxxForRangeStmt( - hasRangeInit(declRefExpr(supportedContainerTypesMatcher())), + hasRangeInit( + anyOf(declRefExpr(supportedContainerTypesMatcher()), + memberExpr(hasObjectExpression(unless(hasSideEffects())), + supportedContainerTypesMatcher()))), HasInterestingLoopBody, InInterestingCompoundStmt) .bind(RangeLoopName), this); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -127,6 +127,10 @@ Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Improved :doc:`performance-inefficient-vector-operation + ` to work when + the vector is a member of a structure. + - Fixed a false positive in :doc:`readability-non-const-parameter ` when the parameter is referenced by an lvalue diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-inefficient-vector-operation.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-inefficient-vector-operation.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance-inefficient-vector-operation.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-inefficient-vector-operation.cpp @@ -44,7 +44,7 @@ void reserve(size_t n); void resize(size_t n); - size_t size(); + size_t size() const; const_reference operator[] (size_type) const; reference operator[] (size_type); @@ -359,3 +359,31 @@ } } } + +struct StructWithFieldContainer { + std::vector Numbers; + std::vector getNumbers() const { + std::vector Result; + // CHECK-FIXES: Result.reserve(Numbers.size()); + for (auto Number : Numbers) { + Result.push_back(Number); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called + } + return Result; + } +}; + +StructWithFieldContainer getStructWithField(); + +void foo(const StructWithFieldContainer &Src) { + std::vector A; + // CHECK-FIXES: A.reserve(Src.Numbers.size()); + for (auto Number : Src.Numbers) { + A.push_back(Number); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'push_back' is called + } + std::vector B; + for (auto Number : getStructWithField().Numbers) { + B.push_back(Number); + } +}