xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-reverse.cpp (revision e8a3ddafe063c970df9c23e803812369abde4c82)
189a1d03eSRichard // RUN: %check_clang_tidy -std=c++20 -check-suffixes=,RANGES %s modernize-loop-convert %t
289a1d03eSRichard 
389a1d03eSRichard // RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-SYS %s modernize-loop-convert %t -- \
4*e8a3ddafSNathan James // RUN:   -config="{CheckOptions: { \
5*e8a3ddafSNathan James // RUN:   modernize-loop-convert.MakeReverseRangeFunction: 'llvm::reverse', \
6*e8a3ddafSNathan James // RUN:   modernize-loop-convert.MakeReverseRangeHeader: 'llvm/ADT/STLExtras.h'}}"
789a1d03eSRichard 
889a1d03eSRichard // RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-SYS %s modernize-loop-convert %t -- \
9*e8a3ddafSNathan James // RUN:   -config="{CheckOptions: { \
10*e8a3ddafSNathan James // RUN:   modernize-loop-convert.MakeReverseRangeFunction: 'llvm::reverse', \
11*e8a3ddafSNathan James // RUN:   modernize-loop-convert.MakeReverseRangeHeader: '<llvm/ADT/STLExtras.h>'}}"
1289a1d03eSRichard 
1389a1d03eSRichard // RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-HEADER %s modernize-loop-convert %t -- \
14*e8a3ddafSNathan James // RUN:   -config="{CheckOptions: { \
15*e8a3ddafSNathan James // RUN:   modernize-loop-convert.MakeReverseRangeFunction: 'llvm::reverse'}}"
1689a1d03eSRichard 
1789a1d03eSRichard // Ensure the check doesn't transform reverse loops when not in c++20 mode or
1889a1d03eSRichard // when UseCxx20ReverseRanges has been disabled
1989a1d03eSRichard // RUN: clang-tidy %s -checks=-*,modernize-loop-convert -- -std=c++17 | count 0
2089a1d03eSRichard 
2189a1d03eSRichard // RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: \
22*e8a3ddafSNathan James // RUN:     {modernize-loop-convert.UseCxx20ReverseRanges: 'false'} \
2389a1d03eSRichard // RUN:     }" -- -std=c++20 | count 0
2489a1d03eSRichard 
2589a1d03eSRichard // Ensure we get a warning if we supply the header argument without the
2689a1d03eSRichard // function argument.
27*e8a3ddafSNathan James // RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: { \
28*e8a3ddafSNathan James // RUN:   modernize-loop-convert.MakeReverseRangeHeader: 'llvm/ADT/STLExtras.h'}}" \
2989a1d03eSRichard // RUN: -- -std=c++17 2>&1 \
3089a1d03eSRichard // RUN:   | FileCheck %s -check-prefix=CHECK-HEADER-NO-FUNC \
3189a1d03eSRichard // RUN:       -implicit-check-not="{{warning|error}}:"
3289a1d03eSRichard 
3389a1d03eSRichard // CHECK-HEADER-NO-FUNC: warning: modernize-loop-convert: 'MakeReverseRangeHeader' is set but 'MakeReverseRangeFunction' is not, disabling reverse loop transformation
3489a1d03eSRichard 
3589a1d03eSRichard // Make sure appropiate headers are included
3689a1d03eSRichard // CHECK-FIXES-RANGES: #include <ranges>
3789a1d03eSRichard // CHECK-FIXES-CUSTOM-NO-SYS: #include "llvm/ADT/STLExtras.h"
3889a1d03eSRichard // CHECK-FIXES-CUSTOM-SYS: #include <llvm/ADT/STLExtras.h>
3989a1d03eSRichard 
4089a1d03eSRichard // Make sure no header is included in this example
4189a1d03eSRichard // CHECK-FIXES-CUSTOM-NO-HEADER-NOT: #include
4289a1d03eSRichard 
436a1f8ef8SChris Cotter namespace ADL {
446a1f8ef8SChris Cotter 
4589a1d03eSRichard template <typename T>
4689a1d03eSRichard struct Reversable {
4789a1d03eSRichard   using iterator = T *;
4889a1d03eSRichard   using const_iterator = const T *;
4989a1d03eSRichard 
5089a1d03eSRichard   iterator begin();
5189a1d03eSRichard   iterator end();
5289a1d03eSRichard   iterator rbegin();
5389a1d03eSRichard   iterator rend();
5489a1d03eSRichard 
5589a1d03eSRichard   const_iterator begin() const;
5689a1d03eSRichard   const_iterator end() const;
5789a1d03eSRichard   const_iterator rbegin() const;
5889a1d03eSRichard   const_iterator rend() const;
5989a1d03eSRichard 
6089a1d03eSRichard   const_iterator cbegin() const;
6189a1d03eSRichard   const_iterator cend() const;
6289a1d03eSRichard   const_iterator crbegin() const;
6389a1d03eSRichard   const_iterator crend() const;
6489a1d03eSRichard };
6589a1d03eSRichard 
666a1f8ef8SChris Cotter template <typename C>
rbegin(C & c)676a1f8ef8SChris Cotter constexpr auto rbegin(C& c) -> decltype(c.rbegin()) { return c.rbegin(); }
686a1f8ef8SChris Cotter template <typename C>
rend(C & c)696a1f8ef8SChris Cotter constexpr auto rend(C& c) -> decltype(c.rend()) { return c.rend(); }
706a1f8ef8SChris Cotter template <typename C>
rbegin(const C & c)716a1f8ef8SChris Cotter constexpr auto rbegin(const C& c) -> decltype(c.rbegin()) { return c.rbegin(); }
726a1f8ef8SChris Cotter template <typename C>
rend(const C & c)736a1f8ef8SChris Cotter constexpr auto rend(const C& c) -> decltype(c.rend()) { return c.rend(); }
746a1f8ef8SChris Cotter 
756a1f8ef8SChris Cotter template <typename C>
766a1f8ef8SChris Cotter constexpr auto crbegin(C& c) -> decltype(c.crbegin());
776a1f8ef8SChris Cotter template <typename C>
786a1f8ef8SChris Cotter constexpr auto crend(C& c) -> decltype(c.crend());
796a1f8ef8SChris Cotter template <typename C>
806a1f8ef8SChris Cotter constexpr auto crbegin(const C& c) -> decltype(c.crbegin());
816a1f8ef8SChris Cotter template <typename C>
826a1f8ef8SChris Cotter constexpr auto crend(const C& c) -> decltype(c.crend());
836a1f8ef8SChris Cotter 
846a1f8ef8SChris Cotter } // namespace ADL
856a1f8ef8SChris Cotter 
866a1f8ef8SChris Cotter using ADL::Reversable;
876a1f8ef8SChris Cotter 
8889a1d03eSRichard template <typename T>
8989a1d03eSRichard void observe(const T &);
9089a1d03eSRichard template <typename T>
9189a1d03eSRichard void mutate(T &);
9289a1d03eSRichard 
constContainer(const Reversable<int> & Numbers)9389a1d03eSRichard void constContainer(const Reversable<int> &Numbers) {
9489a1d03eSRichard   for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) {
9589a1d03eSRichard     observe(*I);
9689a1d03eSRichard   }
9789a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
9889a1d03eSRichard   // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
9989a1d03eSRichard   // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
10089a1d03eSRichard   //   CHECK-FIXES-NEXT:   observe(Number);
10189a1d03eSRichard   //   CHECK-FIXES-NEXT: }
10289a1d03eSRichard 
10389a1d03eSRichard   for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) {
10489a1d03eSRichard     observe(*I);
10589a1d03eSRichard   }
10689a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
10789a1d03eSRichard   // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
10889a1d03eSRichard   // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
10989a1d03eSRichard   //   CHECK-FIXES-NEXT:   observe(Number);
11089a1d03eSRichard   //   CHECK-FIXES-NEXT: }
11189a1d03eSRichard 
1126a1f8ef8SChris Cotter   for (auto I = rbegin(Numbers), E = rend(Numbers); I != E; ++I) {
1136a1f8ef8SChris Cotter     observe(*I);
1146a1f8ef8SChris Cotter   }
1156a1f8ef8SChris Cotter   // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
1166a1f8ef8SChris Cotter   // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
1176a1f8ef8SChris Cotter   // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
1186a1f8ef8SChris Cotter   //   CHECK-FIXES-NEXT:   observe(Number);
1196a1f8ef8SChris Cotter   //   CHECK-FIXES-NEXT: }
1206a1f8ef8SChris Cotter 
1216a1f8ef8SChris Cotter   for (auto I = crbegin(Numbers), E = crend(Numbers); I != E; ++I) {
1226a1f8ef8SChris Cotter     observe(*I);
1236a1f8ef8SChris Cotter   }
1246a1f8ef8SChris Cotter   // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
1256a1f8ef8SChris Cotter   // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
1266a1f8ef8SChris Cotter   // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
1276a1f8ef8SChris Cotter   //   CHECK-FIXES-NEXT:   observe(Number);
1286a1f8ef8SChris Cotter   //   CHECK-FIXES-NEXT: }
1296a1f8ef8SChris Cotter 
13089a1d03eSRichard   // Ensure these bad loops aren't transformed.
13189a1d03eSRichard   for (auto I = Numbers.rbegin(), E = Numbers.end(); I != E; ++I) {
13289a1d03eSRichard     observe(*I);
13389a1d03eSRichard   }
13489a1d03eSRichard   for (auto I = Numbers.begin(), E = Numbers.rend(); I != E; ++I) {
13589a1d03eSRichard     observe(*I);
13689a1d03eSRichard   }
13789a1d03eSRichard }
13889a1d03eSRichard 
nonConstContainer(Reversable<int> & Numbers)13989a1d03eSRichard void nonConstContainer(Reversable<int> &Numbers) {
14089a1d03eSRichard   for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) {
14189a1d03eSRichard     mutate(*I);
14289a1d03eSRichard   }
14389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
14489a1d03eSRichard   // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) {
14589a1d03eSRichard   // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) {
14689a1d03eSRichard   //   CHECK-FIXES-NEXT:   mutate(Number);
14789a1d03eSRichard   //   CHECK-FIXES-NEXT: }
14889a1d03eSRichard 
14989a1d03eSRichard   for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) {
15089a1d03eSRichard     observe(*I);
15189a1d03eSRichard   }
15289a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
15389a1d03eSRichard   // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
15489a1d03eSRichard   // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
15589a1d03eSRichard   //   CHECK-FIXES-NEXT:   observe(Number);
15689a1d03eSRichard   //   CHECK-FIXES-NEXT: }
1576a1f8ef8SChris Cotter 
1586a1f8ef8SChris Cotter   for (auto I = rbegin(Numbers), E = rend(Numbers); I != E; ++I) {
1596a1f8ef8SChris Cotter     mutate(*I);
1606a1f8ef8SChris Cotter   }
1616a1f8ef8SChris Cotter   // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
1626a1f8ef8SChris Cotter   // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) {
1636a1f8ef8SChris Cotter   // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) {
1646a1f8ef8SChris Cotter   //   CHECK-FIXES-NEXT:   mutate(Number);
1656a1f8ef8SChris Cotter   //   CHECK-FIXES-NEXT: }
16689a1d03eSRichard }
167