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