189a1d03eSRichard // RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing
289a1d03eSRichard
389a1d03eSRichard namespace std {
489a1d03eSRichard
589a1d03eSRichard template <typename _Tp>
689a1d03eSRichard struct remove_reference { typedef _Tp type; };
789a1d03eSRichard template <typename _Tp>
889a1d03eSRichard struct remove_reference<_Tp&> { typedef _Tp type; };
989a1d03eSRichard template <typename _Tp>
1089a1d03eSRichard struct remove_reference<_Tp&&> { typedef _Tp type; };
1189a1d03eSRichard
1289a1d03eSRichard template <typename _Tp>
move(_Tp && __t)1389a1d03eSRichard constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
1489a1d03eSRichard return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
1589a1d03eSRichard }
1689a1d03eSRichard
1789a1d03eSRichard } // std
1889a1d03eSRichard
1989a1d03eSRichard template <typename T>
2089a1d03eSRichard struct Iterator {
operator ++Iterator2189a1d03eSRichard void operator++() {}
operator *Iterator2289a1d03eSRichard const T& operator*() {
2389a1d03eSRichard static T* TT = new T();
2489a1d03eSRichard return *TT;
2589a1d03eSRichard }
operator !=Iterator2689a1d03eSRichard bool operator!=(const Iterator &) { return false; }
2789a1d03eSRichard typedef const T& const_reference;
2889a1d03eSRichard };
2989a1d03eSRichard template <typename T>
3089a1d03eSRichard struct View {
3189a1d03eSRichard View() = default;
beginView3289a1d03eSRichard T begin() { return T(); }
beginView3389a1d03eSRichard T begin() const { return T(); }
endView3489a1d03eSRichard T end() { return T(); }
endView3589a1d03eSRichard T end() const { return T(); }
3689a1d03eSRichard typedef typename T::const_reference const_reference;
3789a1d03eSRichard };
3889a1d03eSRichard
3989a1d03eSRichard struct ConstructorConvertible {
4089a1d03eSRichard };
4189a1d03eSRichard
4289a1d03eSRichard struct S {
4389a1d03eSRichard S();
4489a1d03eSRichard S(const S &);
SS4589a1d03eSRichard S(const ConstructorConvertible&) {}
4689a1d03eSRichard ~S();
4789a1d03eSRichard S &operator=(const S &);
4889a1d03eSRichard };
4989a1d03eSRichard
50*8fd32b96SClement Courbet struct Point {
~PointPoint51*8fd32b96SClement Courbet ~Point() {}
52*8fd32b96SClement Courbet int x, y;
53*8fd32b96SClement Courbet };
54*8fd32b96SClement Courbet
5589a1d03eSRichard struct Convertible {
operator SConvertible5689a1d03eSRichard operator S() const {
5789a1d03eSRichard return S();
5889a1d03eSRichard }
5989a1d03eSRichard };
6089a1d03eSRichard
negativeConstReference()6189a1d03eSRichard void negativeConstReference() {
6289a1d03eSRichard for (const S &S1 : View<Iterator<S>>()) {
6389a1d03eSRichard }
6489a1d03eSRichard }
6589a1d03eSRichard
negativeUserDefinedConversion()6689a1d03eSRichard void negativeUserDefinedConversion() {
6789a1d03eSRichard Convertible C[0];
6889a1d03eSRichard for (const S S1 : C) {
6989a1d03eSRichard }
7089a1d03eSRichard }
7189a1d03eSRichard
negativeImplicitConstructorConversion()7289a1d03eSRichard void negativeImplicitConstructorConversion() {
7389a1d03eSRichard ConstructorConvertible C[0];
7489a1d03eSRichard for (const S S1 : C) {
7589a1d03eSRichard }
7689a1d03eSRichard }
7789a1d03eSRichard
7889a1d03eSRichard template <typename T>
uninstantiated()7989a1d03eSRichard void uninstantiated() {
8089a1d03eSRichard for (const S S1 : View<Iterator<S>>()) {}
8189a1d03eSRichard // 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]
8289a1d03eSRichard // CHECK-FIXES: {{^}} for (const S& S1 : View<Iterator<S>>()) {}
8389a1d03eSRichard
8489a1d03eSRichard // Don't warn on dependent types.
8589a1d03eSRichard for (const T t1 : View<Iterator<T>>()) {
8689a1d03eSRichard }
8789a1d03eSRichard }
8889a1d03eSRichard
8989a1d03eSRichard template <typename T>
instantiated()9089a1d03eSRichard void instantiated() {
9189a1d03eSRichard for (const S S2 : View<Iterator<S>>()) {}
9289a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
9389a1d03eSRichard // CHECK-FIXES: {{^}} for (const S& S2 : View<Iterator<S>>()) {}
9489a1d03eSRichard
95*8fd32b96SClement Courbet for (const auto [X, Y] : View<Iterator<Point>>()) {}
96*8fd32b96SClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:19: warning: the loop variable's type is
97*8fd32b96SClement Courbet // CHECK-FIXES: {{^}} for (const auto& [X, Y] : View<Iterator<Point>>()) {}
98*8fd32b96SClement Courbet
9989a1d03eSRichard for (const T T2 : View<Iterator<T>>()) {}
10089a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
10189a1d03eSRichard // CHECK-FIXES: {{^}} for (const T& T2 : View<Iterator<T>>()) {}
10289a1d03eSRichard }
10389a1d03eSRichard
10489a1d03eSRichard template <typename T>
instantiatedNegativeTypedefConstReference()10589a1d03eSRichard void instantiatedNegativeTypedefConstReference() {
10689a1d03eSRichard for (typename T::const_reference T2 : T()) {
10789a1d03eSRichard S S1 = T2;
10889a1d03eSRichard }
10989a1d03eSRichard }
11089a1d03eSRichard
f()11189a1d03eSRichard void f() {
11289a1d03eSRichard instantiated<int>();
11389a1d03eSRichard instantiated<S>();
11489a1d03eSRichard instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();
11589a1d03eSRichard }
11689a1d03eSRichard
11789a1d03eSRichard struct Mutable {
MutableMutable11889a1d03eSRichard Mutable() {}
11989a1d03eSRichard Mutable(const Mutable &) = default;
12089a1d03eSRichard Mutable(Mutable&&) = default;
MutableMutable12189a1d03eSRichard Mutable(const Mutable &, const Mutable &) {}
setBoolMutable12289a1d03eSRichard void setBool(bool B) {}
constMethodMutable12389a1d03eSRichard bool constMethod() const {
12489a1d03eSRichard return true;
12589a1d03eSRichard }
operator []Mutable12689a1d03eSRichard Mutable& operator[](int I) {
12789a1d03eSRichard return *this;
12889a1d03eSRichard }
operator ==Mutable12989a1d03eSRichard bool operator==(const Mutable &Other) const {
13089a1d03eSRichard return true;
13189a1d03eSRichard }
~MutableMutable13289a1d03eSRichard ~Mutable() {}
13389a1d03eSRichard };
13489a1d03eSRichard
operator <<(Mutable & Out,bool B)13589a1d03eSRichard Mutable& operator<<(Mutable &Out, bool B) {
13689a1d03eSRichard Out.setBool(B);
13789a1d03eSRichard return Out;
13889a1d03eSRichard }
13989a1d03eSRichard
operator !=(const Mutable & M1,const Mutable & M2)14089a1d03eSRichard bool operator!=(const Mutable& M1, const Mutable& M2) {
14189a1d03eSRichard return false;
14289a1d03eSRichard }
14389a1d03eSRichard
14489a1d03eSRichard void use(const Mutable &M);
14589a1d03eSRichard void use(int I);
14689a1d03eSRichard void useTwice(const Mutable &M1, const Mutable &M2);
14789a1d03eSRichard void useByValue(Mutable M);
14889a1d03eSRichard void useByConstValue(const Mutable M);
14989a1d03eSRichard void mutate(Mutable *M);
15089a1d03eSRichard void mutate(Mutable &M);
151*8fd32b96SClement Courbet void mutate(int &);
15289a1d03eSRichard void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
15389a1d03eSRichard
negativeVariableIsMutated()15489a1d03eSRichard void negativeVariableIsMutated() {
15589a1d03eSRichard for (auto M : View<Iterator<Mutable>>()) {
15689a1d03eSRichard mutate(M);
15789a1d03eSRichard }
15889a1d03eSRichard for (auto M : View<Iterator<Mutable>>()) {
15989a1d03eSRichard mutate(&M);
16089a1d03eSRichard }
16189a1d03eSRichard for (auto M : View<Iterator<Mutable>>()) {
16289a1d03eSRichard M.setBool(true);
16389a1d03eSRichard }
16489a1d03eSRichard }
16589a1d03eSRichard
negativeOnceConstOnceMutated()16689a1d03eSRichard void negativeOnceConstOnceMutated() {
16789a1d03eSRichard for (auto M : View<Iterator<Mutable>>()) {
16889a1d03eSRichard onceConstOnceMutated(M, M);
16989a1d03eSRichard }
17089a1d03eSRichard }
17189a1d03eSRichard
negativeVarIsMoved()17289a1d03eSRichard void negativeVarIsMoved() {
17389a1d03eSRichard for (auto M : View<Iterator<Mutable>>()) {
17489a1d03eSRichard auto Moved = std::move(M);
17589a1d03eSRichard }
17689a1d03eSRichard }
17789a1d03eSRichard
negativeNonConstOperatorIsInvoked()17889a1d03eSRichard void negativeNonConstOperatorIsInvoked() {
17989a1d03eSRichard for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
18089a1d03eSRichard auto& N = NonConstOperatorInvokee[0];
18189a1d03eSRichard }
18289a1d03eSRichard }
18389a1d03eSRichard
negativeNonConstNonMemberOperatorInvoked()18489a1d03eSRichard void negativeNonConstNonMemberOperatorInvoked() {
18589a1d03eSRichard for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
18689a1d03eSRichard NonConstOperatorInvokee << true;
18789a1d03eSRichard }
18889a1d03eSRichard }
18989a1d03eSRichard
negativeConstCheapToCopy()19089a1d03eSRichard void negativeConstCheapToCopy() {
19189a1d03eSRichard for (const int I : View<Iterator<int>>()) {
19289a1d03eSRichard }
19389a1d03eSRichard }
19489a1d03eSRichard
negativeConstCheapToCopyTypedef()19589a1d03eSRichard void negativeConstCheapToCopyTypedef() {
19689a1d03eSRichard typedef const int ConstInt;
19789a1d03eSRichard for (ConstInt C : View<Iterator<ConstInt>>()) {
19889a1d03eSRichard }
19989a1d03eSRichard }
20089a1d03eSRichard
negativeCheapToCopy()20189a1d03eSRichard void negativeCheapToCopy() {
20289a1d03eSRichard for (int I : View<Iterator<int>>()) {
20389a1d03eSRichard use(I);
20489a1d03eSRichard }
20589a1d03eSRichard }
20689a1d03eSRichard
negativeCheapToCopyTypedef()20789a1d03eSRichard void negativeCheapToCopyTypedef() {
20889a1d03eSRichard typedef int Int;
20989a1d03eSRichard for (Int I : View<Iterator<Int>>()) {
21089a1d03eSRichard use(I);
21189a1d03eSRichard }
21289a1d03eSRichard }
21389a1d03eSRichard
positiveOnlyConstMethodInvoked()21489a1d03eSRichard void positiveOnlyConstMethodInvoked() {
21589a1d03eSRichard for (auto M : View<Iterator<Mutable>>()) {
21689a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
21789a1d03eSRichard // CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {
21889a1d03eSRichard M.constMethod();
21989a1d03eSRichard }
22089a1d03eSRichard }
22189a1d03eSRichard
positiveOnlyUsedAsConstArguments()22289a1d03eSRichard void positiveOnlyUsedAsConstArguments() {
22389a1d03eSRichard for (auto UsedAsConst : View<Iterator<Mutable>>()) {
22489a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
22589a1d03eSRichard // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {
22689a1d03eSRichard use(UsedAsConst);
22789a1d03eSRichard useTwice(UsedAsConst, UsedAsConst);
22889a1d03eSRichard useByValue(UsedAsConst);
22989a1d03eSRichard useByConstValue(UsedAsConst);
23089a1d03eSRichard }
23189a1d03eSRichard }
23289a1d03eSRichard
positiveOnlyAccessedFieldAsConst()23389a1d03eSRichard void positiveOnlyAccessedFieldAsConst() {
23489a1d03eSRichard for (auto UsedAsConst : View<Iterator<Point>>()) {
23589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
23689a1d03eSRichard // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {
23789a1d03eSRichard use(UsedAsConst.x);
23889a1d03eSRichard use(UsedAsConst.y);
23989a1d03eSRichard }
24089a1d03eSRichard }
24189a1d03eSRichard
positiveOnlyUsedAsConstBinding()242*8fd32b96SClement Courbet void positiveOnlyUsedAsConstBinding() {
243*8fd32b96SClement Courbet for (auto [X, Y] : View<Iterator<Point>>()) {
244*8fd32b96SClement Courbet // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but
245*8fd32b96SClement Courbet // CHECK-FIXES: for (const auto& [X, Y] : View<Iterator<Point>>()) {
246*8fd32b96SClement Courbet use(X);
247*8fd32b96SClement Courbet use(Y);
248*8fd32b96SClement Courbet }
249*8fd32b96SClement Courbet }
250*8fd32b96SClement Courbet
negativeMutatedBinding()251*8fd32b96SClement Courbet void negativeMutatedBinding() {
252*8fd32b96SClement Courbet for (auto [X, Y] : View<Iterator<Point>>()) {
253*8fd32b96SClement Courbet use(X);
254*8fd32b96SClement Courbet mutate(Y);
255*8fd32b96SClement Courbet }
256*8fd32b96SClement Courbet }
257*8fd32b96SClement Courbet
positiveOnlyUsedInCopyConstructor()25889a1d03eSRichard void positiveOnlyUsedInCopyConstructor() {
25989a1d03eSRichard for (auto A : View<Iterator<Mutable>>()) {
26089a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
26189a1d03eSRichard // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
26289a1d03eSRichard Mutable Copy = A;
26389a1d03eSRichard Mutable Copy2(A);
26489a1d03eSRichard }
26589a1d03eSRichard }
26689a1d03eSRichard
positiveTwoConstConstructorArgs()26789a1d03eSRichard void positiveTwoConstConstructorArgs() {
26889a1d03eSRichard for (auto A : View<Iterator<Mutable>>()) {
26989a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
27089a1d03eSRichard // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
27189a1d03eSRichard Mutable Copy(A, A);
27289a1d03eSRichard }
27389a1d03eSRichard }
27489a1d03eSRichard
PositiveConstMemberOperatorInvoked()27589a1d03eSRichard void PositiveConstMemberOperatorInvoked() {
27689a1d03eSRichard for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
27789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
27889a1d03eSRichard // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
27989a1d03eSRichard bool result = ConstOperatorInvokee == Mutable();
28089a1d03eSRichard }
28189a1d03eSRichard }
28289a1d03eSRichard
PositiveConstNonMemberOperatorInvoked()28389a1d03eSRichard void PositiveConstNonMemberOperatorInvoked() {
28489a1d03eSRichard for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
28589a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
28689a1d03eSRichard // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
28789a1d03eSRichard bool result = ConstOperatorInvokee != Mutable();
28889a1d03eSRichard }
28989a1d03eSRichard }
29089a1d03eSRichard
IgnoreLoopVariableNotUsedInLoopBody()29189a1d03eSRichard void IgnoreLoopVariableNotUsedInLoopBody() {
29289a1d03eSRichard for (auto _ : View<Iterator<S>>()) {
29389a1d03eSRichard }
29489a1d03eSRichard }
29589a1d03eSRichard
29689a1d03eSRichard template <typename T>
29789a1d03eSRichard struct ValueReturningIterator {
operator ++ValueReturningIterator29889a1d03eSRichard void operator++() {}
operator *ValueReturningIterator29989a1d03eSRichard T operator*() { return T(); }
operator !=ValueReturningIterator30089a1d03eSRichard bool operator!=(const ValueReturningIterator &) { return false; }
30189a1d03eSRichard typedef const T &const_reference;
30289a1d03eSRichard };
30389a1d03eSRichard
negativeValueIterator()30489a1d03eSRichard void negativeValueIterator() {
30589a1d03eSRichard // Check does not trigger for iterators that return elements by value.
30689a1d03eSRichard for (const S SS : View<ValueReturningIterator<S>>()) {
30789a1d03eSRichard }
30889a1d03eSRichard }
30989a1d03eSRichard
createView(S)31089a1d03eSRichard View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }
31189a1d03eSRichard
positiveValueIteratorUsedElseWhere()31289a1d03eSRichard void positiveValueIteratorUsedElseWhere() {
31389a1d03eSRichard for (const S SS : createView(*ValueReturningIterator<S>())) {
31489a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
31589a1d03eSRichard // a reference type; this creates a copy in each iteration; consider making
31689a1d03eSRichard // this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
31789a1d03eSRichard // SS : createView(*ValueReturningIterator<S>())) {
31889a1d03eSRichard }
31989a1d03eSRichard }
3201e512688SShivam Gupta
positiveConstMemberExpr()3211e512688SShivam Gupta void positiveConstMemberExpr() {
3221e512688SShivam Gupta struct Struct {
3231e512688SShivam Gupta Mutable Member;
3241e512688SShivam Gupta };
3251e512688SShivam Gupta for (Struct SS : View<Iterator<Struct>>()) {
3261e512688SShivam Gupta // CHECK-MESSAGES: [[@LINE-1]]:15: warning: loop variable is copied
3271e512688SShivam Gupta // CHECK-FIXES: for (const Struct& SS : View<Iterator<Struct>>()) {
3281e512688SShivam Gupta auto MemberCopy = SS.Member;
3291e512688SShivam Gupta const auto &ConstRef = SS.Member;
3301e512688SShivam Gupta bool b = SS.Member.constMethod();
3311e512688SShivam Gupta use(SS.Member);
3321e512688SShivam Gupta useByConstValue(SS.Member);
3331e512688SShivam Gupta useByValue(SS.Member);
3341e512688SShivam Gupta }
3351e512688SShivam Gupta }
3361e512688SShivam Gupta
negativeNonConstMemberExpr()3371e512688SShivam Gupta void negativeNonConstMemberExpr() {
3381e512688SShivam Gupta struct Struct {
3391e512688SShivam Gupta Mutable Member;
3401e512688SShivam Gupta };
3411e512688SShivam Gupta for (Struct SS : View<Iterator<Struct>>()) {
3421e512688SShivam Gupta SS.Member.setBool(true);
3431e512688SShivam Gupta }
3441e512688SShivam Gupta for (Struct SS : View<Iterator<Struct>>()) {
3451e512688SShivam Gupta SS.Member[1];
3461e512688SShivam Gupta }
3471e512688SShivam Gupta for (Struct SS : View<Iterator<Struct>>()) {
3481e512688SShivam Gupta mutate(SS.Member);
3491e512688SShivam Gupta }
3501e512688SShivam Gupta for (Struct SS : View<Iterator<Struct>>()) {
3511e512688SShivam Gupta mutate(&SS.Member);
3521e512688SShivam Gupta }
3531e512688SShivam Gupta }
3541e512688SShivam Gupta
355