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