1 // RUN: %check_clang_tidy %s performance-implicit-conversion-in-loop %t 2 3 // ---------- Classes used in the tests ---------- 4 5 // Iterator returning by value. 6 template <typename T> 7 struct Iterator { 8 void operator++(); 9 T operator*(); 10 bool operator!=(const Iterator& other); 11 }; 12 13 // Iterator returning by reference. 14 template <typename T> 15 struct RefIterator { 16 void operator++(); 17 T& operator*(); 18 bool operator!=(const RefIterator& other); 19 }; 20 21 // The template argument is an iterator type, and a view is an object you can 22 // run a for loop on. 23 template <typename T> 24 struct View { 25 T begin(); 26 T end(); 27 }; 28 29 // With this class, the implicit conversion is a call to the (implicit) 30 // constructor of the class. 31 template <typename T> 32 class ImplicitWrapper { 33 public: 34 // Implicit! 35 ImplicitWrapper(const T& t); 36 }; 37 38 // With this class, the implicit conversion is a call to the conversion 39 // operators of SimpleClass and ComplexClass. 40 template <typename T> 41 class OperatorWrapper { 42 public: 43 OperatorWrapper() = delete; 44 }; 45 46 struct SimpleClass { 47 int foo; 48 operator OperatorWrapper<SimpleClass>(); 49 }; 50 51 // The materialize expression is not the same when the class has a destructor, 52 // so we make sure we cover that case too. 53 class ComplexClass { 54 public: 55 ComplexClass(); 56 ~ComplexClass(); 57 operator OperatorWrapper<ComplexClass>(); 58 }; 59 60 typedef View<Iterator<SimpleClass>> SimpleView; 61 typedef View<RefIterator<SimpleClass>> SimpleRefView; 62 typedef View<Iterator<ComplexClass>> ComplexView; 63 typedef View<RefIterator<ComplexClass>> ComplexRefView; 64 65 // ---------- The test themselves ---------- 66 // For each test we do, in the same order, const ref, non const ref, const 67 // value, non const value. 68 SimpleClassIterator()69void SimpleClassIterator() { 70 for (const SimpleClass& foo : SimpleView()) {} 71 // This line does not compile because a temporary cannot be assigned to a non 72 // const reference. 73 // for (SimpleClass& foo : SimpleView()) {} 74 for (const SimpleClass foo : SimpleView()) {} 75 for (SimpleClass foo : SimpleView()) {} 76 } 77 SimpleClassRefIterator()78void SimpleClassRefIterator() { 79 for (const SimpleClass& foo : SimpleRefView()) {} 80 for (SimpleClass& foo : SimpleRefView()) {} 81 for (const SimpleClass foo : SimpleRefView()) {} 82 for (SimpleClass foo : SimpleRefView()) {} 83 } 84 ComplexClassIterator()85void ComplexClassIterator() { 86 for (const ComplexClass& foo : ComplexView()) {} 87 // for (ComplexClass& foo : ComplexView()) {} 88 for (const ComplexClass foo : ComplexView()) {} 89 for (ComplexClass foo : ComplexView()) {} 90 } 91 ComplexClassRefIterator()92void ComplexClassRefIterator() { 93 for (const ComplexClass& foo : ComplexRefView()) {} 94 for (ComplexClass& foo : ComplexRefView()) {} 95 for (const ComplexClass foo : ComplexRefView()) {} 96 for (ComplexClass foo : ComplexRefView()) {} 97 } 98 ImplicitSimpleClassIterator()99void ImplicitSimpleClassIterator() { 100 for (const ImplicitWrapper<SimpleClass>& foo : SimpleView()) {} 101 // 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] 102 // for (ImplicitWrapper<SimpleClass>& foo : SimpleView()) {} 103 for (const ImplicitWrapper<SimpleClass> foo : SimpleView()) {} 104 for (ImplicitWrapper<SimpleClass> foo : SimpleView()) {} 105 } 106 ImplicitSimpleClassRefIterator()107void ImplicitSimpleClassRefIterator() { 108 for (const ImplicitWrapper<SimpleClass>& foo : SimpleRefView()) {} 109 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} 110 // for (ImplicitWrapper<SimpleClass>& foo : SimpleRefView()) {} 111 for (const ImplicitWrapper<SimpleClass> foo : SimpleRefView()) {} 112 for (ImplicitWrapper<SimpleClass> foo : SimpleRefView()) {} 113 } 114 ImplicitSimpleClassArray()115void ImplicitSimpleClassArray() { 116 SimpleClass array[5]; 117 for (const ImplicitWrapper<SimpleClass>& foo : array) {} 118 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} 119 // for (ImplicitWrapper<SimpleClass>& foo : array) {} 120 for (const ImplicitWrapper<SimpleClass> foo : array) {} 121 for (ImplicitWrapper<SimpleClass> foo : array) {} 122 } 123 ImplicitComplexClassIterator()124void ImplicitComplexClassIterator() { 125 for (const ImplicitWrapper<ComplexClass>& foo : ComplexView()) {} 126 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} 127 // for (ImplicitWrapper<ComplexClass>& foo : ComplexView()) {} 128 for (const ImplicitWrapper<ComplexClass> foo : ComplexView()) {} 129 for (ImplicitWrapper<ComplexClass> foo : ComplexView()) {} 130 } 131 ImplicitComplexClassRefIterator()132void ImplicitComplexClassRefIterator() { 133 ComplexClass array[5]; 134 for (const ImplicitWrapper<ComplexClass>& foo : array) {} 135 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} 136 // for (ImplicitWrapper<ComplexClass>& foo : array) {} 137 for (const ImplicitWrapper<ComplexClass> foo : array) {} 138 for (ImplicitWrapper<ComplexClass> foo : array) {} 139 } 140 ImplicitComplexClassArray()141void ImplicitComplexClassArray() { 142 for (const ImplicitWrapper<ComplexClass>& foo : ComplexRefView()) {} 143 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} 144 // for (ImplicitWrapper<ComplexClass>& foo : ComplexRefView()) {} 145 for (const ImplicitWrapper<ComplexClass> foo : ComplexRefView()) {} 146 for (ImplicitWrapper<ComplexClass> foo : ComplexRefView()) {} 147 } 148 OperatorSimpleClassIterator()149void OperatorSimpleClassIterator() { 150 for (const OperatorWrapper<SimpleClass>& foo : SimpleView()) {} 151 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} 152 // for (OperatorWrapper<SimpleClass>& foo : SimpleView()) {} 153 for (const OperatorWrapper<SimpleClass> foo : SimpleView()) {} 154 for (OperatorWrapper<SimpleClass> foo : SimpleView()) {} 155 } 156 OperatorSimpleClassRefIterator()157void OperatorSimpleClassRefIterator() { 158 for (const OperatorWrapper<SimpleClass>& foo : SimpleRefView()) {} 159 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} 160 // for (OperatorWrapper<SimpleClass>& foo : SimpleRefView()) {} 161 for (const OperatorWrapper<SimpleClass> foo : SimpleRefView()) {} 162 for (OperatorWrapper<SimpleClass> foo : SimpleRefView()) {} 163 } 164 OperatorSimpleClassArray()165void OperatorSimpleClassArray() { 166 SimpleClass array[5]; 167 for (const OperatorWrapper<SimpleClass>& foo : array) {} 168 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} 169 // for (OperatorWrapper<SimpleClass>& foo : array) {} 170 for (const OperatorWrapper<SimpleClass> foo : array) {} 171 for (OperatorWrapper<SimpleClass> foo : array) {} 172 } 173 OperatorComplexClassIterator()174void OperatorComplexClassIterator() { 175 for (const OperatorWrapper<ComplexClass>& foo : ComplexView()) {} 176 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} 177 // for (OperatorWrapper<ComplexClass>& foo : ComplexView()) {} 178 for (const OperatorWrapper<ComplexClass> foo : ComplexView()) {} 179 for (OperatorWrapper<ComplexClass> foo : ComplexView()) {} 180 } 181 OperatorComplexClassRefIterator()182void OperatorComplexClassRefIterator() { 183 for (const OperatorWrapper<ComplexClass>& foo : ComplexRefView()) {} 184 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} 185 // for (OperatorWrapper<ComplexClass>& foo : ComplexRefView()) {} 186 for (const OperatorWrapper<ComplexClass> foo : ComplexRefView()) {} 187 for (OperatorWrapper<ComplexClass> foo : ComplexRefView()) {} 188 } 189 OperatorComplexClassArray()190void OperatorComplexClassArray() { 191 ComplexClass array[5]; 192 for (const OperatorWrapper<ComplexClass>& foo : array) {} 193 // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} 194 // for (OperatorWrapper<ComplexClass>& foo : array) {} 195 for (const OperatorWrapper<ComplexClass> foo : array) {} 196 for (OperatorWrapper<ComplexClass> foo : array) {} 197 } 198