File: loop-convert-reverse.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,998,520 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (166 lines) | stat: -rw-r--r-- 6,557 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// RUN: %check_clang_tidy -std=c++20 -check-suffixes=,RANGES %s modernize-loop-convert %t

// RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-SYS %s modernize-loop-convert %t -- \
// RUN:   -config="{CheckOptions: { \
// RUN:   modernize-loop-convert.MakeReverseRangeFunction: 'llvm::reverse', \
// RUN:   modernize-loop-convert.MakeReverseRangeHeader: 'llvm/ADT/STLExtras.h'}}"

// RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-SYS %s modernize-loop-convert %t -- \
// RUN:   -config="{CheckOptions: { \
// RUN:   modernize-loop-convert.MakeReverseRangeFunction: 'llvm::reverse', \
// RUN:   modernize-loop-convert.MakeReverseRangeHeader: '<llvm/ADT/STLExtras.h>'}}"

// RUN: %check_clang_tidy -check-suffixes=,CUSTOM,CUSTOM-NO-HEADER %s modernize-loop-convert %t -- \
// RUN:   -config="{CheckOptions: { \
// RUN:   modernize-loop-convert.MakeReverseRangeFunction: 'llvm::reverse'}}"

// Ensure the check doesn't transform reverse loops when not in c++20 mode or
// when UseCxx20ReverseRanges has been disabled
// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -- -std=c++17 | count 0

// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: \
// RUN:     {modernize-loop-convert.UseCxx20ReverseRanges: 'false'} \
// RUN:     }" -- -std=c++20 | count 0

// Ensure we get a warning if we supply the header argument without the
// function argument.
// RUN: clang-tidy %s -checks=-*,modernize-loop-convert -config="{CheckOptions: { \
// RUN:   modernize-loop-convert.MakeReverseRangeHeader: 'llvm/ADT/STLExtras.h'}}" \
// RUN: -- -std=c++17 2>&1 \
// RUN:   | FileCheck %s -check-prefix=CHECK-HEADER-NO-FUNC \
// RUN:       -implicit-check-not="{{warning|error}}:"

// CHECK-HEADER-NO-FUNC: warning: modernize-loop-convert: 'MakeReverseRangeHeader' is set but 'MakeReverseRangeFunction' is not, disabling reverse loop transformation

// Make sure appropiate headers are included
// CHECK-FIXES-RANGES: #include <ranges>
// CHECK-FIXES-CUSTOM-NO-SYS: #include "llvm/ADT/STLExtras.h"
// CHECK-FIXES-CUSTOM-SYS: #include <llvm/ADT/STLExtras.h>

// Make sure no header is included in this example
// CHECK-FIXES-CUSTOM-NO-HEADER-NOT: #include

namespace ADL {

template <typename T>
struct Reversable {
  using iterator = T *;
  using const_iterator = const T *;

  iterator begin();
  iterator end();
  iterator rbegin();
  iterator rend();

  const_iterator begin() const;
  const_iterator end() const;
  const_iterator rbegin() const;
  const_iterator rend() const;

  const_iterator cbegin() const;
  const_iterator cend() const;
  const_iterator crbegin() const;
  const_iterator crend() const;
};

template <typename C>
constexpr auto rbegin(C& c) -> decltype(c.rbegin()) { return c.rbegin(); }
template <typename C>
constexpr auto rend(C& c) -> decltype(c.rend()) { return c.rend(); }
template <typename C>
constexpr auto rbegin(const C& c) -> decltype(c.rbegin()) { return c.rbegin(); }
template <typename C>
constexpr auto rend(const C& c) -> decltype(c.rend()) { return c.rend(); }

template <typename C>
constexpr auto crbegin(C& c) -> decltype(c.crbegin());
template <typename C>
constexpr auto crend(C& c) -> decltype(c.crend());
template <typename C>
constexpr auto crbegin(const C& c) -> decltype(c.crbegin());
template <typename C>
constexpr auto crend(const C& c) -> decltype(c.crend());

} // namespace ADL

using ADL::Reversable;

template <typename T>
void observe(const T &);
template <typename T>
void mutate(T &);

void constContainer(const Reversable<int> &Numbers) {
  for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) {
    observe(*I);
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
  // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
  // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
  //   CHECK-FIXES-NEXT:   observe(Number);
  //   CHECK-FIXES-NEXT: }

  for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) {
    observe(*I);
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
  // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
  // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
  //   CHECK-FIXES-NEXT:   observe(Number);
  //   CHECK-FIXES-NEXT: }

  for (auto I = rbegin(Numbers), E = rend(Numbers); I != E; ++I) {
    observe(*I);
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
  // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
  // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
  //   CHECK-FIXES-NEXT:   observe(Number);
  //   CHECK-FIXES-NEXT: }

  for (auto I = crbegin(Numbers), E = crend(Numbers); I != E; ++I) {
    observe(*I);
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
  // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
  // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
  //   CHECK-FIXES-NEXT:   observe(Number);
  //   CHECK-FIXES-NEXT: }

  // Ensure these bad loops aren't transformed.
  for (auto I = Numbers.rbegin(), E = Numbers.end(); I != E; ++I) {
    observe(*I);
  }
  for (auto I = Numbers.begin(), E = Numbers.rend(); I != E; ++I) {
    observe(*I);
  }
}

void nonConstContainer(Reversable<int> &Numbers) {
  for (auto I = Numbers.rbegin(), E = Numbers.rend(); I != E; ++I) {
    mutate(*I);
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
  // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) {
  // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) {
  //   CHECK-FIXES-NEXT:   mutate(Number);
  //   CHECK-FIXES-NEXT: }

  for (auto I = Numbers.crbegin(), E = Numbers.crend(); I != E; ++I) {
    observe(*I);
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
  // CHECK-FIXES-RANGES: for (int Number : std::ranges::reverse_view(Numbers)) {
  // CHECK-FIXES-CUSTOM: for (int Number : llvm::reverse(Numbers)) {
  //   CHECK-FIXES-NEXT:   observe(Number);
  //   CHECK-FIXES-NEXT: }

  for (auto I = rbegin(Numbers), E = rend(Numbers); I != E; ++I) {
    mutate(*I);
  }
  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
  // CHECK-FIXES-RANGES: for (int & Number : std::ranges::reverse_view(Numbers)) {
  // CHECK-FIXES-CUSTOM: for (int & Number : llvm::reverse(Numbers)) {
  //   CHECK-FIXES-NEXT:   mutate(Number);
  //   CHECK-FIXES-NEXT: }
}