// RUN: %check_clang_tidy %s performance-implicit-conversion-in-loop %t
// ---------- Classes used in the tests ----------
// Iterator returning by value.
template <typename T>
struct Iterator {
void operator++();
T operator*();
bool operator!=(const Iterator& other);
};
// Iterator returning by reference.
template <typename T>
struct RefIterator {
void operator++();
T& operator*();
bool operator!=(const RefIterator& other);
};
// The template argument is an iterator type, and a view is an object you can
// run a for loop on.
template <typename T>
struct View {
T begin();
T end();
};
// With this class, the implicit conversion is a call to the (implicit)
// constructor of the class.
template <typename T>
class ImplicitWrapper {
public:
// Implicit!
ImplicitWrapper(const T& t);
};
// With this class, the implicit conversion is a call to the conversion
// operators of SimpleClass and ComplexClass.
template <typename T>
class OperatorWrapper {
public:
OperatorWrapper() = delete;
};
struct SimpleClass {
int foo;
operator OperatorWrapper<SimpleClass>();
};
// The materialize expression is not the same when the class has a destructor,
// so we make sure we cover that case too.
class ComplexClass {
public:
ComplexClass();
~ComplexClass();
operator OperatorWrapper<ComplexClass>();
};
typedef View<Iterator<SimpleClass>> SimpleView;
typedef View<RefIterator<SimpleClass>> SimpleRefView;
typedef View<Iterator<ComplexClass>> ComplexView;
typedef View<RefIterator<ComplexClass>> ComplexRefView;
// ---------- The test themselves ----------
// For each test we do, in the same order, const ref, non const ref, const
// value, non const value.
void SimpleClassIterator() {
for (const SimpleClass& foo : SimpleView()) {}
// This line does not compile because a temporary cannot be assigned to a non
// const reference.
// for (SimpleClass& foo : SimpleView()) {}
for (const SimpleClass foo : SimpleView()) {}
for (SimpleClass foo : SimpleView()) {}
}
void SimpleClassRefIterator() {
for (const SimpleClass& foo : SimpleRefView()) {}
for (SimpleClass& foo : SimpleRefView()) {}
for (const SimpleClass foo : SimpleRefView()) {}
for (SimpleClass foo : SimpleRefView()) {}
}
void ComplexClassIterator() {
for (const ComplexClass& foo : ComplexView()) {}
// for (ComplexClass& foo : ComplexView()) {}
for (const ComplexClass foo : ComplexView()) {}
for (ComplexClass foo : ComplexView()) {}
}
void ComplexClassRefIterator() {
for (const ComplexClass& foo : ComplexRefView()) {}
for (ComplexClass& foo : ComplexRefView()) {}
for (const ComplexClass foo : ComplexRefView()) {}
for (ComplexClass foo : ComplexRefView()) {}
}
void ImplicitSimpleClassIterator() {
for (const ImplicitWrapper<SimpleClass>& foo : SimpleView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the loop variable 'foo' is different from the one returned by the iterator and generates an implicit conversion; you can either change the type to the matching one ('const SimpleClass &' but 'const auto&' is always a valid option) or remove the reference to make it explicit that you are creating a new value [performance-implicit-conversion-in-loop]
// for (ImplicitWrapper<SimpleClass>& foo : SimpleView()) {}
for (const ImplicitWrapper<SimpleClass> foo : SimpleView()) {}
for (ImplicitWrapper<SimpleClass> foo : SimpleView()) {}
}
void ImplicitSimpleClassRefIterator() {
for (const ImplicitWrapper<SimpleClass>& foo : SimpleRefView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
// for (ImplicitWrapper<SimpleClass>& foo : SimpleRefView()) {}
for (const ImplicitWrapper<SimpleClass> foo : SimpleRefView()) {}
for (ImplicitWrapper<SimpleClass> foo : SimpleRefView()) {}
}
void ImplicitSimpleClassArray() {
SimpleClass array[5];
for (const ImplicitWrapper<SimpleClass>& foo : array) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
// for (ImplicitWrapper<SimpleClass>& foo : array) {}
for (const ImplicitWrapper<SimpleClass> foo : array) {}
for (ImplicitWrapper<SimpleClass> foo : array) {}
}
void ImplicitComplexClassIterator() {
for (const ImplicitWrapper<ComplexClass>& foo : ComplexView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
// for (ImplicitWrapper<ComplexClass>& foo : ComplexView()) {}
for (const ImplicitWrapper<ComplexClass> foo : ComplexView()) {}
for (ImplicitWrapper<ComplexClass> foo : ComplexView()) {}
}
void ImplicitComplexClassRefIterator() {
ComplexClass array[5];
for (const ImplicitWrapper<ComplexClass>& foo : array) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
// for (ImplicitWrapper<ComplexClass>& foo : array) {}
for (const ImplicitWrapper<ComplexClass> foo : array) {}
for (ImplicitWrapper<ComplexClass> foo : array) {}
}
void ImplicitComplexClassArray() {
for (const ImplicitWrapper<ComplexClass>& foo : ComplexRefView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
// for (ImplicitWrapper<ComplexClass>& foo : ComplexRefView()) {}
for (const ImplicitWrapper<ComplexClass> foo : ComplexRefView()) {}
for (ImplicitWrapper<ComplexClass> foo : ComplexRefView()) {}
}
void OperatorSimpleClassIterator() {
for (const OperatorWrapper<SimpleClass>& foo : SimpleView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
// for (OperatorWrapper<SimpleClass>& foo : SimpleView()) {}
for (const OperatorWrapper<SimpleClass> foo : SimpleView()) {}
for (OperatorWrapper<SimpleClass> foo : SimpleView()) {}
}
void OperatorSimpleClassRefIterator() {
for (const OperatorWrapper<SimpleClass>& foo : SimpleRefView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
// for (OperatorWrapper<SimpleClass>& foo : SimpleRefView()) {}
for (const OperatorWrapper<SimpleClass> foo : SimpleRefView()) {}
for (OperatorWrapper<SimpleClass> foo : SimpleRefView()) {}
}
void OperatorSimpleClassArray() {
SimpleClass array[5];
for (const OperatorWrapper<SimpleClass>& foo : array) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}}
// for (OperatorWrapper<SimpleClass>& foo : array) {}
for (const OperatorWrapper<SimpleClass> foo : array) {}
for (OperatorWrapper<SimpleClass> foo : array) {}
}
void OperatorComplexClassIterator() {
for (const OperatorWrapper<ComplexClass>& foo : ComplexView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
// for (OperatorWrapper<ComplexClass>& foo : ComplexView()) {}
for (const OperatorWrapper<ComplexClass> foo : ComplexView()) {}
for (OperatorWrapper<ComplexClass> foo : ComplexView()) {}
}
void OperatorComplexClassRefIterator() {
for (const OperatorWrapper<ComplexClass>& foo : ComplexRefView()) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
// for (OperatorWrapper<ComplexClass>& foo : ComplexRefView()) {}
for (const OperatorWrapper<ComplexClass> foo : ComplexRefView()) {}
for (OperatorWrapper<ComplexClass> foo : ComplexRefView()) {}
}
void OperatorComplexClassArray() {
ComplexClass array[5];
for (const OperatorWrapper<ComplexClass>& foo : array) {}
// CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}}
// for (OperatorWrapper<ComplexClass>& foo : array) {}
for (const OperatorWrapper<ComplexClass> foo : array) {}
for (OperatorWrapper<ComplexClass> foo : array) {}
}