1 | // RUN: %check_clang_tidy --match-partial-fixes -std=c++17-or-later %s performance-unnecessary-copy-initialization %t |
2 | |
3 | template <typename T> |
4 | struct Iterator { |
5 | void operator++(); |
6 | T &operator*() const; |
7 | bool operator!=(const Iterator &) const; |
8 | typedef const T &const_reference; |
9 | }; |
10 | |
11 | template <typename T> |
12 | struct ConstIterator { |
13 | void operator++(); |
14 | const T &operator*() const; |
15 | bool operator!=(const ConstIterator &) const; |
16 | typedef const T &const_reference; |
17 | }; |
18 | |
19 | struct ExpensiveToCopyType { |
20 | ExpensiveToCopyType(); |
21 | virtual ~ExpensiveToCopyType(); |
22 | const ExpensiveToCopyType &reference() const; |
23 | using ConstRef = const ExpensiveToCopyType &; |
24 | ConstRef referenceWithAlias() const; |
25 | const ExpensiveToCopyType *pointer() const; |
26 | void nonConstMethod(); |
27 | bool constMethod() const; |
28 | template <typename A> |
29 | const A &templatedAccessor() const; |
30 | operator int() const; // Implicit conversion to int. |
31 | |
32 | static const ExpensiveToCopyType &instance(); |
33 | }; |
34 | |
35 | template <typename T> |
36 | struct Container { |
37 | using reference = T&; |
38 | using const_reference = const T&; |
39 | |
40 | bool empty() const; |
41 | const T& operator[](int) const; |
42 | const T& operator[](int); |
43 | Iterator<T> begin(); |
44 | Iterator<T> end(); |
45 | ConstIterator<T> begin() const; |
46 | ConstIterator<T> end() const; |
47 | void nonConstMethod(); |
48 | bool constMethod() const; |
49 | |
50 | reference at(int) const; |
51 | const_reference at(int); |
52 | |
53 | }; |
54 | |
55 | using ExpensiveToCopyContainerAlias = Container<ExpensiveToCopyType>; |
56 | |
57 | struct TrivialToCopyType { |
58 | const TrivialToCopyType &reference() const; |
59 | }; |
60 | |
61 | struct WeirdCopyCtorType { |
62 | WeirdCopyCtorType(); |
63 | WeirdCopyCtorType(const WeirdCopyCtorType &w, bool oh_yes = true); |
64 | |
65 | void nonConstMethod(); |
66 | bool constMethod() const; |
67 | }; |
68 | |
69 | ExpensiveToCopyType global_expensive_to_copy_type; |
70 | |
71 | const ExpensiveToCopyType &ExpensiveTypeReference(); |
72 | const ExpensiveToCopyType &freeFunctionWithArg(const ExpensiveToCopyType &); |
73 | const ExpensiveToCopyType &freeFunctionWithDefaultArg( |
74 | const ExpensiveToCopyType *arg = nullptr); |
75 | const TrivialToCopyType &TrivialTypeReference(); |
76 | |
77 | void mutate(ExpensiveToCopyType &); |
78 | void mutate(ExpensiveToCopyType *); |
79 | void useAsConstPointer(const ExpensiveToCopyType *); |
80 | void useAsConstReference(const ExpensiveToCopyType &); |
81 | void useByValue(ExpensiveToCopyType); |
82 | |
83 | void PositiveFunctionCall() { |
84 | const auto AutoAssigned = ExpensiveTypeReference(); |
85 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference; consider making it a const reference [performance-unnecessary-copy-initialization] |
86 | // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); |
87 | AutoAssigned.constMethod(); |
88 | |
89 | const auto AutoCopyConstructed(ExpensiveTypeReference()); |
90 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
91 | // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); |
92 | AutoCopyConstructed.constMethod(); |
93 | |
94 | const ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); |
95 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
96 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); |
97 | VarAssigned.constMethod(); |
98 | |
99 | const ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); |
100 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
101 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); |
102 | VarCopyConstructed.constMethod(); |
103 | } |
104 | |
105 | void PositiveStaticMethodCall() { |
106 | const auto AutoAssigned = ExpensiveToCopyType::instance(); |
107 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference; consider making it a const reference [performance-unnecessary-copy-initialization] |
108 | // CHECK-FIXES: const auto& AutoAssigned = ExpensiveToCopyType::instance(); |
109 | AutoAssigned.constMethod(); |
110 | |
111 | const auto AutoCopyConstructed(ExpensiveToCopyType::instance()); |
112 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
113 | // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveToCopyType::instance()); |
114 | AutoCopyConstructed.constMethod(); |
115 | |
116 | const ExpensiveToCopyType VarAssigned = ExpensiveToCopyType::instance(); |
117 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
118 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveToCopyType::instance(); |
119 | VarAssigned.constMethod(); |
120 | |
121 | const ExpensiveToCopyType VarCopyConstructed(ExpensiveToCopyType::instance()); |
122 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
123 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveToCopyType::instance()); |
124 | VarCopyConstructed.constMethod(); |
125 | } |
126 | |
127 | void PositiveMethodCallConstReferenceParam(const ExpensiveToCopyType &Obj) { |
128 | const auto AutoAssigned = Obj.reference(); |
129 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
130 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
131 | AutoAssigned.constMethod(); |
132 | |
133 | const auto AutoCopyConstructed(Obj.reference()); |
134 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
135 | // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); |
136 | AutoCopyConstructed.constMethod(); |
137 | |
138 | const ExpensiveToCopyType VarAssigned = Obj.reference(); |
139 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
140 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); |
141 | VarAssigned.constMethod(); |
142 | |
143 | const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
144 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
145 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); |
146 | VarCopyConstructed.constMethod(); |
147 | } |
148 | |
149 | void PositiveMethodCallConstParam(const ExpensiveToCopyType Obj) { |
150 | const auto AutoAssigned = Obj.reference(); |
151 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
152 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
153 | AutoAssigned.constMethod(); |
154 | |
155 | const auto AutoCopyConstructed(Obj.reference()); |
156 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
157 | // CHECK-FIXES: const auto& AutoCopyConstructed(Obj.reference()); |
158 | AutoCopyConstructed.constMethod(); |
159 | |
160 | const ExpensiveToCopyType VarAssigned = Obj.reference(); |
161 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
162 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj.reference(); |
163 | VarAssigned.constMethod(); |
164 | |
165 | const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
166 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
167 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj.reference()); |
168 | VarCopyConstructed.constMethod(); |
169 | } |
170 | |
171 | void PositiveMethodCallConstPointerParam(const ExpensiveToCopyType *const Obj) { |
172 | const auto AutoAssigned = Obj->reference(); |
173 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
174 | // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); |
175 | AutoAssigned.constMethod(); |
176 | |
177 | const auto AutoCopyConstructed(Obj->reference()); |
178 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
179 | // CHECK-FIXES: const auto& AutoCopyConstructed(Obj->reference()); |
180 | AutoCopyConstructed.constMethod(); |
181 | |
182 | const ExpensiveToCopyType VarAssigned = Obj->reference(); |
183 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
184 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = Obj->reference(); |
185 | VarAssigned.constMethod(); |
186 | |
187 | const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); |
188 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
189 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(Obj->reference()); |
190 | VarCopyConstructed.constMethod(); |
191 | } |
192 | |
193 | void PositiveOperatorCallConstReferenceParam(const Container<ExpensiveToCopyType> &C) { |
194 | const auto AutoAssigned = C[42]; |
195 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
196 | // CHECK-FIXES: const auto& AutoAssigned = C[42]; |
197 | AutoAssigned.constMethod(); |
198 | |
199 | const auto AutoCopyConstructed(C[42]); |
200 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
201 | // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); |
202 | AutoCopyConstructed.constMethod(); |
203 | |
204 | const ExpensiveToCopyType VarAssigned = C[42]; |
205 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
206 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; |
207 | VarAssigned.constMethod(); |
208 | |
209 | const ExpensiveToCopyType VarCopyConstructed(C[42]); |
210 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
211 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); |
212 | VarCopyConstructed.constMethod(); |
213 | } |
214 | |
215 | void PositiveOperatorCallConstValueParam(const Container<ExpensiveToCopyType> C) { |
216 | const auto AutoAssigned = C[42]; |
217 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
218 | // CHECK-FIXES: const auto& AutoAssigned = C[42]; |
219 | AutoAssigned.constMethod(); |
220 | |
221 | const auto AutoCopyConstructed(C[42]); |
222 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
223 | // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); |
224 | AutoCopyConstructed.constMethod(); |
225 | |
226 | const ExpensiveToCopyType VarAssigned = C[42]; |
227 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
228 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; |
229 | VarAssigned.constMethod(); |
230 | |
231 | const ExpensiveToCopyType VarCopyConstructed(C[42]); |
232 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
233 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); |
234 | VarCopyConstructed.constMethod(); |
235 | } |
236 | |
237 | void PositiveOperatorValueParam(Container<ExpensiveToCopyType> C) { |
238 | const auto AutoAssigned = C[42]; |
239 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
240 | // CHECK-FIXES: const auto& AutoAssigned = C[42]; |
241 | AutoAssigned.constMethod(); |
242 | |
243 | const auto AutoCopyConstructed(C[42]); |
244 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
245 | // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); |
246 | AutoCopyConstructed.constMethod(); |
247 | |
248 | const ExpensiveToCopyType VarAssigned = C.at(42); |
249 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
250 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C.at(42); |
251 | VarAssigned.constMethod(); |
252 | |
253 | const ExpensiveToCopyType VarCopyConstructed(C.at(42)); |
254 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
255 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C.at(42)); |
256 | VarCopyConstructed.constMethod(); |
257 | } |
258 | |
259 | void PositiveOperatorCallConstValueParamAlias(const ExpensiveToCopyContainerAlias C) { |
260 | const auto AutoAssigned = C[42]; |
261 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
262 | // CHECK-FIXES: const auto& AutoAssigned = C[42]; |
263 | AutoAssigned.constMethod(); |
264 | |
265 | const auto AutoCopyConstructed(C[42]); |
266 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
267 | // CHECK-FIXES: const auto& AutoCopyConstructed(C[42]); |
268 | AutoCopyConstructed.constMethod(); |
269 | |
270 | const ExpensiveToCopyType VarAssigned = C[42]; |
271 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
272 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C[42]; |
273 | VarAssigned.constMethod(); |
274 | |
275 | const ExpensiveToCopyType VarCopyConstructed(C[42]); |
276 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
277 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C[42]); |
278 | VarCopyConstructed.constMethod(); |
279 | } |
280 | |
281 | void PositiveOperatorCallConstPtrParam(const Container<ExpensiveToCopyType>* C) { |
282 | const auto AutoAssigned = (*C)[42]; |
283 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
284 | // CHECK-FIXES: const auto& AutoAssigned = (*C)[42]; |
285 | AutoAssigned.constMethod(); |
286 | |
287 | const auto AutoCopyConstructed((*C)[42]); |
288 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed' |
289 | // CHECK-FIXES: const auto& AutoCopyConstructed((*C)[42]); |
290 | AutoCopyConstructed.constMethod(); |
291 | |
292 | const ExpensiveToCopyType VarAssigned = C->at(42); |
293 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned' |
294 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C->at(42); |
295 | VarAssigned.constMethod(); |
296 | |
297 | const ExpensiveToCopyType VarCopyConstructed(C->at(42)); |
298 | // CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed' |
299 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C->at(42)); |
300 | VarCopyConstructed.constMethod(); |
301 | } |
302 | |
303 | void PositiveLocalConstValue() { |
304 | const ExpensiveToCopyType Obj; |
305 | const auto UnnecessaryCopy = Obj.reference(); |
306 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
307 | // CHECK-FIXES: const auto& UnnecessaryCopy = Obj.reference(); |
308 | UnnecessaryCopy.constMethod(); |
309 | } |
310 | |
311 | void PositiveLocalConstRef() { |
312 | const ExpensiveToCopyType Obj; |
313 | const ExpensiveToCopyType &ConstReference = Obj.reference(); |
314 | const auto UnnecessaryCopy = ConstReference.reference(); |
315 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
316 | // CHECK-FIXES: const auto& UnnecessaryCopy = ConstReference.reference(); |
317 | UnnecessaryCopy.constMethod(); |
318 | } |
319 | |
320 | void PositiveLocalConstPointer() { |
321 | const ExpensiveToCopyType Obj; |
322 | const ExpensiveToCopyType *const ConstPointer = &Obj; |
323 | const auto UnnecessaryCopy = ConstPointer->reference(); |
324 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' |
325 | // CHECK-FIXES: const auto& UnnecessaryCopy = ConstPointer->reference(); |
326 | UnnecessaryCopy.constMethod(); |
327 | } |
328 | |
329 | void NegativeFunctionCallTrivialType() { |
330 | const auto AutoAssigned = TrivialTypeReference(); |
331 | const auto AutoCopyConstructed(TrivialTypeReference()); |
332 | const TrivialToCopyType VarAssigned = TrivialTypeReference(); |
333 | const TrivialToCopyType VarCopyConstructed(TrivialTypeReference()); |
334 | } |
335 | |
336 | void NegativeStaticLocalVar(const ExpensiveToCopyType &Obj) { |
337 | static const auto StaticVar = Obj.reference(); |
338 | } |
339 | |
340 | void PositiveFunctionCallExpensiveTypeNonConstVariable() { |
341 | auto AutoAssigned = ExpensiveTypeReference(); |
342 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoAssigned' is copy-constructed from a const reference but is only used as const reference; consider making it a const reference [performance-unnecessary-copy-initialization] |
343 | // CHECK-FIXES: const auto& AutoAssigned = ExpensiveTypeReference(); |
344 | AutoAssigned.constMethod(); |
345 | |
346 | auto AutoCopyConstructed(ExpensiveTypeReference()); |
347 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'AutoCopyConstructed' |
348 | // CHECK-FIXES: const auto& AutoCopyConstructed(ExpensiveTypeReference()); |
349 | AutoCopyConstructed.constMethod(); |
350 | |
351 | ExpensiveToCopyType VarAssigned = ExpensiveTypeReference(); |
352 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarAssigned' |
353 | // CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = ExpensiveTypeReference(); |
354 | VarAssigned.constMethod(); |
355 | |
356 | ExpensiveToCopyType VarCopyConstructed(ExpensiveTypeReference()); |
357 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: the variable 'VarCopyConstructed' |
358 | // CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(ExpensiveTypeReference()); |
359 | VarCopyConstructed.constMethod(); |
360 | } |
361 | |
362 | void positiveNonConstVarInCodeBlock(const ExpensiveToCopyType &Obj) { |
363 | { |
364 | auto Assigned = Obj.reference(); |
365 | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: the variable 'Assigned' |
366 | // CHECK-FIXES: const auto& Assigned = Obj.reference(); |
367 | Assigned.reference(); |
368 | useAsConstReference(Assigned); |
369 | useByValue(Assigned); |
370 | } |
371 | } |
372 | |
373 | void positiveNonConstVarInCodeBlockWithAlias(const ExpensiveToCopyType &Obj) { |
374 | { |
375 | const ExpensiveToCopyType Assigned = Obj.referenceWithAlias(); |
376 | // CHECK-MESSAGES: [[@LINE-1]]:31: warning: the const qualified variable |
377 | // CHECK-FIXES: const ExpensiveToCopyType& Assigned = Obj.referenceWithAlias(); |
378 | useAsConstReference(Assigned); |
379 | } |
380 | } |
381 | |
382 | void negativeNonConstVarWithNonConstUse(const ExpensiveToCopyType &Obj) { |
383 | { |
384 | auto NonConstInvoked = Obj.reference(); |
385 | // CHECK-FIXES: auto NonConstInvoked = Obj.reference(); |
386 | NonConstInvoked.nonConstMethod(); |
387 | } |
388 | { |
389 | auto Reassigned = Obj.reference(); |
390 | // CHECK-FIXES: auto Reassigned = Obj.reference(); |
391 | Reassigned = ExpensiveToCopyType(); |
392 | } |
393 | { |
394 | auto MutatedByReference = Obj.reference(); |
395 | // CHECK-FIXES: auto MutatedByReference = Obj.reference(); |
396 | mutate(MutatedByReference); |
397 | } |
398 | { |
399 | auto MutatedByPointer = Obj.reference(); |
400 | // CHECK-FIXES: auto MutatedByPointer = Obj.reference(); |
401 | mutate(&MutatedByPointer); |
402 | } |
403 | } |
404 | |
405 | void PositiveMethodCallNonConstRefNotModified(ExpensiveToCopyType &Obj) { |
406 | const auto AutoAssigned = Obj.reference(); |
407 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
408 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
409 | AutoAssigned.constMethod(); |
410 | } |
411 | |
412 | void NegativeMethodCallNonConstRefIsModified(ExpensiveToCopyType &Obj) { |
413 | const auto AutoAssigned = Obj.reference(); |
414 | const auto AutoCopyConstructed(Obj.reference()); |
415 | const ExpensiveToCopyType VarAssigned = Obj.reference(); |
416 | const ExpensiveToCopyType VarCopyConstructed(Obj.reference()); |
417 | mutate(&Obj); |
418 | } |
419 | |
420 | void PositiveMethodCallNonConstNotModified(ExpensiveToCopyType Obj) { |
421 | const auto AutoAssigned = Obj.reference(); |
422 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
423 | // CHECK-FIXES: const auto& AutoAssigned = Obj.reference(); |
424 | AutoAssigned.constMethod(); |
425 | } |
426 | |
427 | void NegativeMethodCallNonConstValueArgumentIsModified(ExpensiveToCopyType Obj) { |
428 | Obj.nonConstMethod(); |
429 | const auto AutoAssigned = Obj.reference(); |
430 | } |
431 | |
432 | void PositiveMethodCallNonConstPointerNotModified(ExpensiveToCopyType *const Obj) { |
433 | const auto AutoAssigned = Obj->reference(); |
434 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
435 | // CHECK-FIXES: const auto& AutoAssigned = Obj->reference(); |
436 | Obj->constMethod(); |
437 | AutoAssigned.constMethod(); |
438 | } |
439 | |
440 | void NegativeMethodCallNonConstPointerIsModified(ExpensiveToCopyType *const Obj) { |
441 | const auto AutoAssigned = Obj->reference(); |
442 | const auto AutoCopyConstructed(Obj->reference()); |
443 | const ExpensiveToCopyType VarAssigned = Obj->reference(); |
444 | const ExpensiveToCopyType VarCopyConstructed(Obj->reference()); |
445 | mutate(Obj); |
446 | } |
447 | |
448 | void PositiveLocalVarIsNotModified() { |
449 | ExpensiveToCopyType LocalVar; |
450 | const auto AutoAssigned = LocalVar.reference(); |
451 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' |
452 | // CHECK-FIXES: const auto& AutoAssigned = LocalVar.reference(); |
453 | AutoAssigned.constMethod(); |
454 | } |
455 | |
456 | void NegativeLocalVarIsModified() { |
457 | ExpensiveToCopyType Obj; |
458 | const auto AutoAssigned = Obj.reference(); |
459 | Obj = AutoAssigned; |
460 | } |
461 | |
462 | struct NegativeConstructor { |
463 | NegativeConstructor(const ExpensiveToCopyType &Obj) : Obj(Obj) {} |
464 | ExpensiveToCopyType Obj; |
465 | }; |
466 | |
467 | #define UNNECESSARY_COPY_INIT_IN_MACRO_BODY(TYPE) \ |
468 | void functionWith##TYPE(const TYPE &T) { \ |
469 | auto AssignedInMacro = T.reference(); \ |
470 | } \ |
471 | // Ensure fix is not applied. |
472 | // CHECK-FIXES: auto AssignedInMacro = T.reference(); |
473 | |
474 | UNNECESSARY_COPY_INIT_IN_MACRO_BODY(ExpensiveToCopyType) |
475 | // CHECK-MESSAGES: [[@LINE-1]]:1: warning: the variable 'AssignedInMacro' is copy-constructed |
476 | |
477 | #define UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(ARGUMENT) ARGUMENT |
478 | |
479 | void PositiveMacroArgument(const ExpensiveToCopyType &Obj) { |
480 | UNNECESSARY_COPY_INIT_IN_MACRO_ARGUMENT(auto CopyInMacroArg = Obj.reference()); |
481 | // CHECK-MESSAGES: [[@LINE-1]]:48: warning: the variable 'CopyInMacroArg' is copy-constructed |
482 | // Ensure fix is not applied. |
483 | // CHECK-FIXES: auto CopyInMacroArg = Obj.reference() |
484 | CopyInMacroArg.constMethod(); |
485 | } |
486 | |
487 | void PositiveLocalCopyConstMethodInvoked() { |
488 | ExpensiveToCopyType orig; |
489 | ExpensiveToCopyType copy_1 = orig; |
490 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_1' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] |
491 | // CHECK-FIXES: const ExpensiveToCopyType& copy_1 = orig; |
492 | copy_1.constMethod(); |
493 | orig.constMethod(); |
494 | } |
495 | |
496 | void PositiveLocalCopyUsingExplicitCopyCtor() { |
497 | ExpensiveToCopyType orig; |
498 | ExpensiveToCopyType copy_2(orig); |
499 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_2' |
500 | // CHECK-FIXES: const ExpensiveToCopyType& copy_2(orig); |
501 | copy_2.constMethod(); |
502 | orig.constMethod(); |
503 | } |
504 | |
505 | void PositiveLocalCopyCopyIsArgument(const ExpensiveToCopyType &orig) { |
506 | ExpensiveToCopyType copy_3 = orig; |
507 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_3' |
508 | // CHECK-FIXES: const ExpensiveToCopyType& copy_3 = orig; |
509 | copy_3.constMethod(); |
510 | } |
511 | |
512 | void PositiveLocalCopyUsedAsConstRef() { |
513 | ExpensiveToCopyType orig; |
514 | ExpensiveToCopyType copy_4 = orig; |
515 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_4' |
516 | // CHECK-FIXES: const ExpensiveToCopyType& copy_4 = orig; |
517 | useAsConstReference(orig); |
518 | copy_4.constMethod(); |
519 | } |
520 | |
521 | void PositiveLocalCopyTwice() { |
522 | ExpensiveToCopyType orig; |
523 | ExpensiveToCopyType copy_5 = orig; |
524 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_5' |
525 | // CHECK-FIXES: const ExpensiveToCopyType& copy_5 = orig; |
526 | ExpensiveToCopyType copy_6 = copy_5; |
527 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy_6' |
528 | // CHECK-FIXES: const ExpensiveToCopyType& copy_6 = copy_5; |
529 | copy_5.constMethod(); |
530 | copy_6.constMethod(); |
531 | orig.constMethod(); |
532 | } |
533 | |
534 | |
535 | void PositiveLocalCopyWeirdCopy() { |
536 | WeirdCopyCtorType orig; |
537 | WeirdCopyCtorType weird_1(orig); |
538 | // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_1' |
539 | // CHECK-FIXES: const WeirdCopyCtorType& weird_1(orig); |
540 | weird_1.constMethod(); |
541 | |
542 | WeirdCopyCtorType weird_2 = orig; |
543 | // CHECK-MESSAGES: [[@LINE-1]]:21: warning: local copy 'weird_2' |
544 | // CHECK-FIXES: const WeirdCopyCtorType& weird_2 = orig; |
545 | weird_2.constMethod(); |
546 | } |
547 | |
548 | void NegativeLocalCopySimpleTypes() { |
549 | int i1 = 0; |
550 | int i2 = i1; |
551 | } |
552 | |
553 | void NegativeLocalCopyCopyIsModified() { |
554 | ExpensiveToCopyType orig; |
555 | ExpensiveToCopyType neg_copy_1 = orig; |
556 | neg_copy_1.nonConstMethod(); |
557 | } |
558 | |
559 | void NegativeLocalCopyOriginalIsModified() { |
560 | ExpensiveToCopyType orig; |
561 | ExpensiveToCopyType neg_copy_2 = orig; |
562 | orig.nonConstMethod(); |
563 | } |
564 | |
565 | void NegativeLocalCopyUsedAsRefArg() { |
566 | ExpensiveToCopyType orig; |
567 | ExpensiveToCopyType neg_copy_3 = orig; |
568 | mutate(neg_copy_3); |
569 | } |
570 | |
571 | void NegativeLocalCopyUsedAsPointerArg() { |
572 | ExpensiveToCopyType orig; |
573 | ExpensiveToCopyType neg_copy_4 = orig; |
574 | mutate(&neg_copy_4); |
575 | } |
576 | |
577 | void NegativeLocalCopyCopyFromGlobal() { |
578 | ExpensiveToCopyType neg_copy_5 = global_expensive_to_copy_type; |
579 | } |
580 | |
581 | void NegativeLocalCopyCopyToStatic() { |
582 | ExpensiveToCopyType orig; |
583 | static ExpensiveToCopyType neg_copy_6 = orig; |
584 | } |
585 | |
586 | void NegativeLocalCopyNonConstInForLoop() { |
587 | ExpensiveToCopyType orig; |
588 | for (ExpensiveToCopyType neg_copy_7 = orig; orig.constMethod(); |
589 | orig.nonConstMethod()) { |
590 | orig.constMethod(); |
591 | } |
592 | } |
593 | |
594 | void NegativeLocalCopyWeirdNonCopy() { |
595 | WeirdCopyCtorType orig; |
596 | WeirdCopyCtorType neg_weird_1(orig, false); |
597 | WeirdCopyCtorType neg_weird_2(orig, true); |
598 | } |
599 | void WarningOnlyMultiDeclStmt() { |
600 | ExpensiveToCopyType orig; |
601 | ExpensiveToCopyType copy = orig, copy2; |
602 | // CHECK-MESSAGES: [[@LINE-1]]:23: warning: local copy 'copy' of the variable 'orig' is never modified; consider avoiding the copy [performance-unnecessary-copy-initialization] |
603 | // CHECK-FIXES: ExpensiveToCopyType copy = orig, copy2; |
604 | copy.constMethod(); |
605 | } |
606 | |
607 | class Element {}; |
608 | |
609 | void implicitVarFalsePositive() { |
610 | for (const Element &E : Container<Element>()) { |
611 | } |
612 | } |
613 | |
614 | // This should not trigger the check as the argument could introduce an alias. |
615 | void negativeInitializedFromFreeFunctionWithArg() { |
616 | ExpensiveToCopyType Orig; |
617 | const ExpensiveToCopyType Copy = freeFunctionWithArg(Orig); |
618 | } |
619 | |
620 | void negativeInitializedFromFreeFunctionWithDefaultArg() { |
621 | const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(); |
622 | } |
623 | |
624 | void negativeInitialzedFromFreeFunctionWithNonDefaultArg() { |
625 | ExpensiveToCopyType Orig; |
626 | const ExpensiveToCopyType Copy = freeFunctionWithDefaultArg(arg: &Orig); |
627 | } |
628 | |
629 | namespace std { |
630 | inline namespace __1 { |
631 | |
632 | template <class> |
633 | class function; |
634 | template <class R, class... ArgTypes> |
635 | class function<R(ArgTypes...)> { |
636 | public: |
637 | function(); |
638 | function(const function &Other); |
639 | R operator()(ArgTypes... Args) const; |
640 | }; |
641 | |
642 | } // namespace __1 |
643 | } // namespace std |
644 | |
645 | void negativeStdFunction() { |
646 | std::function<int()> Orig; |
647 | std::function<int()> Copy = Orig; |
648 | int i = Orig(); |
649 | } |
650 | |
651 | using Functor = std::function<int()>; |
652 | |
653 | void negativeAliasedStdFunction() { |
654 | Functor Orig; |
655 | Functor Copy = Orig; |
656 | int i = Orig(); |
657 | } |
658 | |
659 | typedef std::function<int()> TypedefFunc; |
660 | |
661 | void negativeTypedefedStdFunction() { |
662 | TypedefFunc Orig; |
663 | TypedefFunc Copy = Orig; |
664 | int i = Orig(); |
665 | } |
666 | |
667 | namespace fake { |
668 | namespace std { |
669 | template <class R, class... Args> |
670 | struct function { |
671 | // Custom copy constructor makes it expensive to copy; |
672 | function(const function &); |
673 | void constMethod() const; |
674 | }; |
675 | } // namespace std |
676 | |
677 | void positiveFakeStdFunction(std::function<void(int)> F) { |
678 | auto Copy = F; |
679 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'Copy' of the variable 'F' is never modified; |
680 | // CHECK-FIXES: const auto& Copy = F; |
681 | Copy.constMethod(); |
682 | } |
683 | |
684 | } // namespace fake |
685 | |
686 | void positiveInvokedOnStdFunction( |
687 | std::function<void(const ExpensiveToCopyType &)> Update, |
688 | const ExpensiveToCopyType Orig) { |
689 | auto Copy = Orig.reference(); |
690 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'Copy' is copy-constructed from a const reference |
691 | // CHECK-FIXES: const auto& Copy = Orig.reference(); |
692 | Update(Copy); |
693 | } |
694 | |
695 | void negativeInvokedOnStdFunction( |
696 | std::function<void(ExpensiveToCopyType &)> Update, |
697 | const ExpensiveToCopyType Orig) { |
698 | auto Copy = Orig.reference(); |
699 | Update(Copy); |
700 | } |
701 | |
702 | void negativeCopiedFromReferenceToModifiedVar() { |
703 | ExpensiveToCopyType Orig; |
704 | const auto &Ref = Orig; |
705 | const auto NecessaryCopy = Ref; |
706 | Orig.nonConstMethod(); |
707 | } |
708 | |
709 | void positiveCopiedFromReferenceToConstVar() { |
710 | ExpensiveToCopyType Orig; |
711 | const auto &Ref = Orig; |
712 | const auto UnnecessaryCopy = Ref; |
713 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: local copy 'UnnecessaryCopy' of |
714 | // CHECK-FIXES: const auto& UnnecessaryCopy = Ref; |
715 | Orig.constMethod(); |
716 | UnnecessaryCopy.constMethod(); |
717 | } |
718 | |
719 | void negativeCopiedFromGetterOfReferenceToModifiedVar() { |
720 | ExpensiveToCopyType Orig; |
721 | const auto &Ref = Orig.reference(); |
722 | const auto NecessaryCopy = Ref.reference(); |
723 | Orig.nonConstMethod(); |
724 | } |
725 | |
726 | void negativeAliasNonCanonicalPointerType() { |
727 | ExpensiveToCopyType Orig; |
728 | // The use of auto here hides that the type is a pointer type. The check needs |
729 | // to look at the canonical type to detect the aliasing through this pointer. |
730 | const auto Pointer = Orig.pointer(); |
731 | const auto NecessaryCopy = Pointer->reference(); |
732 | Orig.nonConstMethod(); |
733 | } |
734 | |
735 | void negativeAliasTypedefedType() { |
736 | typedef const ExpensiveToCopyType &ReferenceType; |
737 | ExpensiveToCopyType Orig; |
738 | // The typedef hides the fact that this is a reference type. The check needs |
739 | // to look at the canonical type to detect the aliasing. |
740 | ReferenceType Ref = Orig.reference(); |
741 | const auto NecessaryCopy = Ref.reference(); |
742 | Orig.nonConstMethod(); |
743 | } |
744 | |
745 | void positiveCopiedFromGetterOfReferenceToConstVar() { |
746 | ExpensiveToCopyType Orig; |
747 | const auto &Ref = Orig.reference(); |
748 | auto UnnecessaryCopy = Ref.reference(); |
749 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'UnnecessaryCopy' is |
750 | // CHECK-FIXES: const auto& UnnecessaryCopy = Ref.reference(); |
751 | Orig.constMethod(); |
752 | UnnecessaryCopy.constMethod(); |
753 | } |
754 | |
755 | void positiveUnusedReferenceIsRemoved() { |
756 | // clang-format off |
757 | const auto AutoAssigned = ExpensiveTypeReference(); int i = 0; // Foo bar. |
758 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned' is copy-constructed from a const reference but is never used; consider removing the statement [performance-unnecessary-copy-initialization] |
759 | // CHECK-FIXES-NOT: const auto AutoAssigned = ExpensiveTypeReference(); |
760 | // CHECK-FIXES: int i = 0; // Foo bar. |
761 | auto = ExpensiveTypeReference(); // Trailing comment. |
762 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used; |
763 | // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); |
764 | // CHECK-FIXES-NOT: // Trailing comment. |
765 | // clang-format on |
766 | |
767 | auto UnusedAndUnnecessary = ExpensiveTypeReference(); |
768 | // Comments on a new line should not be deleted. |
769 | // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed |
770 | // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference(); |
771 | // CHECK-FIXES: // Comments on a new line should not be deleted. |
772 | } |
773 | |
774 | void positiveLoopedOverObjectIsConst() { |
775 | const Container<ExpensiveToCopyType> Orig; |
776 | for (const auto &Element : Orig) { |
777 | const auto Copy = Element; |
778 | // CHECK-MESSAGES: [[@LINE-1]]:16: warning: local copy 'Copy' |
779 | // CHECK-FIXES: const auto& Copy = Element; |
780 | Orig.constMethod(); |
781 | Copy.constMethod(); |
782 | } |
783 | |
784 | auto Lambda = []() { |
785 | const Container<ExpensiveToCopyType> Orig; |
786 | for (const auto &Element : Orig) { |
787 | const auto Copy = Element; |
788 | // CHECK-MESSAGES: [[@LINE-1]]:18: warning: local copy 'Copy' |
789 | // CHECK-FIXES: const auto& Copy = Element; |
790 | Orig.constMethod(); |
791 | Copy.constMethod(); |
792 | } |
793 | }; |
794 | } |
795 | |
796 | void negativeLoopedOverObjectIsModified() { |
797 | Container<ExpensiveToCopyType> Orig; |
798 | for (const auto &Element : Orig) { |
799 | const auto Copy = Element; |
800 | Orig.nonConstMethod(); |
801 | Copy.constMethod(); |
802 | } |
803 | |
804 | auto Lambda = []() { |
805 | Container<ExpensiveToCopyType> Orig; |
806 | for (const auto &Element : Orig) { |
807 | const auto Copy = Element; |
808 | Orig.nonConstMethod(); |
809 | Copy.constMethod(); |
810 | } |
811 | }; |
812 | } |
813 | |
814 | void negativeReferenceIsInitializedOutsideOfBlock() { |
815 | ExpensiveToCopyType Orig; |
816 | const auto &E2 = Orig; |
817 | if (1 != 2 * 3) { |
818 | const auto C2 = E2; |
819 | Orig.nonConstMethod(); |
820 | C2.constMethod(); |
821 | } |
822 | |
823 | auto Lambda = []() { |
824 | ExpensiveToCopyType Orig; |
825 | const auto &E2 = Orig; |
826 | if (1 != 2 * 3) { |
827 | const auto C2 = E2; |
828 | Orig.nonConstMethod(); |
829 | C2.constMethod(); |
830 | } |
831 | }; |
832 | } |
833 | |
834 | void negativeStructuredBinding() { |
835 | // Structured bindings are not yet supported but can trigger false positives |
836 | // since the DecompositionDecl itself is unused and the check doesn't traverse |
837 | // VarDecls of the BindingDecls. |
838 | struct Pair { |
839 | ExpensiveToCopyType first; |
840 | ExpensiveToCopyType second; |
841 | }; |
842 | |
843 | Pair P; |
844 | const auto [C, D] = P; |
845 | C.constMethod(); |
846 | D.constMethod(); |
847 | } |
848 | |
849 | template <typename A> |
850 | const A &templatedReference(); |
851 | |
852 | template <typename A, typename B> |
853 | void negativeTemplateTypes() { |
854 | A Orig; |
855 | // Different replaced template type params do not trigger the check. In some |
856 | // template instantiation this might not be a copy but an implicit |
857 | // conversion, so converting this to a reference might not work. |
858 | B AmbiguousCopy = Orig; |
859 | // CHECK-NOT-FIXES: B AmbiguousCopy = Orig; |
860 | |
861 | B NecessaryCopy = templatedReference<A>(); |
862 | // CHECK-NOT-FIXES: B NecessaryCopy = templatedReference<A>(); |
863 | |
864 | B NecessaryCopy2 = Orig.template templatedAccessor<A>(); |
865 | |
866 | // Non-dependent types in template still trigger the check. |
867 | const auto UnnecessaryCopy = ExpensiveTypeReference(); |
868 | // CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'UnnecessaryCopy' is copy-constructed |
869 | // CHECK-FIXES: const auto& UnnecessaryCopy = ExpensiveTypeReference(); |
870 | UnnecessaryCopy.constMethod(); |
871 | } |
872 | |
873 | void instantiateNegativeTemplateTypes() { |
874 | negativeTemplateTypes<ExpensiveToCopyType, ExpensiveToCopyType>(); |
875 | // This template instantiation would not compile if the `AmbiguousCopy` above was made a reference. |
876 | negativeTemplateTypes<ExpensiveToCopyType, int>(); |
877 | } |
878 | |
879 | template <typename A> |
880 | void positiveSingleTemplateType() { |
881 | A Orig; |
882 | A SingleTmplParmTypeCopy = Orig; |
883 | // CHECK-MESSAGES: [[@LINE-1]]:5: warning: local copy 'SingleTmplParmTypeCopy' of the variable 'Orig' is never modified |
884 | // CHECK-FIXES: const A& SingleTmplParmTypeCopy = Orig; |
885 | SingleTmplParmTypeCopy.constMethod(); |
886 | |
887 | A UnnecessaryCopy2 = templatedReference<A>(); |
888 | // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy2' is copy-constructed from a const reference |
889 | // CHECK-FIXES: const A& UnnecessaryCopy2 = templatedReference<A>(); |
890 | UnnecessaryCopy2.constMethod(); |
891 | |
892 | A UnnecessaryCopy3 = Orig.template templatedAccessor<A>(); |
893 | // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the variable 'UnnecessaryCopy3' is copy-constructed from a const reference |
894 | // CHECK-FIXES: const A& UnnecessaryCopy3 = Orig.template templatedAccessor<A>(); |
895 | UnnecessaryCopy3.constMethod(); |
896 | } |
897 | |
898 | void instantiatePositiveSingleTemplateType() { positiveSingleTemplateType<ExpensiveToCopyType>(); } |
899 | |
900 | struct Struct { |
901 | ExpensiveToCopyType Member; |
902 | }; |
903 | |
904 | void positiveConstMemberExpr() { |
905 | Struct Orig; |
906 | auto UC = Orig; |
907 | // CHECK-MESSAGES: [[@LINE-1]]:8: warning: local copy 'UC' |
908 | // CHECK-FIXES: const auto& UC = Orig; |
909 | const auto &ConstRef = UC.Member; |
910 | auto MemberCopy = UC.Member; |
911 | bool b = UC.Member.constMethod(); |
912 | useByValue(UC.Member); |
913 | useAsConstReference(UC.Member); |
914 | useByValue(UC.Member); |
915 | } |
916 | |
917 | void negativeNonConstMemberExpr() { |
918 | Struct Orig; |
919 | { |
920 | auto Copy = Orig; |
921 | Copy.Member.nonConstMethod(); |
922 | } |
923 | { |
924 | auto Copy = Orig; |
925 | mutate(Copy.Member); |
926 | } |
927 | { |
928 | auto Copy = Orig; |
929 | mutate(&Copy.Member); |
930 | } |
931 | } |
932 | |
933 | |
934 | bool operator==(ExpensiveToCopyType, ExpensiveToCopyType); |
935 | |
936 | template<typename T> bool OperatorWithNoDirectCallee(T t) { |
937 | ExpensiveToCopyType a1; |
938 | ExpensiveToCopyType a2 = a1; |
939 | return a1 == t; |
940 | } |
941 | |
942 | |