forked from OSchip/llvm-project
384 lines
14 KiB
C++
384 lines
14 KiB
C++
// RUN: %check_clang_tidy %s performance-unnecessary-value-param %t
|
|
|
|
// CHECK-FIXES: #include <utility>
|
|
|
|
struct ExpensiveToCopyType {
|
|
const ExpensiveToCopyType & constReference() const {
|
|
return *this;
|
|
}
|
|
void nonConstMethod();
|
|
virtual ~ExpensiveToCopyType();
|
|
};
|
|
|
|
void mutate(ExpensiveToCopyType &);
|
|
void mutate(ExpensiveToCopyType *);
|
|
void useAsConstReference(const ExpensiveToCopyType &);
|
|
void useByValue(ExpensiveToCopyType);
|
|
|
|
template <class T> class Vector {
|
|
public:
|
|
using iterator = T*;
|
|
using const_iterator = const T*;
|
|
|
|
Vector(const Vector&);
|
|
Vector& operator=(const Vector&);
|
|
|
|
iterator begin();
|
|
iterator end();
|
|
const_iterator begin() const;
|
|
const_iterator end() const;
|
|
};
|
|
|
|
// This class simulates std::pair<>. It is trivially copy constructible
|
|
// and trivially destructible, but not trivially copy assignable.
|
|
class SomewhatTrivial {
|
|
public:
|
|
SomewhatTrivial();
|
|
SomewhatTrivial(const SomewhatTrivial&) = default;
|
|
~SomewhatTrivial() = default;
|
|
SomewhatTrivial& operator=(const SomewhatTrivial&);
|
|
};
|
|
|
|
struct MoveOnlyType {
|
|
MoveOnlyType(const MoveOnlyType &) = delete;
|
|
MoveOnlyType(MoveOnlyType &&) = default;
|
|
~MoveOnlyType();
|
|
void constMethod() const;
|
|
};
|
|
|
|
struct ExpensiveMovableType {
|
|
ExpensiveMovableType();
|
|
ExpensiveMovableType(ExpensiveMovableType &&);
|
|
ExpensiveMovableType(const ExpensiveMovableType &) = default;
|
|
ExpensiveMovableType &operator=(const ExpensiveMovableType &) = default;
|
|
ExpensiveMovableType &operator=(ExpensiveMovableType &&);
|
|
~ExpensiveMovableType();
|
|
};
|
|
|
|
void positiveExpensiveConstValue(const ExpensiveToCopyType Obj);
|
|
// CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj);
|
|
void positiveExpensiveConstValue(const ExpensiveToCopyType Obj) {
|
|
// 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]
|
|
// CHECK-FIXES: void positiveExpensiveConstValue(const ExpensiveToCopyType& Obj) {
|
|
}
|
|
|
|
void positiveExpensiveValue(ExpensiveToCopyType Obj);
|
|
// CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj);
|
|
void positiveExpensiveValue(ExpensiveToCopyType Obj) {
|
|
// 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]
|
|
// CHECK-FIXES: void positiveExpensiveValue(const ExpensiveToCopyType& Obj) {
|
|
Obj.constReference();
|
|
useAsConstReference(Obj);
|
|
auto Copy = Obj;
|
|
useByValue(Obj);
|
|
}
|
|
|
|
void positiveVector(Vector<ExpensiveToCopyType> V) {
|
|
// 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]
|
|
// CHECK-FIXES: void positiveVector(const Vector<ExpensiveToCopyType>& V) {
|
|
for (const auto& Obj : V) {
|
|
useByValue(Obj);
|
|
}
|
|
}
|
|
|
|
void positiveWithComment(const ExpensiveToCopyType /* important */ S);
|
|
// CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S);
|
|
void positiveWithComment(const ExpensiveToCopyType /* important */ S) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:68: warning: the const qualified
|
|
// CHECK-FIXES: void positiveWithComment(const ExpensiveToCopyType& /* important */ S) {
|
|
}
|
|
|
|
void positiveUnnamedParam(const ExpensiveToCopyType) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter #1
|
|
// CHECK-FIXES: void positiveUnnamedParam(const ExpensiveToCopyType&) {
|
|
}
|
|
|
|
void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy);
|
|
// CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy);
|
|
void positiveAndNegative(const ExpensiveToCopyType ConstCopy, const ExpensiveToCopyType& ConstRef, ExpensiveToCopyType Copy) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:52: warning: the const qualified parameter 'ConstCopy'
|
|
// CHECK-MESSAGES: [[@LINE-2]]:120: warning: the parameter 'Copy'
|
|
// CHECK-FIXES: void positiveAndNegative(const ExpensiveToCopyType& ConstCopy, const ExpensiveToCopyType& ConstRef, const ExpensiveToCopyType& Copy) {
|
|
}
|
|
|
|
struct PositiveConstValueConstructor {
|
|
PositiveConstValueConstructor(const ExpensiveToCopyType ConstCopy) {}
|
|
// CHECK-MESSAGES: [[@LINE-1]]:59: warning: the const qualified parameter 'ConstCopy'
|
|
// CHECK-FIXES: PositiveConstValueConstructor(const ExpensiveToCopyType& ConstCopy) {}
|
|
};
|
|
|
|
template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType S, T V) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'S'
|
|
// CHECK-FIXES: template <typename T> void templateWithNonTemplatizedParameter(const ExpensiveToCopyType& S, T V) {
|
|
}
|
|
|
|
void instantiated() {
|
|
templateWithNonTemplatizedParameter(ExpensiveToCopyType(), ExpensiveToCopyType());
|
|
templateWithNonTemplatizedParameter(ExpensiveToCopyType(), 5);
|
|
}
|
|
|
|
template <typename T> void negativeTemplateType(const T V) {
|
|
}
|
|
|
|
void negativeArray(const ExpensiveToCopyType[]) {
|
|
}
|
|
|
|
void negativePointer(ExpensiveToCopyType* Obj) {
|
|
}
|
|
|
|
void negativeConstPointer(const ExpensiveToCopyType* Obj) {
|
|
}
|
|
|
|
void negativeConstReference(const ExpensiveToCopyType& Obj) {
|
|
}
|
|
|
|
void negativeReference(ExpensiveToCopyType& Obj) {
|
|
}
|
|
|
|
void negativeUniversalReference(ExpensiveToCopyType&& Obj) {
|
|
}
|
|
|
|
void negativeSomewhatTrivialConstValue(const SomewhatTrivial Somewhat) {
|
|
}
|
|
|
|
void negativeSomewhatTrivialValue(SomewhatTrivial Somewhat) {
|
|
}
|
|
|
|
void negativeConstBuiltIn(const int I) {
|
|
}
|
|
|
|
void negativeValueBuiltIn(int I) {
|
|
}
|
|
|
|
void negativeValueIsMutatedByReference(ExpensiveToCopyType Obj) {
|
|
mutate(Obj);
|
|
}
|
|
|
|
void negativeValueIsMutatatedByPointer(ExpensiveToCopyType Obj) {
|
|
mutate(&Obj);
|
|
}
|
|
|
|
void negativeValueIsReassigned(ExpensiveToCopyType Obj) {
|
|
Obj = ExpensiveToCopyType();
|
|
}
|
|
|
|
void negativeValueNonConstMethodIsCalled(ExpensiveToCopyType Obj) {
|
|
Obj.nonConstMethod();
|
|
}
|
|
|
|
struct PositiveValueUnusedConstructor {
|
|
PositiveValueUnusedConstructor(ExpensiveToCopyType Copy) {}
|
|
// CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
|
|
// CHECK-FIXES: PositiveValueUnusedConstructor(const ExpensiveToCopyType& Copy) {}
|
|
};
|
|
|
|
struct PositiveValueCopiedConstructor {
|
|
PositiveValueCopiedConstructor(ExpensiveToCopyType Copy) : Field(Copy) {}
|
|
// CHECK-MESSAGES: [[@LINE-1]]:54: warning: the parameter 'Copy'
|
|
// CHECK-FIXES: PositiveValueCopiedConstructor(const ExpensiveToCopyType& Copy) : Field(Copy) {}
|
|
ExpensiveToCopyType Field;
|
|
};
|
|
|
|
struct PositiveValueMovableConstructor {
|
|
PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(Copy) {}
|
|
// CHECK-MESSAGES: [[@LINE-1]]:70: warning: parameter 'Copy'
|
|
// CHECK-FIXES: PositiveValueMovableConstructor(ExpensiveMovableType Copy) : Field(std::move(Copy)) {}
|
|
ExpensiveMovableType Field;
|
|
};
|
|
|
|
struct NegativeValueMovedConstructor {
|
|
NegativeValueMovedConstructor(ExpensiveMovableType Copy) : Field(static_cast<ExpensiveMovableType &&>(Copy)) {}
|
|
ExpensiveMovableType Field;
|
|
};
|
|
|
|
template <typename T>
|
|
struct Container {
|
|
typedef const T & const_reference;
|
|
};
|
|
|
|
void NegativeTypedefParam(const Container<ExpensiveToCopyType>::const_reference Param) {
|
|
}
|
|
|
|
#define UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY() \
|
|
void inMacro(const ExpensiveToCopyType T) { \
|
|
} \
|
|
// Ensure fix is not applied.
|
|
// CHECK-FIXES: void inMacro(const ExpensiveToCopyType T) {
|
|
|
|
UNNECESSARY_VALUE_PARAM_IN_MACRO_BODY()
|
|
// CHECK-MESSAGES: [[@LINE-1]]:1: warning: the const qualified parameter 'T'
|
|
|
|
#define UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(ARGUMENT) \
|
|
ARGUMENT
|
|
|
|
UNNECESSARY_VALUE_PARAM_IN_MACRO_ARGUMENT(void inMacroArgument(const ExpensiveToCopyType InMacroArg) {})
|
|
// CHECK-MESSAGES: [[@LINE-1]]:90: warning: the const qualified parameter 'InMacroArg'
|
|
// CHECK-FIXES: void inMacroArgument(const ExpensiveToCopyType InMacroArg) {}
|
|
|
|
struct VirtualMethod {
|
|
virtual ~VirtualMethod() {}
|
|
virtual void handle(ExpensiveToCopyType T) const = 0;
|
|
};
|
|
|
|
struct NegativeOverriddenMethod : public VirtualMethod {
|
|
void handle(ExpensiveToCopyType Overridden) const {
|
|
// CHECK-FIXES: handle(ExpensiveToCopyType Overridden) const {
|
|
}
|
|
};
|
|
|
|
struct VirtualMethodWarningOnly {
|
|
virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {}
|
|
// CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'T' is copied
|
|
// CHECK-FIXES: virtual void methodWithExpensiveValueParam(ExpensiveToCopyType T) {}
|
|
virtual ~VirtualMethodWarningOnly() {}
|
|
};
|
|
|
|
struct PositiveNonVirualMethod {
|
|
void method(const ExpensiveToCopyType T) {}
|
|
// CHECK-MESSAGES: [[@LINE-1]]:41: warning: the const qualified parameter 'T' is copied
|
|
// CHECK-FIXES: void method(const ExpensiveToCopyType& T) {}
|
|
};
|
|
|
|
struct NegativeDeletedMethod {
|
|
~NegativeDeletedMethod() {}
|
|
NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
|
|
// CHECK-FIXES: NegativeDeletedMethod& operator=(NegativeDeletedMethod N) = delete;
|
|
};
|
|
|
|
void NegativeMoveOnlyTypePassedByValue(MoveOnlyType M) {
|
|
M.constMethod();
|
|
}
|
|
|
|
void PositiveMoveOnCopyConstruction(ExpensiveMovableType E) {
|
|
auto F = E;
|
|
// 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]
|
|
// CHECK-FIXES: auto F = std::move(E);
|
|
}
|
|
|
|
void PositiveConstRefNotMoveSinceReferencedMultipleTimes(ExpensiveMovableType E) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:79: warning: the parameter 'E' is copied
|
|
// CHECK-FIXES: void PositiveConstRefNotMoveSinceReferencedMultipleTimes(const ExpensiveMovableType& E) {
|
|
auto F = E;
|
|
auto G = E;
|
|
}
|
|
|
|
void PositiveMoveOnCopyAssignment(ExpensiveMovableType E) {
|
|
ExpensiveMovableType F;
|
|
F = E;
|
|
// CHECK-MESSAGES: [[@LINE-1]]:7: warning: parameter 'E' is passed by value
|
|
// CHECK-FIXES: F = std::move(E);
|
|
}
|
|
|
|
struct NotCopyAssigned {
|
|
NotCopyAssigned &operator=(const ExpensiveMovableType &);
|
|
};
|
|
|
|
void PositiveNoMoveForNonCopyAssigmentOperator(ExpensiveMovableType E) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:69: warning: the parameter 'E' is copied
|
|
// CHECK-FIXES: void PositiveNoMoveForNonCopyAssigmentOperator(const ExpensiveMovableType& E) {
|
|
NotCopyAssigned N;
|
|
N = E;
|
|
}
|
|
|
|
// The argument could be moved but is not since copy statement is inside a loop.
|
|
void PositiveNoMoveInsideLoop(ExpensiveMovableType E) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:52: warning: the parameter 'E' is copied
|
|
// CHECK-FIXES: void PositiveNoMoveInsideLoop(const ExpensiveMovableType& E) {
|
|
for (;;) {
|
|
auto F = E;
|
|
}
|
|
}
|
|
|
|
void PositiveConstRefNotMoveConstructible(ExpensiveToCopyType T) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:63: warning: the parameter 'T' is copied
|
|
// CHECK-FIXES: void PositiveConstRefNotMoveConstructible(const ExpensiveToCopyType& T) {
|
|
auto U = T;
|
|
}
|
|
|
|
void PositiveConstRefNotMoveAssignable(ExpensiveToCopyType A) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:60: warning: the parameter 'A' is copied
|
|
// CHECK-FIXES: void PositiveConstRefNotMoveAssignable(const ExpensiveToCopyType& A) {
|
|
ExpensiveToCopyType B;
|
|
B = A;
|
|
}
|
|
|
|
// Case where parameter in declaration is already const-qualified but not in
|
|
// implementation. Make sure a second 'const' is not added to the declaration.
|
|
void PositiveConstDeclaration(const ExpensiveToCopyType A);
|
|
// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A);
|
|
void PositiveConstDeclaration(ExpensiveToCopyType A) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:51: warning: the parameter 'A' is copied
|
|
// CHECK-FIXES: void PositiveConstDeclaration(const ExpensiveToCopyType& A) {
|
|
}
|
|
|
|
void PositiveNonConstDeclaration(ExpensiveToCopyType A);
|
|
// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A);
|
|
void PositiveNonConstDeclaration(const ExpensiveToCopyType A) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:60: warning: the const qualified parameter 'A'
|
|
// CHECK-FIXES: void PositiveNonConstDeclaration(const ExpensiveToCopyType& A) {
|
|
}
|
|
|
|
void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:75: warning: the parameter 'A' is copied
|
|
// CHECK-FIXES: void PositiveOnlyMessageAsReferencedInCompilationUnit(ExpensiveToCopyType A) {
|
|
}
|
|
|
|
void ReferenceFunctionOutsideOfCallExpr() {
|
|
void (*ptr)(ExpensiveToCopyType) = &PositiveOnlyMessageAsReferencedInCompilationUnit;
|
|
}
|
|
|
|
void PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType A) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:66: warning: the parameter 'A' is copied
|
|
// CHECK-FIXES: void PositiveMessageAndFixAsFunctionIsCalled(const ExpensiveToCopyType& A) {
|
|
}
|
|
|
|
void ReferenceFunctionByCallingIt() {
|
|
PositiveMessageAndFixAsFunctionIsCalled(ExpensiveToCopyType());
|
|
}
|
|
|
|
// Virtual method overrides of dependent types cannot be recognized unless they
|
|
// are marked as override or final. Test that check is not triggered on methods
|
|
// marked with override or final.
|
|
template <typename T>
|
|
struct NegativeDependentTypeInterface {
|
|
virtual void Method(ExpensiveToCopyType E) = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
struct NegativeOverrideImpl : public NegativeDependentTypeInterface<T> {
|
|
void Method(ExpensiveToCopyType E) override {}
|
|
};
|
|
|
|
template <typename T>
|
|
struct NegativeFinalImpl : public NegativeDependentTypeInterface<T> {
|
|
void Method(ExpensiveToCopyType E) final {}
|
|
};
|
|
|
|
struct PositiveConstructor {
|
|
PositiveConstructor(ExpensiveToCopyType E) : E(E) {}
|
|
// CHECK-MESSAGES: [[@LINE-1]]:43: warning: the parameter 'E' is copied
|
|
// CHECK-FIXES: PositiveConstructor(const ExpensiveToCopyType& E) : E(E) {}
|
|
|
|
ExpensiveToCopyType E;
|
|
};
|
|
|
|
struct NegativeUsingConstructor : public PositiveConstructor {
|
|
using PositiveConstructor::PositiveConstructor;
|
|
};
|
|
|
|
void fun() {
|
|
ExpensiveToCopyType E;
|
|
NegativeUsingConstructor S(E);
|
|
}
|
|
|
|
template<typename T>
|
|
void templateFunction(T) {
|
|
}
|
|
|
|
template<>
|
|
void templateFunction<ExpensiveToCopyType>(ExpensiveToCopyType E) {
|
|
// CHECK-MESSAGES: [[@LINE-1]]:64: warning: the parameter 'E' is copied
|
|
// CHECK-FIXES: void templateFunction<ExpensiveToCopyType>(ExpensiveToCopyType E) {
|
|
E.constReference();
|
|
}
|