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