xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp (revision 1ce89899ad33a0d2976859d8d278dba4342cbb6b)
1 // RUN: %check_clang_tidy %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(ExpensiveToCopyType A) {
336 }
337 
338 void ReferenceFunctionOutsideOfCallExpr() {
339   void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit;
340 }
341 
342 void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) {
343   // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied
344   // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) {
345 }
346 
347 void ReferenceFunctionByCallingIt() {
348   PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType());
349 }
350 
351 // Virtual method overrides of dependent types cannot be recognized unless they
352 // are marked as override or final. Test that check is not triggered on methods
353 // marked with override or final.
354 template <typename T>
355 struct NegativeDependentTypeInterface {
356   virtual void Method(ExpensiveToCopyType E) = 0;
357 };
358 
359 template <typename T>
360 struct NegativeOverrideImpl : public NegativeDependentTypeInterface<T> {
361   void Method(ExpensiveToCopyType E) override {}
362 };
363 
364 template <typename T>
365 struct NegativeFinalImpl : public NegativeDependentTypeInterface<T> {
366   void Method(ExpensiveToCopyType E) final {}
367 };
368 
369 struct PositiveConstructor {
370   PositiveConstructor(ExpensiveToCopyType E) : E(E) {}
371   // CHECK-MESSAGES: [[@LINE-1]]:43: warning: the parameter 'E' is copied
372   // CHECK-FIXES: PositiveConstructor(const ExpensiveToCopyType& E) : E(E) {}
373 
374   ExpensiveToCopyType E;
375 };
376 
377 struct NegativeUsingConstructor : public PositiveConstructor {
378   using PositiveConstructor::PositiveConstructor;
379 };
380 
381 void fun() {
382   ExpensiveToCopyType E;
383   NegativeUsingConstructor S(E);
384 }
385 
386 struct B {
387   static void bar(ExpensiveMovableType a, ExpensiveMovableType b);
388 };
389 
390 template <typename T>
391 void NegativeCallWithDependentAndNondependentArgs(ExpensiveMovableType a, T b) {
392     B::bar(std::move(a), b);
393 }
394