1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
// 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) {}
}
|