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