llvm-project/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp

299 lines
8.3 KiB
C++

// RUN: %check_clang_tidy %s performance-for-range-copy %t -- -- -fno-delayed-template-parsing
namespace std {
template <typename _Tp>
struct remove_reference { typedef _Tp type; };
template <typename _Tp>
struct remove_reference<_Tp&> { typedef _Tp type; };
template <typename _Tp>
struct remove_reference<_Tp&&> { typedef _Tp type; };
template <typename _Tp>
constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) {
return static_cast<typename std::remove_reference<_Tp>::type &&>(__t);
}
} // std
template <typename T>
struct Iterator {
void operator++() {}
const T& operator*() {
static T* TT = new T();
return *TT;
}
bool operator!=(const Iterator &) { return false; }
typedef const T& const_reference;
};
template <typename T>
struct View {
View() = default;
T begin() { return T(); }
T begin() const { return T(); }
T end() { return T(); }
T end() const { return T(); }
typedef typename T::const_reference const_reference;
};
struct ConstructorConvertible {
};
struct S {
S();
S(const S &);
S(const ConstructorConvertible&) {}
~S();
S &operator=(const S &);
};
struct Convertible {
operator S() const {
return S();
}
};
void negativeConstReference() {
for (const S &S1 : View<Iterator<S>>()) {
}
}
void negativeUserDefinedConversion() {
Convertible C[0];
for (const S S1 : C) {
}
}
void negativeImplicitConstructorConversion() {
ConstructorConvertible C[0];
for (const S S1 : C) {
}
}
template <typename T>
void uninstantiated() {
for (const S S1 : View<Iterator<S>>()) {}
// CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not a reference type; this creates a copy in each iteration; consider making this a reference [performance-for-range-copy]
// CHECK-FIXES: {{^}} for (const S& S1 : View<Iterator<S>>()) {}
// Don't warn on dependent types.
for (const T t1 : View<Iterator<T>>()) {
}
}
template <typename T>
void instantiated() {
for (const S S2 : View<Iterator<S>>()) {}
// CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
// CHECK-FIXES: {{^}} for (const S& S2 : View<Iterator<S>>()) {}
for (const T T2 : View<Iterator<T>>()) {}
// CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is {{.*}}
// CHECK-FIXES: {{^}} for (const T& T2 : View<Iterator<T>>()) {}
}
template <typename T>
void instantiatedNegativeTypedefConstReference() {
for (typename T::const_reference T2 : T()) {
S S1 = T2;
}
}
void f() {
instantiated<int>();
instantiated<S>();
instantiatedNegativeTypedefConstReference<View<Iterator<S>>>();
}
struct Mutable {
Mutable() {}
Mutable(const Mutable &) = default;
Mutable(Mutable&&) = default;
Mutable(const Mutable &, const Mutable &) {}
void setBool(bool B) {}
bool constMethod() const {
return true;
}
Mutable& operator[](int I) {
return *this;
}
bool operator==(const Mutable &Other) const {
return true;
}
~Mutable() {}
};
struct Point {
~Point() {}
int x, y;
};
Mutable& operator<<(Mutable &Out, bool B) {
Out.setBool(B);
return Out;
}
bool operator!=(const Mutable& M1, const Mutable& M2) {
return false;
}
void use(const Mutable &M);
void use(int I);
void useTwice(const Mutable &M1, const Mutable &M2);
void useByValue(Mutable M);
void useByConstValue(const Mutable M);
void mutate(Mutable *M);
void mutate(Mutable &M);
void onceConstOnceMutated(const Mutable &M1, Mutable &M2);
void negativeVariableIsMutated() {
for (auto M : View<Iterator<Mutable>>()) {
mutate(M);
}
for (auto M : View<Iterator<Mutable>>()) {
mutate(&M);
}
for (auto M : View<Iterator<Mutable>>()) {
M.setBool(true);
}
}
void negativeOnceConstOnceMutated() {
for (auto M : View<Iterator<Mutable>>()) {
onceConstOnceMutated(M, M);
}
}
void negativeVarIsMoved() {
for (auto M : View<Iterator<Mutable>>()) {
auto Moved = std::move(M);
}
}
void negativeNonConstOperatorIsInvoked() {
for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
auto& N = NonConstOperatorInvokee[0];
}
}
void negativeNonConstNonMemberOperatorInvoked() {
for (auto NonConstOperatorInvokee : View<Iterator<Mutable>>()) {
NonConstOperatorInvokee << true;
}
}
void negativeConstCheapToCopy() {
for (const int I : View<Iterator<int>>()) {
}
}
void negativeConstCheapToCopyTypedef() {
typedef const int ConstInt;
for (ConstInt C : View<Iterator<ConstInt>>()) {
}
}
void negativeCheapToCopy() {
for (int I : View<Iterator<int>>()) {
use(I);
}
}
void negativeCheapToCopyTypedef() {
typedef int Int;
for (Int I : View<Iterator<Int>>()) {
use(I);
}
}
void positiveOnlyConstMethodInvoked() {
for (auto M : View<Iterator<Mutable>>()) {
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
// CHECK-FIXES: for (const auto& M : View<Iterator<Mutable>>()) {
M.constMethod();
}
}
void positiveOnlyUsedAsConstArguments() {
for (auto UsedAsConst : View<Iterator<Mutable>>()) {
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
// CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Mutable>>()) {
use(UsedAsConst);
useTwice(UsedAsConst, UsedAsConst);
useByValue(UsedAsConst);
useByConstValue(UsedAsConst);
}
}
void positiveOnlyAccessedFieldAsConst() {
for (auto UsedAsConst : View<Iterator<Point>>()) {
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
// CHECK-FIXES: for (const auto& UsedAsConst : View<Iterator<Point>>()) {
use(UsedAsConst.x);
use(UsedAsConst.y);
}
}
void positiveOnlyUsedInCopyConstructor() {
for (auto A : View<Iterator<Mutable>>()) {
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
// CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
Mutable Copy = A;
Mutable Copy2(A);
}
}
void positiveTwoConstConstructorArgs() {
for (auto A : View<Iterator<Mutable>>()) {
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
// CHECK-FIXES: for (const auto& A : View<Iterator<Mutable>>()) {
Mutable Copy(A, A);
}
}
void PositiveConstMemberOperatorInvoked() {
for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
// CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
bool result = ConstOperatorInvokee == Mutable();
}
}
void PositiveConstNonMemberOperatorInvoked() {
for (auto ConstOperatorInvokee : View<Iterator<Mutable>>()) {
// CHECK-MESSAGES: [[@LINE-1]]:13: warning: loop variable is copied but only used as const reference; consider making it a const reference [performance-for-range-copy]
// CHECK-FIXES: for (const auto& ConstOperatorInvokee : View<Iterator<Mutable>>()) {
bool result = ConstOperatorInvokee != Mutable();
}
}
void IgnoreLoopVariableNotUsedInLoopBody() {
for (auto _ : View<Iterator<S>>()) {
}
}
template <typename T>
struct ValueReturningIterator {
void operator++() {}
T operator*() { return T(); }
bool operator!=(const ValueReturningIterator &) { return false; }
typedef const T &const_reference;
};
void negativeValueIterator() {
// Check does not trigger for iterators that return elements by value.
for (const S SS : View<ValueReturningIterator<S>>()) {
}
}
View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }
void positiveValueIteratorUsedElseWhere() {
for (const S SS : createView(*ValueReturningIterator<S>())) {
// CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
// a reference type; this creates a copy in each iteration; consider making
// this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
// SS : createView(*ValueReturningIterator<S>())) {
}
}