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.
6template <typename T>
7struct Iterator {
8 void operator++();
9 T operator*();
10 bool operator!=(const Iterator& other);
11};
12
13// Iterator returning by reference.
14template <typename T>
15struct 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.
23template <typename T>
24struct 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.
31template <typename T>
32class 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.
40template <typename T>
41class OperatorWrapper {
42 public:
43 OperatorWrapper() = delete;
44};
45
46struct 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.
53class ComplexClass {
54 public:
55 ComplexClass();
56 ~ComplexClass();
57 operator OperatorWrapper<ComplexClass>();
58};
59
60typedef View<Iterator<SimpleClass>> SimpleView;
61typedef View<RefIterator<SimpleClass>> SimpleRefView;
62typedef View<Iterator<ComplexClass>> ComplexView;
63typedef 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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

source code of clang-tools-extra/test/clang-tidy/checkers/performance/implicit-conversion-in-loop.cpp