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()69 void 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()78 void 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()85 void 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()92 void 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()99 void 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()107 void 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()115 void 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()124 void 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()132 void 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()141 void 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()149 void 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()157 void 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()165 void 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()174 void 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()182 void 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()190 void 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