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