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 template <typename T> 44 struct Reversable { 45 using iterator = T *; 46 using const_iterator = const T *; 47 48 iterator begin(); 49 iterator end(); 50 iterator rbegin(); 51 iterator rend(); 52 53 const_iterator begin() const; 54 const_iterator end() const; 55 const_iterator rbegin() const; 56 const_iterator rend() const; 57 58 const_iterator cbegin() const; 59 const_iterator cend() const; 60 const_iterator crbegin() const; 61 const_iterator crend() const; 62 }; 63 64 template <typename T> 65 void observe(const T &); 66 template <typename T> 67 void mutate(T &); 68 69 void constContainer(const Reversable<int> &Numbers) { 70 for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) { 71 observe(*I); 72 } 73 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 74 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 75 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 76 // CHECK-FIXES-NEXT: observe(Number); 77 // CHECK-FIXES-NEXT: } 78 79 for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) { 80 observe(*I); 81 } 82 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 83 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 84 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 85 // CHECK-FIXES-NEXT: observe(Number); 86 // CHECK-FIXES-NEXT: } 87 88 // Ensure these bad loops aren't transformed. 89 for (auto I = Numbers.rbegin(), E = Numbers.end(); I != E; ++I) { 90 observe(*I); 91 } 92 for (auto I = Numbers.begin(), E = Numbers.rend(); I != E; ++I) { 93 observe(*I); 94 } 95 } 96 97 void nonConstContainer(Reversable<int> &Numbers) { 98 for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) { 99 mutate(*I); 100 } 101 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 102 // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) { 103 // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) { 104 // CHECK-FIXES-NEXT: mutate(Number); 105 // CHECK-FIXES-NEXT: } 106 107 for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) { 108 observe(*I); 109 } 110 // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead 111 // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) { 112 // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) { 113 // CHECK-FIXES-NEXT: observe(Number); 114 // CHECK-FIXES-NEXT: } 115 } 116