1 // RUN: %check_clang_tidy %s performance-unnecessary-value-param %t
2
3 // CHECK-FIXES: #include <utility>
4
5 struct ExpensiveToCopyType {
constReferenceExpensiveToCopyType6 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);
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);
positiveExpensiveValue(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
positiveVector(Vector<ExpensiveToCopyType> V)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);
positiveWithComment(const ExpensiveToCopyType S)86 void positiveWithComment(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
positiveUnnamedParam(const ExpensiveToCopyType)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);
positiveAndNegative(const ExpensiveToCopyType ConstCopy,const ExpensiveToCopyType & ConstRef,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 {
PositiveConstValueConstructorPositiveConstValueConstructor105 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
templateWithNonTemplatizedParameter(const ExpensiveToCopyType S,T V)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: template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) {
113 }
114
instantiated()115 void instantiated() {
116 templateWithNonTemplatizedParameter(ExpensiveToCopyType(), ExpensiveToCopyType());
117 templateWithNonTemplatizedParameter(ExpensiveToCopyType(), 5);
118 }
119
negativeTemplateType(const T V)120 template <typename T> void negativeTemplateType(const T V) {
121 }
122
negativeArray(const ExpensiveToCopyType[])123 void negativeArray(const ExpensiveToCopyType[]) {
124 }
125
negativePointer(ExpensiveToCopyType * Obj)126 void negativePointer(ExpensiveToCopyType* Obj) {
127 }
128
negativeConstPointer(const ExpensiveToCopyType * Obj)129 void negativeConstPointer(const ExpensiveToCopyType* Obj) {
130 }
131
negativeConstReference(const ExpensiveToCopyType & Obj)132 void negativeConstReference(const ExpensiveToCopyType& Obj) {
133 }
134
negativeReference(ExpensiveToCopyType & Obj)135 void negativeReference(ExpensiveToCopyType& Obj) {
136 }
137
negativeUniversalReference(ExpensiveToCopyType && Obj)138 void negativeUniversalReference(ExpensiveToCopyType&& Obj) {
139 }
140
negativeSomewhatTrivialConstValue(const SomewhatTrivial Somewhat)141 void negativeSomewhatTrivialConstValue(const SomewhatTrivial Somewhat) {
142 }
143
negativeSomewhatTrivialValue(SomewhatTrivial Somewhat)144 void negativeSomewhatTrivialValue(SomewhatTrivial Somewhat) {
145 }
146
negativeConstBuiltIn(const int I)147 void negativeConstBuiltIn(const int I) {
148 }
149
negativeValueBuiltIn(int I)150 void negativeValueBuiltIn(int I) {
151 }
152
negativeValueIsMutatedByReference(ExpensiveToCopyType Obj)153 void negativeValueIsMutatedByReference(ExpensiveToCopyType Obj) {
154 mutate(Obj);
155 }
156
negativeValueIsMutatatedByPointer(ExpensiveToCopyType Obj)157 void negativeValueIsMutatatedByPointer(ExpensiveToCopyType Obj) {
158 mutate(&Obj);
159 }
160
negativeValueIsReassigned(ExpensiveToCopyType Obj)161 void negativeValueIsReassigned(ExpensiveToCopyType Obj) {
162 Obj = ExpensiveToCopyType();
163 }
164
negativeValueNonConstMethodIsCalled(ExpensiveToCopyType Obj)165 void negativeValueNonConstMethodIsCalled(ExpensiveToCopyType Obj) {
166 Obj.nonConstMethod();
167 }
168
169 struct PositiveValueUnusedConstructor {
PositiveValueUnusedConstructorPositiveValueUnusedConstructor170 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 {
PositiveValueCopiedConstructorPositiveValueCopiedConstructor176 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 {
PositiveValueMovableConstructorPositiveValueMovableConstructor183 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 {
NegativeValueMovedConstructorNegativeValueMovedConstructor190 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
NegativeTypedefParam(const Container<ExpensiveToCopyType>::const_reference Param)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 {
~VirtualMethodVirtualMethod219 virtual ~VirtualMethod() {}
220 virtual void handle(ExpensiveToCopyType T) const = 0;
221 };
222
223 struct NegativeOverriddenMethod : public VirtualMethod {
handleNegativeOverriddenMethod224 void handle(ExpensiveToCopyType Overridden) const {
225 // CHECK-FIXES: handle(ExpensiveToCopyType Overridden) const {
226 }
227 };
228
229 struct VirtualMethodWarningOnly {
methodWithExpensiveValueParamVirtualMethodWarningOnly230 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) {}
~VirtualMethodWarningOnlyVirtualMethodWarningOnly233 virtual ~VirtualMethodWarningOnly() {}
234 };
235
236 struct PositiveNonVirualMethod {
methodPositiveNonVirualMethod237 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 {
~NegativeDeletedMethodNegativeDeletedMethod243 ~NegativeDeletedMethod() {}
244 NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
245 // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
246 };
247
NegativeMoveOnlyTypePassedByValue(MoveOnlyType M)248 void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) {
249 M.constMethod();
250 }
251
PositiveMoveOnCopyConstruction(ExpensiveMovableType E)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
PositiveConstRefNotMoveSinceReferencedMultipleTimes(ExpensiveMovableType E)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
PositiveMoveOnCopyAssignment(ExpensiveMovableType E)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
PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E)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.
PositiveNoMoveInsideLoop(ExpensiveMovableType E)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
PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T)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
PositiveConstRefNotMoveAssignable(ExpensiveToCopyType A)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);
PositiveConstDeclaration(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);
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
PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A)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
ReferenceFunctionOutsideOfCallExpr()326 void ReferenceFunctionOutsideOfCallExpr() {
327 void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit;
328 }
329
PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A)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
ReferenceFunctionByCallingIt()335 void ReferenceFunctionByCallingIt() {
336 PositiveMessageAndFixAsFunctionIsCalled(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> {
MethodNegativeOverrideImpl349 void Method(ExpensiveToCopyType E) override {}
350 };
351
352 template <typename T>
353 struct NegativeFinalImpl : public NegativeDependentTypeInterface<T> {
MethodNegativeFinalImpl354 void Method(ExpensiveToCopyType E) final {}
355 };
356
357 struct PositiveConstructor {
PositiveConstructorPositiveConstructor358 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
fun()369 void fun() {
370 ExpensiveToCopyType E;
371 NegativeUsingConstructor S(E);
372 }
373
374 template<typename T>
templateFunction(T)375 void templateFunction(T) {
376 }
377
378 template<>
templateFunction(ExpensiveToCopyType E)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