1 | // RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -- -fno-delayed-template-parsing |
2 | |
3 | // CHECK-FIXES: #include <utility> |
4 | |
5 | struct ExpensiveToCopyType { |
6 | const ExpensiveToCopyType & constReference() const { |
7 | return *this; |
8 | } |
9 | void nonConstMethod(); |
10 | virtual ~ExpensiveToCopyType(); |
11 | }; |
12 | |
13 | void mutate(ExpensiveToCopyType &); |
14 | void mutate(ExpensiveToCopyType *); |
15 | void useAsConstReference(const ExpensiveToCopyType &); |
16 | void useByValue(ExpensiveToCopyType); |
17 | |
18 | template <class T> class Vector { |
19 | public: |
20 | using iterator = T*; |
21 | using const_iterator = const T*; |
22 | |
23 | Vector(const Vector&); |
24 | Vector& operator=(const Vector&); |
25 | |
26 | iterator begin(); |
27 | iterator end(); |
28 | const_iterator begin() const; |
29 | const_iterator end() const; |
30 | }; |
31 | |
32 | // This class simulates std::pair<>. It is trivially copy constructible |
33 | // and trivially destructible, but not trivially copy assignable. |
34 | class SomewhatTrivial { |
35 | public: |
36 | SomewhatTrivial(); |
37 | SomewhatTrivial(const SomewhatTrivial&) = default; |
38 | ~SomewhatTrivial() = default; |
39 | SomewhatTrivial& operator=(const SomewhatTrivial&); |
40 | }; |
41 | |
42 | struct MoveOnlyType { |
43 | MoveOnlyType(const MoveOnlyType &) = delete; |
44 | MoveOnlyType(MoveOnlyType &&) = default; |
45 | ~MoveOnlyType(); |
46 | void constMethod() const; |
47 | }; |
48 | |
49 | struct ExpensiveMovableType { |
50 | ExpensiveMovableType(); |
51 | ExpensiveMovableType(ExpensiveMovableType &&); |
52 | ExpensiveMovableType(const ExpensiveMovableType &) = default; |
53 | ExpensiveMovableType &operator=(const ExpensiveMovableType &) = default; |
54 | ExpensiveMovableType &operator=(ExpensiveMovableType &&); |
55 | ~ExpensiveMovableType(); |
56 | }; |
57 | |
58 | void positiveExpensiveConstValue(const ExpensiveToCopyType Obj); |
59 | // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj); |
60 | void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) { |
61 | // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'Obj' is copied for each invocation; consider making it a reference [performance-unnecessary-value-param] |
62 | // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj) { |
63 | } |
64 | |
65 | void positiveExpensiveValue(ExpensiveToCopyType Obj); |
66 | // CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj); |
67 | void positiveExpensiveValue(ExpensiveToCopyType Obj) { |
68 | // CHECK-MESSAGES: [[@LINE-1]]:49: warning: the parameter 'Obj' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param] |
69 | // CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj) { |
70 | Obj.constReference(); |
71 | useAsConstReference(Obj); |
72 | auto Copy = Obj; |
73 | useByValue(Obj); |
74 | } |
75 | |
76 | void positiveVector(Vector<ExpensiveToCopyType> V) { |
77 | // CHECK-MESSAGES: [[@LINE-1]]:49: warning: the parameter 'V' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param] |
78 | // CHECK-FIXES: void positiveVector(const Vector<ExpensiveToCopyType>& V) { |
79 | for (const auto& Obj : V) { |
80 | useByValue(Obj); |
81 | } |
82 | } |
83 | |
84 | void positiveWithComment(const ExpensiveToCopyType /* important */ S); |
85 | // CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S); |
86 | void (const ExpensiveToCopyType /* important */ S) { |
87 | // CHECK-MESSAGES: [[@LINE-1]]:68: warning: the const qualified |
88 | // CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S) { |
89 | } |
90 | |
91 | void positiveUnnamedParam(const ExpensiveToCopyType) { |
92 | // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter #1 |
93 | // CHECK-FIXES: void positiveUnnamedParam(const ExpensiveToCopyType&) { |
94 | } |
95 | |
96 | void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy); |
97 | // CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy); |
98 | void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy) { |
99 | // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter 'ConstCopy' |
100 | // CHECK-MESSAGES: [[@LINE-2]]:120: warning: the parameter 'Copy' |
101 | // CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy) { |
102 | } |
103 | |
104 | struct PositiveConstValueConstructor { |
105 | PositiveConstValueConstructor(const ExpensiveToCopyType ConstCopy) {} |
106 | // CHECK-MESSAGES: [[@LINE-1]]:59: warning: the const qualified parameter 'ConstCopy' |
107 | // CHECK-FIXES: PositiveConstValueConstructor(const ExpensiveToCopyType& ConstCopy) {} |
108 | }; |
109 | |
110 | template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) { |
111 | // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S' |
112 | // CHECK-FIXES-NOT: template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) { |
113 | } |
114 | |
115 | void instantiated() { |
116 | templateWithNonTemplatizedParameter(S: ExpensiveToCopyType(), V: ExpensiveToCopyType()); |
117 | templateWithNonTemplatizedParameter(S: ExpensiveToCopyType(), V: 5); |
118 | } |
119 | |
120 | template <typename T> void negativeTemplateType(const T V) { |
121 | } |
122 | |
123 | void negativeArray(const ExpensiveToCopyType[]) { |
124 | } |
125 | |
126 | void negativePointer(ExpensiveToCopyType* Obj) { |
127 | } |
128 | |
129 | void negativeConstPointer(const ExpensiveToCopyType* Obj) { |
130 | } |
131 | |
132 | void negativeConstReference(const ExpensiveToCopyType& Obj) { |
133 | } |
134 | |
135 | void negativeReference(ExpensiveToCopyType& Obj) { |
136 | } |
137 | |
138 | void negativeUniversalReference(ExpensiveToCopyType&& Obj) { |
139 | } |
140 | |
141 | void negativeSomewhatTrivialConstValue(const SomewhatTrivial Somewhat) { |
142 | } |
143 | |
144 | void negativeSomewhatTrivialValue(SomewhatTrivial Somewhat) { |
145 | } |
146 | |
147 | void negativeConstBuiltIn(const int I) { |
148 | } |
149 | |
150 | void negativeValueBuiltIn(int I) { |
151 | } |
152 | |
153 | void negativeValueIsMutatedByReference(ExpensiveToCopyType Obj) { |
154 | mutate(Obj); |
155 | } |
156 | |
157 | void negativeValueIsMutatatedByPointer(ExpensiveToCopyType Obj) { |
158 | mutate(&Obj); |
159 | } |
160 | |
161 | void negativeValueIsReassigned(ExpensiveToCopyType Obj) { |
162 | Obj = ExpensiveToCopyType(); |
163 | } |
164 | |
165 | void negativeValueNonConstMethodIsCalled(ExpensiveToCopyType Obj) { |
166 | Obj.nonConstMethod(); |
167 | } |
168 | |
169 | struct PositiveValueUnusedConstructor { |
170 | PositiveValueUnusedConstructor(ExpensiveToCopyType Copy) {} |
171 | // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy' |
172 | // CHECK-FIXES: PositiveValueUnusedConstructor(const ExpensiveToCopyType& Copy) {} |
173 | }; |
174 | |
175 | struct PositiveValueCopiedConstructor { |
176 | PositiveValueCopiedConstructor(ExpensiveToCopyType Copy) : Field(Copy) {} |
177 | // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy' |
178 | // CHECK-FIXES: PositiveValueCopiedConstructor(const ExpensiveToCopyType& Copy) : Field(Copy) {} |
179 | ExpensiveToCopyType Field; |
180 | }; |
181 | |
182 | struct PositiveValueMovableConstructor { |
183 | PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(Copy) {} |
184 | // CHECK-MESSAGES: [[@LINE-1]]:70: warning: parameter 'Copy' |
185 | // CHECK-FIXES: PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(std::move(Copy)) {} |
186 | ExpensiveMovableType Field; |
187 | }; |
188 | |
189 | struct NegativeValueMovedConstructor { |
190 | NegativeValueMovedConstructor(ExpensiveMovableType Copy) : Field(static_cast<ExpensiveMovableType &&>(Copy)) {} |
191 | ExpensiveMovableType Field; |
192 | }; |
193 | |
194 | template <typename T> |
195 | struct Container { |
196 | typedef const T & const_reference; |
197 | }; |
198 | |
199 | void NegativeTypedefParam(const Container<ExpensiveToCopyType>::const_reference Param) { |
200 | } |
201 | |
202 | #define UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY() \ |
203 | void inMacro(const ExpensiveToCopyType T) { \ |
204 | } \ |
205 | // Ensure fix is not applied. |
206 | // CHECK-FIXES: void inMacro(const ExpensiveToCopyType T) { |
207 | |
208 | UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY() |
209 | // CHECK-MESSAGES: [[@LINE-1]]:1: warning: the const qualified parameter 'T' |
210 | |
211 | #define UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(ARGUMENT) \ |
212 | ARGUMENT |
213 | |
214 | UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(void inMacroArgument(const ExpensiveToCopyType InMacroArg) {}) |
215 | // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'InMacroArg' |
216 | // CHECK-FIXES: void inMacroArgument(const ExpensiveToCopyType InMacroArg) {} |
217 | |
218 | struct VirtualMethod { |
219 | virtual ~VirtualMethod() {} |
220 | virtual void handle(ExpensiveToCopyType T) const = 0; |
221 | }; |
222 | |
223 | struct NegativeOverriddenMethod : public VirtualMethod { |
224 | void handle(ExpensiveToCopyType Overridden) const { |
225 | // CHECK-FIXES: handle(ExpensiveToCopyType Overridden) const { |
226 | } |
227 | }; |
228 | |
229 | struct VirtualMethodWarningOnly { |
230 | virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {} |
231 | // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'T' is copied |
232 | // CHECK-FIXES: virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {} |
233 | virtual ~VirtualMethodWarningOnly() {} |
234 | }; |
235 | |
236 | struct PositiveNonVirualMethod { |
237 | void method(const ExpensiveToCopyType T) {} |
238 | // CHECK-MESSAGES: [[@LINE-1]]:41: warning: the const qualified parameter 'T' is copied |
239 | // CHECK-FIXES: void method(const ExpensiveToCopyType& T) {} |
240 | }; |
241 | |
242 | struct NegativeDeletedMethod { |
243 | ~NegativeDeletedMethod() {} |
244 | NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; |
245 | // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete; |
246 | }; |
247 | |
248 | void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) { |
249 | M.constMethod(); |
250 | } |
251 | |
252 | void PositiveMoveOnCopyConstruction(ExpensiveMovableType E) { |
253 | auto F = E; |
254 | // CHECK-MESSAGES: [[@LINE-1]]:12: warning: parameter 'E' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param] |
255 | // CHECK-FIXES: auto F = std::move(E); |
256 | } |
257 | |
258 | void PositiveConstRefNotMoveSinceReferencedMultipleTimes(ExpensiveMovableType E) { |
259 | // CHECK-MESSAGES: [[@LINE-1]]:79: warning: the parameter 'E' is copied |
260 | // CHECK-FIXES: void PositiveConstRefNotMoveSinceReferencedMultipleTimes(const ExpensiveMovableType& E) { |
261 | auto F = E; |
262 | auto G = E; |
263 | } |
264 | |
265 | void PositiveMoveOnCopyAssignment(ExpensiveMovableType E) { |
266 | ExpensiveMovableType F; |
267 | F = E; |
268 | // CHECK-MESSAGES: [[@LINE-1]]:7: warning: parameter 'E' is passed by value |
269 | // CHECK-FIXES: F = std::move(E); |
270 | } |
271 | |
272 | struct NotCopyAssigned { |
273 | NotCopyAssigned &operator=(const ExpensiveMovableType &); |
274 | }; |
275 | |
276 | void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) { |
277 | // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied |
278 | // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const ExpensiveMovableType& E) { |
279 | NotCopyAssigned N; |
280 | N = E; |
281 | } |
282 | |
283 | // The argument could be moved but is not since copy statement is inside a loop. |
284 | void PositiveNoMoveInsideLoop(ExpensiveMovableType E) { |
285 | // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied |
286 | // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) { |
287 | for (;;) { |
288 | auto F = E; |
289 | } |
290 | } |
291 | |
292 | void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) { |
293 | // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied |
294 | // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const ExpensiveToCopyType& T) { |
295 | auto U = T; |
296 | } |
297 | |
298 | void PositiveConstRefNotMoveAssignable(ExpensiveToCopyType A) { |
299 | // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the parameter 'A' is copied |
300 | // CHECK-FIXES: void PositiveConstRefNotMoveAssignable(const ExpensiveToCopyType& A) { |
301 | ExpensiveToCopyType B; |
302 | B = A; |
303 | } |
304 | |
305 | // Case where parameter in declaration is already const-qualified but not in |
306 | // implementation. Make sure a second 'const' is not added to the declaration. |
307 | void PositiveConstDeclaration(const ExpensiveToCopyType A); |
308 | // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A); |
309 | void PositiveConstDeclaration(ExpensiveToCopyType A) { |
310 | // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied |
311 | // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) { |
312 | } |
313 | |
314 | void PositiveNonConstDeclaration(ExpensiveToCopyType A); |
315 | // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A); |
316 | void PositiveNonConstDeclaration(const ExpensiveToCopyType A) { |
317 | // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A' |
318 | // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) { |
319 | } |
320 | |
321 | void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { |
322 | // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied |
323 | // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) { |
324 | } |
325 | |
326 | void ReferenceFunctionOutsideOfCallExpr() { |
327 | void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit; |
328 | } |
329 | |
330 | void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) { |
331 | // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied |
332 | // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) { |
333 | } |
334 | |
335 | void ReferenceFunctionByCallingIt() { |
336 | PositiveMessageAndFixAsFunctionIsCalled(A: ExpensiveToCopyType()); |
337 | } |
338 | |
339 | // Virtual method overrides of dependent types cannot be recognized unless they |
340 | // are marked as override or final. Test that check is not triggered on methods |
341 | // marked with override or final. |
342 | template <typename T> |
343 | struct NegativeDependentTypeInterface { |
344 | virtual void Method(ExpensiveToCopyType E) = 0; |
345 | }; |
346 | |
347 | template <typename T> |
348 | struct NegativeOverrideImpl : public NegativeDependentTypeInterface<T> { |
349 | void Method(ExpensiveToCopyType E) override {} |
350 | }; |
351 | |
352 | template <typename T> |
353 | struct NegativeFinalImpl : public NegativeDependentTypeInterface<T> { |
354 | void Method(ExpensiveToCopyType E) final {} |
355 | }; |
356 | |
357 | struct PositiveConstructor { |
358 | PositiveConstructor(ExpensiveToCopyType E) : E(E) {} |
359 | // CHECK-MESSAGES: [[@LINE-1]]:43: warning: the parameter 'E' is copied |
360 | // CHECK-FIXES: PositiveConstructor(const ExpensiveToCopyType& E) : E(E) {} |
361 | |
362 | ExpensiveToCopyType E; |
363 | }; |
364 | |
365 | struct NegativeUsingConstructor : public PositiveConstructor { |
366 | using PositiveConstructor::PositiveConstructor; |
367 | }; |
368 | |
369 | void fun() { |
370 | ExpensiveToCopyType E; |
371 | NegativeUsingConstructor S(E); |
372 | } |
373 | |
374 | template<typename T> |
375 | void templateFunction(T) { |
376 | } |
377 | |
378 | template<> |
379 | void templateFunction<ExpensiveToCopyType>(ExpensiveToCopyType E) { |
380 | // CHECK-MESSAGES: [[@LINE-1]]:64: warning: the parameter 'E' is copied |
381 | // CHECK-FIXES: void templateFunction<ExpensiveToCopyType>(ExpensiveToCopyType E) { |
382 | E.constReference(); |
383 | } |
384 | |
385 | template <class T> |
386 | T templateSpecializationFunction(ExpensiveToCopyType E) { |
387 | // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'E' is copied |
388 | // CHECK-FIXES-NOT: T templateSpecializationFunction(const ExpensiveToCopyType& E) { |
389 | return T(); |
390 | } |
391 | |
392 | template <> |
393 | bool templateSpecializationFunction(ExpensiveToCopyType E) { |
394 | // CHECK-MESSAGES: [[@LINE-1]]:57: warning: the parameter 'E' is copied |
395 | // CHECK-FIXES-NOT: bool templateSpecializationFunction(const ExpensiveToCopyType& E) { |
396 | return true; |
397 | } |
398 | |
399 | template <> |
400 | int templateSpecializationFunction(ExpensiveToCopyType E) { |
401 | // CHECK-MESSAGES: [[@LINE-1]]:56: warning: the parameter 'E' is copied |
402 | // CHECK-FIXES-NOT: int templateSpecializationFunction(const ExpensiveToCopyType& E) { |
403 | return 0; |
404 | } |
405 | |