diff --git a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp @@ -37,12 +37,18 @@ // Match loop variables that are not references or pointers or are already // initialized through MaterializeTemporaryExpr which indicates a type // conversion. - auto LoopVar = varDecl( - hasType(qualType( - unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())), - hasDeclaration(namedDecl( - matchers::matchesAnyListedName(AllowedTypes))))))), - unless(hasInitializer(expr(hasDescendant(materializeTemporaryExpr()))))); + auto HasReferenceOrPointerTypeOrIsAllowed = hasType(qualType( + unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())), + hasDeclaration(namedDecl( + matchers::matchesAnyListedName(AllowedTypes))))))); + auto IteratorReturnsValueType = cxxOperatorCallExpr( + hasOverloadedOperatorName("*"), + callee( + cxxMethodDecl(returns(unless(hasCanonicalType(referenceType())))))); + auto LoopVar = + varDecl(HasReferenceOrPointerTypeOrIsAllowed, + unless(hasInitializer(expr(hasDescendant(expr(anyOf( + materializeTemporaryExpr(), IteratorReturnsValueType))))))); Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar"))) .bind("forRange"), this); diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp @@ -28,6 +28,7 @@ }; template struct View { + View() = default; T begin() { return T(); } T begin() const { return T(); } T end() { return T(); } @@ -270,3 +271,28 @@ for (auto _ : View>()) { } } + +template +struct ValueReturningIterator { + void operator++() {} + T operator*() { return T(); } + bool operator!=(const ValueReturningIterator &) { return false; } + typedef const T &const_reference; +}; + +void negativeValueIterator() { + // Check does not trigger for iterators that return elements by value. + for (const S SS : View>()) { + } +} + +View> createView(S) { return View>(); } + +void positiveValueIteratorUsedElseWhere() { + for (const S SS : createView(*ValueReturningIterator())) { + // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not + // a reference type; this creates a copy in each iteration; consider making + // this a reference [performance-for-range-copy] CHECK-FIXES: for (const S& + // SS : createView(*ValueReturningIterator())) { + } +}