xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp (revision 1ce89899ad33a0d2976859d8d278dba4342cbb6b)
189a1d03eSRichard // RUN: %check_clang_tidy %s performance-unnecessary-value-param %t -- -- -fno-delayed-template-parsing
289a1d03eSRichard 
389a1d03eSRichard // CHECK-FIXES: #include <utility>
489a1d03eSRichard 
5*1ce89899SDmitry Polukhin namespace std {
6*1ce89899SDmitry Polukhin template <typename>
7*1ce89899SDmitry Polukhin struct remove_reference;
8*1ce89899SDmitry Polukhin 
9*1ce89899SDmitry Polukhin template <typename _Tp>
10*1ce89899SDmitry Polukhin struct remove_reference {
11*1ce89899SDmitry Polukhin   typedef _Tp type;
12*1ce89899SDmitry Polukhin };
13*1ce89899SDmitry Polukhin 
14*1ce89899SDmitry Polukhin template <typename _Tp>
15*1ce89899SDmitry Polukhin struct remove_reference<_Tp &> {
16*1ce89899SDmitry Polukhin   typedef _Tp type;
17*1ce89899SDmitry Polukhin };
18*1ce89899SDmitry Polukhin 
19*1ce89899SDmitry Polukhin template <typename _Tp>
20*1ce89899SDmitry Polukhin struct remove_reference<_Tp &&> {
21*1ce89899SDmitry Polukhin   typedef _Tp type;
22*1ce89899SDmitry Polukhin };
23*1ce89899SDmitry Polukhin 
24*1ce89899SDmitry Polukhin template <typename _Tp>
25*1ce89899SDmitry Polukhin constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
26*1ce89899SDmitry Polukhin   return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
27*1ce89899SDmitry Polukhin }
28*1ce89899SDmitry Polukhin } // namespace std
29*1ce89899SDmitry Polukhin 
3089a1d03eSRichard struct ExpensiveToCopyType {
3189a1d03eSRichard   const ExpensiveToCopyType & constReference() const {
3289a1d03eSRichard     return *this;
3389a1d03eSRichard   }
3489a1d03eSRichard   void nonConstMethod();
3589a1d03eSRichard   virtual ~ExpensiveToCopyType();
3689a1d03eSRichard };
3789a1d03eSRichard 
3889a1d03eSRichard void mutate(ExpensiveToCopyType &);
3989a1d03eSRichard void mutate(ExpensiveToCopyType *);
4089a1d03eSRichard void useAsConstReference(const ExpensiveToCopyType &);
4189a1d03eSRichard void useByValue(ExpensiveToCopyType);
4289a1d03eSRichard 
4389a1d03eSRichard template <class T> class Vector {
4489a1d03eSRichard  public:
4589a1d03eSRichard   using iterator = T*;
4689a1d03eSRichard   using const_iterator = const T*;
4789a1d03eSRichard 
4889a1d03eSRichard   Vector(const Vector&);
4989a1d03eSRichard   Vector& operator=(const Vector&);
5089a1d03eSRichard 
5189a1d03eSRichard   iterator begin();
5289a1d03eSRichard   iterator end();
5389a1d03eSRichard   const_iterator begin() const;
5489a1d03eSRichard   const_iterator end() const;
5589a1d03eSRichard };
5689a1d03eSRichard 
5789a1d03eSRichard // This class simulates std::pair<>. It is trivially copy constructible
5889a1d03eSRichard // and trivially destructible, but not trivially copy assignable.
5989a1d03eSRichard class SomewhatTrivial {
6089a1d03eSRichard  public:
6189a1d03eSRichard   SomewhatTrivial();
6289a1d03eSRichard   SomewhatTrivial(const SomewhatTrivial&) = default;
6389a1d03eSRichard   ~SomewhatTrivial() = default;
6489a1d03eSRichard   SomewhatTrivial& operator=(const SomewhatTrivial&);
6589a1d03eSRichard };
6689a1d03eSRichard 
6789a1d03eSRichard struct MoveOnlyType {
6889a1d03eSRichard   MoveOnlyType(const MoveOnlyType &) = delete;
6989a1d03eSRichard   MoveOnlyType(MoveOnlyType &&) = default;
7089a1d03eSRichard   ~MoveOnlyType();
7189a1d03eSRichard   void constMethod() const;
7289a1d03eSRichard };
7389a1d03eSRichard 
7489a1d03eSRichard struct ExpensiveMovableType {
7589a1d03eSRichard   ExpensiveMovableType();
7689a1d03eSRichard   ExpensiveMovableType(ExpensiveMovableType &&);
7789a1d03eSRichard   ExpensiveMovableType(const ExpensiveMovableType &) = default;
7889a1d03eSRichard   ExpensiveMovableType &operator=(const ExpensiveMovableType &) = default;
7989a1d03eSRichard   ExpensiveMovableType &operator=(ExpensiveMovableType &&);
8089a1d03eSRichard   ~ExpensiveMovableType();
8189a1d03eSRichard };
8289a1d03eSRichard 
8389a1d03eSRichard void positiveExpensiveConstValue(const ExpensiveToCopyType Obj);
8489a1d03eSRichard // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj);
8589a1d03eSRichard void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) {
8689a1d03eSRichard   // 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]
8789a1d03eSRichard   // CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj) {
8889a1d03eSRichard }
8989a1d03eSRichard 
9089a1d03eSRichard void positiveExpensiveValue(ExpensiveToCopyType Obj);
9189a1d03eSRichard // CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj);
9289a1d03eSRichard void positiveExpensiveValue(ExpensiveToCopyType Obj) {
9389a1d03eSRichard   // 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]
9489a1d03eSRichard   // CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj) {
9589a1d03eSRichard   Obj.constReference();
9689a1d03eSRichard   useAsConstReference(Obj);
9789a1d03eSRichard   auto Copy = Obj;
9889a1d03eSRichard   useByValue(Obj);
9989a1d03eSRichard }
10089a1d03eSRichard 
10189a1d03eSRichard void positiveVector(Vector<ExpensiveToCopyType> V) {
10289a1d03eSRichard   // 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]
10389a1d03eSRichard   // CHECK-FIXES: void positiveVector(const Vector<ExpensiveToCopyType>& V) {
10489a1d03eSRichard   for (const auto& Obj : V) {
10589a1d03eSRichard     useByValue(Obj);
10689a1d03eSRichard   }
10789a1d03eSRichard }
10889a1d03eSRichard 
10989a1d03eSRichard void positiveWithComment(const ExpensiveToCopyType /* important */ S);
11089a1d03eSRichard // CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S);
11189a1d03eSRichard void positiveWithComment(const ExpensiveToCopyType /* important */ S) {
11289a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:68: warning: the const qualified
11389a1d03eSRichard   // CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S) {
11489a1d03eSRichard }
11589a1d03eSRichard 
11689a1d03eSRichard void positiveUnnamedParam(const ExpensiveToCopyType) {
11789a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter #1
11889a1d03eSRichard   // CHECK-FIXES: void positiveUnnamedParam(const ExpensiveToCopyType&) {
11989a1d03eSRichard }
12089a1d03eSRichard 
12189a1d03eSRichard void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy);
12289a1d03eSRichard // CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy);
12389a1d03eSRichard void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy) {
12489a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter 'ConstCopy'
12589a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-2]]:120: warning: the parameter 'Copy'
12689a1d03eSRichard   // CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy) {
12789a1d03eSRichard }
12889a1d03eSRichard 
12989a1d03eSRichard struct PositiveConstValueConstructor {
13089a1d03eSRichard   PositiveConstValueConstructor(const ExpensiveToCopyType ConstCopy) {}
13189a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:59: warning: the const qualified parameter 'ConstCopy'
13289a1d03eSRichard   // CHECK-FIXES: PositiveConstValueConstructor(const ExpensiveToCopyType& ConstCopy) {}
13389a1d03eSRichard };
13489a1d03eSRichard 
13589a1d03eSRichard void negativeArray(const ExpensiveToCopyType[]) {
13689a1d03eSRichard }
13789a1d03eSRichard 
13889a1d03eSRichard void negativePointer(ExpensiveToCopyType* Obj) {
13989a1d03eSRichard }
14089a1d03eSRichard 
14189a1d03eSRichard void negativeConstPointer(const ExpensiveToCopyType* Obj) {
14289a1d03eSRichard }
14389a1d03eSRichard 
14489a1d03eSRichard void negativeConstReference(const ExpensiveToCopyType& Obj) {
14589a1d03eSRichard }
14689a1d03eSRichard 
14789a1d03eSRichard void negativeReference(ExpensiveToCopyType& Obj) {
14889a1d03eSRichard }
14989a1d03eSRichard 
15089a1d03eSRichard void negativeUniversalReference(ExpensiveToCopyType&& Obj) {
15189a1d03eSRichard }
15289a1d03eSRichard 
15389a1d03eSRichard void negativeSomewhatTrivialConstValue(const SomewhatTrivial Somewhat) {
15489a1d03eSRichard }
15589a1d03eSRichard 
15689a1d03eSRichard void negativeSomewhatTrivialValue(SomewhatTrivial Somewhat) {
15789a1d03eSRichard }
15889a1d03eSRichard 
15989a1d03eSRichard void negativeConstBuiltIn(const int I) {
16089a1d03eSRichard }
16189a1d03eSRichard 
16289a1d03eSRichard void negativeValueBuiltIn(int I) {
16389a1d03eSRichard }
16489a1d03eSRichard 
16589a1d03eSRichard void negativeValueIsMutatedByReference(ExpensiveToCopyType Obj) {
16689a1d03eSRichard   mutate(Obj);
16789a1d03eSRichard }
16889a1d03eSRichard 
16989a1d03eSRichard void negativeValueIsMutatatedByPointer(ExpensiveToCopyType Obj) {
17089a1d03eSRichard   mutate(&Obj);
17189a1d03eSRichard }
17289a1d03eSRichard 
17389a1d03eSRichard void negativeValueIsReassigned(ExpensiveToCopyType Obj) {
17489a1d03eSRichard   Obj = ExpensiveToCopyType();
17589a1d03eSRichard }
17689a1d03eSRichard 
17789a1d03eSRichard void negativeValueNonConstMethodIsCalled(ExpensiveToCopyType Obj) {
17889a1d03eSRichard   Obj.nonConstMethod();
17989a1d03eSRichard }
18089a1d03eSRichard 
18189a1d03eSRichard struct PositiveValueUnusedConstructor {
18289a1d03eSRichard   PositiveValueUnusedConstructor(ExpensiveToCopyType Copy) {}
18389a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
18489a1d03eSRichard   // CHECK-FIXES: PositiveValueUnusedConstructor(const ExpensiveToCopyType& Copy) {}
18589a1d03eSRichard };
18689a1d03eSRichard 
18789a1d03eSRichard struct PositiveValueCopiedConstructor {
18889a1d03eSRichard   PositiveValueCopiedConstructor(ExpensiveToCopyType Copy) : Field(Copy) {}
18989a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
19089a1d03eSRichard   // CHECK-FIXES: PositiveValueCopiedConstructor(const ExpensiveToCopyType& Copy) : Field(Copy) {}
19189a1d03eSRichard   ExpensiveToCopyType Field;
19289a1d03eSRichard };
19389a1d03eSRichard 
19489a1d03eSRichard struct PositiveValueMovableConstructor {
19589a1d03eSRichard   PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(Copy) {}
19689a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:70: warning: parameter 'Copy'
19789a1d03eSRichard   // CHECK-FIXES: PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(std::move(Copy)) {}
19889a1d03eSRichard   ExpensiveMovableType Field;
19989a1d03eSRichard };
20089a1d03eSRichard 
20189a1d03eSRichard struct NegativeValueMovedConstructor {
20289a1d03eSRichard   NegativeValueMovedConstructor(ExpensiveMovableType Copy) : Field(static_cast<ExpensiveMovableType &&>(Copy)) {}
20389a1d03eSRichard   ExpensiveMovableType Field;
20489a1d03eSRichard };
20589a1d03eSRichard 
20689a1d03eSRichard template <typename T>
20789a1d03eSRichard struct Container {
20889a1d03eSRichard   typedef const T & const_reference;
20989a1d03eSRichard };
21089a1d03eSRichard 
21189a1d03eSRichard void NegativeTypedefParam(const Container<ExpensiveToCopyType>::const_reference Param) {
21289a1d03eSRichard }
21389a1d03eSRichard 
21489a1d03eSRichard #define UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY()         \
21589a1d03eSRichard   void inMacro(const ExpensiveToCopyType T) {           \
21689a1d03eSRichard   }                                                     \
21789a1d03eSRichard // Ensure fix is not applied.
21889a1d03eSRichard // CHECK-FIXES: void inMacro(const ExpensiveToCopyType T) {
21989a1d03eSRichard 
22089a1d03eSRichard UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY()
22189a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:1: warning: the const qualified parameter 'T'
22289a1d03eSRichard 
22389a1d03eSRichard #define UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(ARGUMENT)     \
22489a1d03eSRichard   ARGUMENT
22589a1d03eSRichard 
22689a1d03eSRichard UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(void inMacroArgument(const ExpensiveToCopyType InMacroArg) {})
22789a1d03eSRichard // CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'InMacroArg'
22889a1d03eSRichard // CHECK-FIXES: void inMacroArgument(const ExpensiveToCopyType InMacroArg) {}
22989a1d03eSRichard 
23089a1d03eSRichard struct VirtualMethod {
23189a1d03eSRichard   virtual ~VirtualMethod() {}
23289a1d03eSRichard   virtual void handle(ExpensiveToCopyType T) const = 0;
23389a1d03eSRichard };
23489a1d03eSRichard 
23589a1d03eSRichard struct NegativeOverriddenMethod : public VirtualMethod {
23689a1d03eSRichard   void handle(ExpensiveToCopyType Overridden) const {
23789a1d03eSRichard     // CHECK-FIXES: handle(ExpensiveToCopyType Overridden) const {
23889a1d03eSRichard   }
23989a1d03eSRichard };
24089a1d03eSRichard 
24189a1d03eSRichard struct VirtualMethodWarningOnly {
24289a1d03eSRichard   virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {}
24389a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'T' is copied
24489a1d03eSRichard   // CHECK-FIXES: virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {}
24589a1d03eSRichard   virtual ~VirtualMethodWarningOnly() {}
24689a1d03eSRichard };
24789a1d03eSRichard 
24889a1d03eSRichard struct PositiveNonVirualMethod {
24989a1d03eSRichard   void method(const ExpensiveToCopyType T) {}
25089a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:41: warning: the const qualified parameter 'T' is copied
25189a1d03eSRichard   // CHECK-FIXES: void method(const ExpensiveToCopyType& T) {}
25289a1d03eSRichard };
25389a1d03eSRichard 
25489a1d03eSRichard struct NegativeDeletedMethod {
25589a1d03eSRichard   ~NegativeDeletedMethod() {}
25689a1d03eSRichard   NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
25789a1d03eSRichard   // CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
25889a1d03eSRichard };
25989a1d03eSRichard 
26089a1d03eSRichard void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) {
26189a1d03eSRichard   M.constMethod();
26289a1d03eSRichard }
26389a1d03eSRichard 
26489a1d03eSRichard void PositiveMoveOnCopyConstruction(ExpensiveMovableType E) {
26589a1d03eSRichard   auto F = E;
26689a1d03eSRichard   // 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]
26789a1d03eSRichard   // CHECK-FIXES: auto F = std::move(E);
26889a1d03eSRichard }
26989a1d03eSRichard 
27089a1d03eSRichard void PositiveConstRefNotMoveSinceReferencedMultipleTimes(ExpensiveMovableType E) {
27189a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:79: warning: the parameter 'E' is copied
27289a1d03eSRichard   // CHECK-FIXES: void PositiveConstRefNotMoveSinceReferencedMultipleTimes(const ExpensiveMovableType& E) {
27389a1d03eSRichard   auto F = E;
27489a1d03eSRichard   auto G = E;
27589a1d03eSRichard }
27689a1d03eSRichard 
27789a1d03eSRichard void PositiveMoveOnCopyAssignment(ExpensiveMovableType E) {
27889a1d03eSRichard   ExpensiveMovableType F;
27989a1d03eSRichard   F = E;
28089a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:7: warning: parameter 'E' is passed by value
28189a1d03eSRichard   // CHECK-FIXES: F = std::move(E);
28289a1d03eSRichard }
28389a1d03eSRichard 
28489a1d03eSRichard struct NotCopyAssigned {
28589a1d03eSRichard   NotCopyAssigned &operator=(const ExpensiveMovableType &);
28689a1d03eSRichard };
28789a1d03eSRichard 
28889a1d03eSRichard void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) {
28989a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied
29089a1d03eSRichard   // CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const ExpensiveMovableType& E) {
29189a1d03eSRichard   NotCopyAssigned N;
29289a1d03eSRichard   N = E;
29389a1d03eSRichard }
29489a1d03eSRichard 
29589a1d03eSRichard // The argument could be moved but is not since copy statement is inside a loop.
29689a1d03eSRichard void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
29789a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
29889a1d03eSRichard   // CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) {
29989a1d03eSRichard   for (;;) {
30089a1d03eSRichard     auto F = E;
30189a1d03eSRichard   }
30289a1d03eSRichard }
30389a1d03eSRichard 
30489a1d03eSRichard void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) {
30589a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied
30689a1d03eSRichard   // CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const ExpensiveToCopyType& T) {
30789a1d03eSRichard   auto U = T;
30889a1d03eSRichard }
30989a1d03eSRichard 
31089a1d03eSRichard void PositiveConstRefNotMoveAssignable(ExpensiveToCopyType A) {
31189a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the parameter 'A' is copied
31289a1d03eSRichard   // CHECK-FIXES: void PositiveConstRefNotMoveAssignable(const ExpensiveToCopyType& A) {
31389a1d03eSRichard   ExpensiveToCopyType B;
31489a1d03eSRichard   B = A;
31589a1d03eSRichard }
31689a1d03eSRichard 
31789a1d03eSRichard // Case where parameter in declaration is already const-qualified but not in
31889a1d03eSRichard // implementation. Make sure a second 'const' is not added to the declaration.
31989a1d03eSRichard void PositiveConstDeclaration(const ExpensiveToCopyType A);
32089a1d03eSRichard // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A);
32189a1d03eSRichard void PositiveConstDeclaration(ExpensiveToCopyType A) {
32289a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied
32389a1d03eSRichard   // CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) {
32489a1d03eSRichard }
32589a1d03eSRichard 
32689a1d03eSRichard void PositiveNonConstDeclaration(ExpensiveToCopyType A);
32789a1d03eSRichard // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A);
32889a1d03eSRichard void PositiveNonConstDeclaration(const ExpensiveToCopyType A) {
32989a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A'
33089a1d03eSRichard   // CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) {
33189a1d03eSRichard }
33289a1d03eSRichard 
33389a1d03eSRichard void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) {
33489a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied
33589a1d03eSRichard   // CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) {
33689a1d03eSRichard }
33789a1d03eSRichard 
33889a1d03eSRichard void ReferenceFunctionOutsideOfCallExpr() {
33989a1d03eSRichard   void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit;
34089a1d03eSRichard }
34189a1d03eSRichard 
34289a1d03eSRichard void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) {
34389a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied
34489a1d03eSRichard   // CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) {
34589a1d03eSRichard }
34689a1d03eSRichard 
34789a1d03eSRichard void ReferenceFunctionByCallingIt() {
34889a1d03eSRichard   PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType());
34989a1d03eSRichard }
35089a1d03eSRichard 
35189a1d03eSRichard // Virtual method overrides of dependent types cannot be recognized unless they
35289a1d03eSRichard // are marked as override or final. Test that check is not triggered on methods
35389a1d03eSRichard // marked with override or final.
35489a1d03eSRichard template <typename T>
35589a1d03eSRichard struct NegativeDependentTypeInterface {
35689a1d03eSRichard   virtual void Method(ExpensiveToCopyType E) = 0;
35789a1d03eSRichard };
35889a1d03eSRichard 
35989a1d03eSRichard template <typename T>
36089a1d03eSRichard struct NegativeOverrideImpl : public NegativeDependentTypeInterface<T> {
36189a1d03eSRichard   void Method(ExpensiveToCopyType E) override {}
36289a1d03eSRichard };
36389a1d03eSRichard 
36489a1d03eSRichard template <typename T>
36589a1d03eSRichard struct NegativeFinalImpl : public NegativeDependentTypeInterface<T> {
36689a1d03eSRichard   void Method(ExpensiveToCopyType E) final {}
36789a1d03eSRichard };
36889a1d03eSRichard 
36989a1d03eSRichard struct PositiveConstructor {
37089a1d03eSRichard   PositiveConstructor(ExpensiveToCopyType E) : E(E) {}
37189a1d03eSRichard   // CHECK-MESSAGES: [[@LINE-1]]:43: warning: the parameter 'E' is copied
37289a1d03eSRichard   // CHECK-FIXES: PositiveConstructor(const ExpensiveToCopyType& E) : E(E) {}
37389a1d03eSRichard 
37489a1d03eSRichard   ExpensiveToCopyType E;
37589a1d03eSRichard };
37689a1d03eSRichard 
37789a1d03eSRichard struct NegativeUsingConstructor : public PositiveConstructor {
37889a1d03eSRichard   using PositiveConstructor::PositiveConstructor;
37989a1d03eSRichard };
38089a1d03eSRichard 
38189a1d03eSRichard void fun() {
38289a1d03eSRichard   ExpensiveToCopyType E;
38389a1d03eSRichard   NegativeUsingConstructor S(E);
38489a1d03eSRichard }
385*1ce89899SDmitry Polukhin 
386*1ce89899SDmitry Polukhin struct B {
387*1ce89899SDmitry Polukhin   static void bar(ExpensiveMovableType a, ExpensiveMovableType b);
388*1ce89899SDmitry Polukhin };
389*1ce89899SDmitry Polukhin 
390*1ce89899SDmitry Polukhin template <typename T>
391*1ce89899SDmitry Polukhin void NegativeCallWithDependentAndNondependentArgs(ExpensiveMovableType a, T b) {
392*1ce89899SDmitry Polukhin     B::bar(std::move(a), b);
393*1ce89899SDmitry Polukhin }
394