// RUN: %check_clang_tidy %s performance-implicit-conversion-in-loop %t // ---------- Classes used in the tests ---------- // Iterator returning by value. template struct Iterator { void operator++(); T operator*(); bool operator!=(const Iterator& other); }; // Iterator returning by reference. template 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 struct View { T begin(); T end(); }; // With this class, the implicit conversion is a call to the (implicit) // constructor of the class. template 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 class OperatorWrapper { public: explicit OperatorWrapper(const T& t); }; struct SimpleClass { int foo; operator OperatorWrapper(); }; // 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(); }; typedef View> SimpleView; typedef View> SimpleRefView; typedef View> ComplexView; typedef View> 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& 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& foo : SimpleView()) {} for (const ImplicitWrapper foo : SimpleView()) {} for (ImplicitWrapperfoo : SimpleView()) {} } void ImplicitSimpleClassRefIterator() { for (const ImplicitWrapper& foo : SimpleRefView()) {} // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} // for (ImplicitWrapper& foo : SimpleRefView()) {} for (const ImplicitWrapper foo : SimpleRefView()) {} for (ImplicitWrapperfoo : SimpleRefView()) {} } void ImplicitComplexClassIterator() { for (const ImplicitWrapper& foo : ComplexView()) {} // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} // for (ImplicitWrapper& foo : ComplexView()) {} for (const ImplicitWrapper foo : ComplexView()) {} for (ImplicitWrapperfoo : ComplexView()) {} } void ImplicitComplexClassRefIterator() { for (const ImplicitWrapper& foo : ComplexRefView()) {} // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} // for (ImplicitWrapper& foo : ComplexRefView()) {} for (const ImplicitWrapper foo : ComplexRefView()) {} for (ImplicitWrapperfoo : ComplexRefView()) {} } void OperatorSimpleClassIterator() { for (const OperatorWrapper& foo : SimpleView()) {} // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} // for (OperatorWrapper& foo : SimpleView()) {} for (const OperatorWrapper foo : SimpleView()) {} for (OperatorWrapperfoo : SimpleView()) {} } void OperatorSimpleClassRefIterator() { for (const OperatorWrapper& foo : SimpleRefView()) {} // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const SimpleClass &'.*}} // for (OperatorWrapper& foo : SimpleRefView()) {} for (const OperatorWrapper foo : SimpleRefView()) {} for (OperatorWrapperfoo : SimpleRefView()) {} } void OperatorComplexClassIterator() { for (const OperatorWrapper& foo : ComplexView()) {} // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} // for (OperatorWrapper& foo : ComplexView()) {} for (const OperatorWrapper foo : ComplexView()) {} for (OperatorWrapperfoo : ComplexView()) {} } void OperatorComplexClassRefIterator() { for (const OperatorWrapper& foo : ComplexRefView()) {} // CHECK-MESSAGES: [[@LINE-1]]:{{[0-9]*}}: warning: the type of the{{.*'const ComplexClass &'.*}} // for (OperatorWrapper& foo : ComplexRefView()) {} for (const OperatorWrapper foo : ComplexRefView()) {} for (OperatorWrapperfoo : ComplexRefView()) {} }