1 // RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing
2
3 namespace std {
4
5 template <typename _Tp>
6 struct remove_reference { typedef _Tp type; };
7 template <typename _Tp>
8 struct remove_reference<_Tp&> { typedef _Tp type; };
9 template <typename _Tp>
10 struct remove_reference<_Tp&&> { typedef _Tp type; };
11
12 template <typename _Tp>
move(_Tp && __t)13 constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
14 return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
15 }
16
17 } // std
18
19 template <typename T>
20 struct Iterator {
operator ++Iterator21 void operator++() {}
operator *Iterator22 const T& operator*() {
23 static T* TT = new T();
24 return *TT;
25 }
operator !=Iterator26 bool operator!=(const Iterator &) { return false; }
27 typedef const T& const_reference;
28 };
29 template <typename T>
30 struct View {
31 View() = default;
beginView32 T begin() { return T(); }
beginView33 T begin() const { return T(); }
endView34 T end() { return T(); }
endView35 T end() const { return T(); }
36 typedef typename T::const_reference const_reference;
37 };
38
39 struct ConstructorConvertible {
40 };
41
42 struct S {
43 S();
44 S(const S &);
SS45 S(const ConstructorConvertible&) {}
46 ~S();
47 S &operator=(const S &);
48 };
49
50 struct Convertible {
operator SConvertible51 operator S() const {
52 return S();
53 }
54 };
55
negativeConstReference()56 void negativeConstReference() {
57 for (const S &S1 : View<Iterator<S>>()) {
58 }
59 }
60
negativeUserDefinedConversion()61 void negativeUserDefinedConversion() {
62 Convertible C[0];
63 for (const S S1 : C) {
64 }
65 }
66
negativeImplicitConstructorConversion()67 void negativeImplicitConstructorConversion() {
68 ConstructorConvertible C[0];
69 for (const S S1 : C) {
70 }
71 }
72
73 template <typename T>
uninstantiated()74 void uninstantiated() {
75 for (const S S1 : View<Iterator<S>>()) {}
76 // 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]
77 // CHECK-FIXES: {{^}} for (const S& S1 : View<Iterator<S>>()) {}
78
79 // Don't warn on dependent types.
80 for (const T t1 : View<Iterator<T>>()) {
81 }
82 }
83
84 template <typename T>
instantiated()85 void instantiated() {
86 for (const S S2 : View<Iterator<S>>()) {}
87 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
88 // CHECK-FIXES: {{^}} for (const S& S2 : View<Iterator<S>>()) {}
89
90 for (const T T2 : View<Iterator<T>>()) {}
91 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
92 // CHECK-FIXES: {{^}} for (const T& T2 : View<Iterator<T>>()) {}
93 }
94
95 template <typename T>
instantiatedNegativeTypedefConstReference()96 void instantiatedNegativeTypedefConstReference() {
97 for (typename T::const_reference T2 : T()) {
98 S S1 = T2;
99 }
100 }
101
f()102 void f() {
103 instantiated<int>();
104 instantiated<S>();
105 instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();
106 }
107
108 struct Mutable {
MutableMutable109 Mutable() {}
110 Mutable(const Mutable &) = default;
111 Mutable(Mutable&&) = default;
MutableMutable112 Mutable(const Mutable &, const Mutable &) {}
setBoolMutable113 void setBool(bool B) {}
constMethodMutable114 bool constMethod() const {
115 return true;
116 }
operator []Mutable117 Mutable& operator[](int I) {
118 return *this;
119 }
operator ==Mutable120 bool operator==(const Mutable &Other) const {
121 return true;
122 }
~MutableMutable123 ~Mutable() {}
124 };
125
126 struct Point {
~PointPoint127 ~Point() {}
128 int x, y;
129 };
130
operator <<(Mutable & Out,bool B)131 Mutable& operator<<(Mutable &Out, bool B) {
132 Out.setBool(B);
133 return Out;
134 }
135
operator !=(const Mutable & M1,const Mutable & M2)136 bool operator!=(const Mutable& M1, const Mutable& M2) {
137 return false;
138 }
139
140 void use(const Mutable &M);
141 void use(int I);
142 void useTwice(const Mutable &M1, const Mutable &M2);
143 void useByValue(Mutable M);
144 void useByConstValue(const Mutable M);
145 void mutate(Mutable *M);
146 void mutate(Mutable &M);
147 void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
148
negativeVariableIsMutated()149 void negativeVariableIsMutated() {
150 for (auto M : View<Iterator<Mutable>>()) {
151 mutate(M);
152 }
153 for (auto M : View<Iterator<Mutable>>()) {
154 mutate(&M);
155 }
156 for (auto M : View<Iterator<Mutable>>()) {
157 M.setBool(true);
158 }
159 }
160
negativeOnceConstOnceMutated()161 void negativeOnceConstOnceMutated() {
162 for (auto M : View<Iterator<Mutable>>()) {
163 onceConstOnceMutated(M, M);
164 }
165 }
166
negativeVarIsMoved()167 void negativeVarIsMoved() {
168 for (auto M : View<Iterator<Mutable>>()) {
169 auto Moved = std::move(M);
170 }
171 }
172
negativeNonConstOperatorIsInvoked()173 void negativeNonConstOperatorIsInvoked() {
174 for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
175 auto& N = NonConstOperatorInvokee[0];
176 }
177 }
178
negativeNonConstNonMemberOperatorInvoked()179 void negativeNonConstNonMemberOperatorInvoked() {
180 for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
181 NonConstOperatorInvokee << true;
182 }
183 }
184
negativeConstCheapToCopy()185 void negativeConstCheapToCopy() {
186 for (const int I : View<Iterator<int>>()) {
187 }
188 }
189
negativeConstCheapToCopyTypedef()190 void negativeConstCheapToCopyTypedef() {
191 typedef const int ConstInt;
192 for (ConstInt C : View<Iterator<ConstInt>>()) {
193 }
194 }
195
negativeCheapToCopy()196 void negativeCheapToCopy() {
197 for (int I : View<Iterator<int>>()) {
198 use(I);
199 }
200 }
201
negativeCheapToCopyTypedef()202 void negativeCheapToCopyTypedef() {
203 typedef int Int;
204 for (Int I : View<Iterator<Int>>()) {
205 use(I);
206 }
207 }
208
positiveOnlyConstMethodInvoked()209 void positiveOnlyConstMethodInvoked() {
210 for (auto M : View<Iterator<Mutable>>()) {
211 // 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]
212 // CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {
213 M.constMethod();
214 }
215 }
216
positiveOnlyUsedAsConstArguments()217 void positiveOnlyUsedAsConstArguments() {
218 for (auto UsedAsConst : View<Iterator<Mutable>>()) {
219 // 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]
220 // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {
221 use(UsedAsConst);
222 useTwice(UsedAsConst, UsedAsConst);
223 useByValue(UsedAsConst);
224 useByConstValue(UsedAsConst);
225 }
226 }
227
positiveOnlyAccessedFieldAsConst()228 void positiveOnlyAccessedFieldAsConst() {
229 for (auto UsedAsConst : View<Iterator<Point>>()) {
230 // 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]
231 // CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {
232 use(UsedAsConst.x);
233 use(UsedAsConst.y);
234 }
235 }
236
positiveOnlyUsedInCopyConstructor()237 void positiveOnlyUsedInCopyConstructor() {
238 for (auto A : View<Iterator<Mutable>>()) {
239 // 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]
240 // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
241 Mutable Copy = A;
242 Mutable Copy2(A);
243 }
244 }
245
positiveTwoConstConstructorArgs()246 void positiveTwoConstConstructorArgs() {
247 for (auto A : View<Iterator<Mutable>>()) {
248 // 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]
249 // CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
250 Mutable Copy(A, A);
251 }
252 }
253
PositiveConstMemberOperatorInvoked()254 void PositiveConstMemberOperatorInvoked() {
255 for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
256 // 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]
257 // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
258 bool result = ConstOperatorInvokee == Mutable();
259 }
260 }
261
PositiveConstNonMemberOperatorInvoked()262 void PositiveConstNonMemberOperatorInvoked() {
263 for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
264 // 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]
265 // CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
266 bool result = ConstOperatorInvokee != Mutable();
267 }
268 }
269
IgnoreLoopVariableNotUsedInLoopBody()270 void IgnoreLoopVariableNotUsedInLoopBody() {
271 for (auto _ : View<Iterator<S>>()) {
272 }
273 }
274
275 template <typename T>
276 struct ValueReturningIterator {
operator ++ValueReturningIterator277 void operator++() {}
operator *ValueReturningIterator278 T operator*() { return T(); }
operator !=ValueReturningIterator279 bool operator!=(const ValueReturningIterator &) { return false; }
280 typedef const T &const_reference;
281 };
282
negativeValueIterator()283 void negativeValueIterator() {
284 // Check does not trigger for iterators that return elements by value.
285 for (const S SS : View<ValueReturningIterator<S>>()) {
286 }
287 }
288
createView(S)289 View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }
290
positiveValueIteratorUsedElseWhere()291 void positiveValueIteratorUsedElseWhere() {
292 for (const S SS : createView(*ValueReturningIterator<S>())) {
293 // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
294 // a reference type; this creates a copy in each iteration; consider making
295 // this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
296 // SS : createView(*ValueReturningIterator<S>())) {
297 }
298 }
299