1 // RUN: %check_clang_tidy -std=c++20 -check-suffixes=,RANGES %s modernize-loop-convert %t 2 3 // RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-SYS %s modernize-loop-convert %t -- \ 4 // RUN: -config="{CheckOptions: [ \ 5 // RUN: {key: modernize-loop-convert.MakeReverseRangeFunction, value: 'llvm::reverse'}, \ 6 // RUN: {key: modernize-loop-convert.MakeReverseRangeHeader, value: 'llvm/ADT/STLExtras.h'}]}" 7 8 // RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-SYS %s modernize-loop-convert %t -- \ 9 // RUN: -config="{CheckOptions: [ \ 10 // RUN: {key: modernize-loop-convert.MakeReverseRangeFunction, value: 'llvm::reverse'}, \ 11 // RUN: {key: modernize-loop-convert.MakeReverseRangeHeader, value: '<llvm/ADT/STLExtras.h>'}]}" 12 13 // RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-HEADER %s modernize-loop-convert %t -- \ 14 // RUN: -config="{CheckOptions: [ \ 15 // RUN: {key: modernize-loop-convert.MakeReverseRangeFunction, value: 'llvm::reverse'}]}" 16 17 // Ensure the check doesn't transform reverse loops when not in c++20 mode or 18 // when UseCxx20ReverseRanges has been disabled 19 // RUN: clang-tidy %s -checks=-*,modernize-loop-convert -- -std=c++17 | count 0 20 21 // RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: \ 22 // RUN: [{key: modernize-loop-convert.UseCxx20ReverseRanges, value: 'false'}] \ 23 // RUN: }" -- -std=c++20 | count 0 24 25 // Ensure we get a warning if we supply the header argument without the 26 // function argument. 27 // RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: [ \ 28 // RUN: {key: modernize-loop-convert.MakeReverseRangeHeader, value: 'llvm/ADT/STLExtras.h'}]}" \ 29 // RUN: -- -std=c++17 2>&1 \ 30 // RUN: | FileCheck %s -check-prefix=CHECK-HEADER-NO-FUNC \ 31 // RUN: -implicit-check-not="{{warning|error}}:" 32 33 // CHECK-HEADER-NO-FUNC: warning: modernize-loop-convert: 'MakeReverseRangeHeader' is set but 'MakeReverseRangeFunction' is not, disabling reverse loop transformation 34 35 // Make sure appropiate headers are included 36 // CHECK-FIXES-RANGES: #include <ranges> 37 // CHECK-FIXES-CUSTOM-NO-SYS: #include "llvm/ADT/STLExtras.h" 38 // CHECK-FIXES-CUSTOM-SYS: #include <llvm/ADT/STLExtras.h> 39 40 // Make sure no header is included in this example 41 // CHECK-FIXES-CUSTOM-NO-HEADER-NOT: #include 42 43 namespace ADL { 44 45 template <typename T> 46 struct Reversable { 47 using iterator = T *; 48 using const_iterator = const T *; 49 50 iterator begin(); 51 iterator end(); 52 iterator rbegin(); 53 iterator rend(); 54 55 const_iterator begin() const; 56 const_iterator end() const; 57 const_iterator rbegin() const; 58 const_iterator rend() const; 59 60 const_iterator cbegin() const; 61 const_iterator cend() const; 62 const_iterator crbegin() const; 63 const_iterator crend() const; 64 }; 65 66 template <typename C> 67 constexpr auto rbegin(C& c) -> decltype(c.rbegin()) { return c.rbegin(); } 68 template <typename C> 69 constexpr auto rend(C& c) -> decltype(c.rend()) { return c.rend(); } 70 template <typename C> 71 constexpr auto rbegin(const C& c) -> decltype(c.rbegin()) { return c.rbegin(); } 72 template <typename C> 73 constexpr auto rend(const C& c) -> decltype(c.rend()) { return c.rend(); } 74 75 template <typename C> 76 constexpr auto crbegin(C& c) -> decltype(c.crbegin()); 77 template <typename C> 78 constexpr auto crend(C& c) -> decltype(c.crend()); 79 template <typename C> 80 constexpr auto crbegin(const C& c) -> decltype(c.crbegin()); 81 template <typename C> 82 constexpr auto crend(const C& c) -> decltype(c.crend()); 83 84 } // namespace ADL 85 86 using ADL::Reversable; 87 88 template <typename T> 89 void observe(const T &); 90 template <typename T> 91 void mutate(T &); 92 93 void constContainer(const Reversable<int> &Numbers) { 94 for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) { 95 observe(*I); 96 } 97 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 98 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 99 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 100 // CHECK-FIXES-NEXT: observe(Number); 101 // CHECK-FIXES-NEXT: } 102 103 for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) { 104 observe(*I); 105 } 106 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 107 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 108 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 109 // CHECK-FIXES-NEXT: observe(Number); 110 // CHECK-FIXES-NEXT: } 111 112 for (auto I = rbegin(Numbers), E = rend(Numbers); I != E; ++I) { 113 observe(*I); 114 } 115 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 116 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 117 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 118 // CHECK-FIXES-NEXT: observe(Number); 119 // CHECK-FIXES-NEXT: } 120 121 for (auto I = crbegin(Numbers), E = crend(Numbers); I != E; ++I) { 122 observe(*I); 123 } 124 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 125 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 126 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 127 // CHECK-FIXES-NEXT: observe(Number); 128 // CHECK-FIXES-NEXT: } 129 130 // Ensure these bad loops aren't transformed. 131 for (auto I = Numbers.rbegin(), E = Numbers.end(); I != E; ++I) { 132 observe(*I); 133 } 134 for (auto I = Numbers.begin(), E = Numbers.rend(); I != E; ++I) { 135 observe(*I); 136 } 137 } 138 139 void nonConstContainer(Reversable<int> &Numbers) { 140 for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) { 141 mutate(*I); 142 } 143 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 144 // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) { 145 // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) { 146 // CHECK-FIXES-NEXT: mutate(Number); 147 // CHECK-FIXES-NEXT: } 148 149 for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) { 150 observe(*I); 151 } 152 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 153 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 154 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 155 // CHECK-FIXES-NEXT: observe(Number); 156 // CHECK-FIXES-NEXT: } 157 158 for (auto I = rbegin(Numbers), E = rend(Numbers); I != E; ++I) { 159 mutate(*I); 160 } 161 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 162 // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) { 163 // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) { 164 // CHECK-FIXES-NEXT: mutate(Number); 165 // CHECK-FIXES-NEXT: } 166 } 167