Skip to content

Commit 6294771

Browse files
njames93yuxuanchen1997
authored andcommitted
[clang-tidy] Allow specifying pipe syntax for use-ranges checks (#98696)
Summary: Add `UseReversePipe` option to (boost|modernize)-use-ranges checks. This controls whether to create a reverse view using function syntax (`reverse(Range)`) or pipe syntax (`Range | reverse`) Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251675
1 parent 23e1e14 commit 6294771

File tree

15 files changed

+358
-237
lines changed

15 files changed

+358
-237
lines changed

clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,15 @@ utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {
331331

332332
UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context)
333333
: utils::UseRangesCheck(Name, Context),
334-
IncludeBoostSystem(Options.get("IncludeBoostSystem", true)) {}
334+
IncludeBoostSystem(Options.get("IncludeBoostSystem", true)),
335+
UseReversePipe(Options.get("UseReversePipe", false)) {}
335336

336337
void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
337338
utils::UseRangesCheck::storeOptions(Opts);
338339
Options.store(Opts, "IncludeBoostSystem", IncludeBoostSystem);
340+
Options.store(Opts, "UseReversePipe", UseReversePipe);
339341
}
342+
340343
DiagnosticBuilder UseRangesCheck::createDiag(const CallExpr &Call) {
341344
DiagnosticBuilder D =
342345
diag(Call.getBeginLoc(), "use a %0 version of this algorithm");
@@ -362,10 +365,10 @@ UseRangesCheck::getReverseDescriptor() const {
362365
{"::boost::rbegin", "::boost::rend"},
363366
{"::boost::const_rbegin", "::boost::const_rend"},
364367
};
365-
return ReverseIteratorDescriptor{"boost::adaptors::reverse",
366-
IncludeBoostSystem
367-
? "<boost/range/adaptor/reversed.hpp>"
368-
: "boost/range/adaptor/reversed.hpp",
369-
Refs};
368+
return ReverseIteratorDescriptor{
369+
UseReversePipe ? "boost::adaptors::reversed" : "boost::adaptors::reverse",
370+
IncludeBoostSystem ? "<boost/range/adaptor/reversed.hpp>"
371+
: "boost/range/adaptor/reversed.hpp",
372+
Refs, UseReversePipe};
370373
}
371374
} // namespace clang::tidy::boost

clang-tools-extra/clang-tidy/boost/UseRangesCheck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class UseRangesCheck : public utils::UseRangesCheck {
3636

3737
private:
3838
bool IncludeBoostSystem;
39+
bool UseReversePipe;
3940
};
4041

4142
} // namespace clang::tidy::boost

clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,15 @@ utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {
166166
return Result;
167167
}
168168

169+
UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context)
170+
: utils::UseRangesCheck(Name, Context),
171+
UseReversePipe(Options.get("UseReversePipe", false)) {}
172+
173+
void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
174+
utils::UseRangesCheck::storeOptions(Opts);
175+
Options.store(Opts, "UseReversePipe", UseReversePipe);
176+
}
177+
169178
bool UseRangesCheck::isLanguageVersionSupported(
170179
const LangOptions &LangOpts) const {
171180
return LangOpts.CPlusPlus20;
@@ -180,6 +189,8 @@ std::optional<UseRangesCheck::ReverseIteratorDescriptor>
180189
UseRangesCheck::getReverseDescriptor() const {
181190
static const std::pair<StringRef, StringRef> Refs[] = {
182191
{"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}};
183-
return ReverseIteratorDescriptor{"std::views::reverse", "<ranges>", Refs};
192+
return ReverseIteratorDescriptor{UseReversePipe ? "std::views::reverse"
193+
: "std::ranges::reverse_view",
194+
"<ranges>", Refs, UseReversePipe};
184195
}
185196
} // namespace clang::tidy::modernize

clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ namespace clang::tidy::modernize {
2020
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-ranges.html
2121
class UseRangesCheck : public utils::UseRangesCheck {
2222
public:
23-
using utils::UseRangesCheck::UseRangesCheck;
23+
UseRangesCheck(StringRef CheckName, ClangTidyContext *Context);
24+
25+
void storeOptions(ClangTidyOptions::OptionMap &Options) override;
2426

2527
ReplacerMap getReplacerMap() const override;
2628

@@ -31,6 +33,9 @@ class UseRangesCheck : public utils::UseRangesCheck {
3133
getReverseDescriptor() const override;
3234

3335
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
36+
37+
private:
38+
bool UseReversePipe;
3439
};
3540

3641
} // namespace clang::tidy::modernize

clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,16 +242,20 @@ void UseRangesCheck::check(const MatchFinder::MatchResult &Result) {
242242
Diag << Inserter.createIncludeInsertion(
243243
Result.SourceManager->getFileID(Call->getBeginLoc()),
244244
*ReverseDescriptor->ReverseHeader);
245+
StringRef ArgText = Lexer::getSourceText(
246+
CharSourceRange::getTokenRange(ArgExpr->getSourceRange()),
247+
Result.Context->getSourceManager(), Result.Context->getLangOpts());
248+
SmallString<128> ReplaceText;
249+
if (ReverseDescriptor->IsPipeSyntax)
250+
ReplaceText.assign(
251+
{ArgText, " | ", ReverseDescriptor->ReverseAdaptorName});
252+
else
253+
ReplaceText.assign(
254+
{ReverseDescriptor->ReverseAdaptorName, "(", ArgText, ")"});
245255
Diag << FixItHint::CreateReplacement(
246256
Call->getArg(Replace == Indexes::Second ? Second : First)
247257
->getSourceRange(),
248-
SmallString<128>{
249-
ReverseDescriptor->ReverseAdaptorName, "(",
250-
Lexer::getSourceText(
251-
CharSourceRange::getTokenRange(ArgExpr->getSourceRange()),
252-
Result.Context->getSourceManager(),
253-
Result.Context->getLangOpts()),
254-
")"});
258+
ReplaceText);
255259
}
256260
ToRemove.push_back(Replace == Indexes::Second ? First : Second);
257261
}

clang-tools-extra/clang-tidy/utils/UseRangesCheck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class UseRangesCheck : public ClangTidyCheck {
3838
StringRef ReverseAdaptorName;
3939
std::optional<StringRef> ReverseHeader;
4040
ArrayRef<std::pair<StringRef, StringRef>> FreeReverseNames;
41+
bool IsPipeSyntax = false;
4142
};
4243

4344
class Replacer : public llvm::RefCountedBase<Replacer> {

clang-tools-extra/docs/clang-tidy/checks/boost/use-ranges.rst

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ Transforms to:
154154

155155
.. code-block:: c++
156156

157-
auto AreSame = std::equal(boost::adaptors::reverse(Items1),
158-
boost::adaptors::reverse(Items2));
157+
auto AreSame = boost::range::equal(boost::adaptors::reverse(Items1),
158+
boost::adaptors::reverse(Items2));
159159

160160
Options
161161
-------
@@ -170,3 +170,18 @@ Options
170170
If `true` (default value) the boost headers are included as system headers
171171
with angle brackets (`#include <boost.hpp>`), otherwise quotes are used
172172
(`#include "boost.hpp"`).
173+
174+
.. option:: UseReversePipe
175+
176+
When `true` (default `false`), fixes which involve reverse ranges will use the
177+
pipe adaptor syntax instead of the function syntax.
178+
179+
.. code-block:: c++
180+
181+
std::find(Items.rbegin(), Items.rend(), 0);
182+
183+
Transforms to:
184+
185+
.. code-block:: c++
186+
187+
boost::range::find(Items | boost::adaptors::reversed, 0);

clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ Transforms to:
116116

117117
.. code-block:: c++
118118

119-
auto AreSame = std::equal(std::views::reverse(Items1),
120-
std::views::reverse(Items2));
119+
auto AreSame = std::ranges::equal(std::ranges::reverse_view(Items1),
120+
std::ranges::reverse_view(Items2));
121121

122122
Options
123123
-------
@@ -127,3 +127,17 @@ Options
127127
A string specifying which include-style is used, `llvm` or `google`. Default
128128
is `llvm`.
129129

130+
.. option:: UseReversePipe
131+
132+
When `true` (default `false`), fixes which involve reverse ranges will use the
133+
pipe adaptor syntax instead of the function syntax.
134+
135+
.. code-block:: c++
136+
137+
std::find(Items.rbegin(), Items.rend(), 0);
138+
139+
Transforms to:
140+
141+
.. code-block:: c++
142+
143+
std::ranges::find(Items | std::views::reverse, 0);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef USE_RANGES_FAKE_BOOST_H
2+
#define USE_RANGES_FAKE_BOOST_H
3+
4+
namespace boost {
5+
namespace range_adl_barrier {
6+
7+
template <typename T> void *begin(T &);
8+
template <typename T> void *end(T &);
9+
template <typename T> void *const_begin(const T &);
10+
template <typename T> void *const_end(const T &);
11+
} // namespace range_adl_barrier
12+
13+
using namespace range_adl_barrier;
14+
15+
template <typename T> void *rbegin(T &);
16+
template <typename T> void *rend(T &);
17+
18+
template <typename T> void *const_rbegin(T &);
19+
template <typename T> void *const_rend(T &);
20+
namespace algorithm {
21+
22+
template <class InputIterator, class T, class BinaryOperation>
23+
T reduce(InputIterator first, InputIterator last, T init, BinaryOperation bOp) {
24+
return init;
25+
}
26+
} // namespace algorithm
27+
} // namespace boost
28+
29+
#endif // USE_RANGES_FAKE_BOOST_H
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#ifndef USE_RANGES_FAKE_STD_H
2+
#define USE_RANGES_FAKE_STD_H
3+
namespace std {
4+
5+
template <typename T> class vector {
6+
public:
7+
using iterator = T *;
8+
using const_iterator = const T *;
9+
using reverse_iterator = T*;
10+
using reverse_const_iterator = const T*;
11+
12+
constexpr const_iterator begin() const;
13+
constexpr const_iterator end() const;
14+
constexpr const_iterator cbegin() const;
15+
constexpr const_iterator cend() const;
16+
constexpr iterator begin();
17+
constexpr iterator end();
18+
constexpr reverse_const_iterator rbegin() const;
19+
constexpr reverse_const_iterator rend() const;
20+
constexpr reverse_const_iterator crbegin() const;
21+
constexpr reverse_const_iterator crend() const;
22+
constexpr reverse_iterator rbegin();
23+
constexpr reverse_iterator rend();
24+
};
25+
26+
template <typename Container> constexpr auto begin(const Container &Cont) {
27+
return Cont.begin();
28+
}
29+
30+
template <typename Container> constexpr auto begin(Container &Cont) {
31+
return Cont.begin();
32+
}
33+
34+
template <typename Container> constexpr auto end(const Container &Cont) {
35+
return Cont.end();
36+
}
37+
38+
template <typename Container> constexpr auto end(Container &Cont) {
39+
return Cont.end();
40+
}
41+
42+
template <typename Container> constexpr auto cbegin(const Container &Cont) {
43+
return Cont.cbegin();
44+
}
45+
46+
template <typename Container> constexpr auto cend(const Container &Cont) {
47+
return Cont.cend();
48+
}
49+
// Find
50+
template< class InputIt, class T >
51+
InputIt find(InputIt first, InputIt last, const T& value);
52+
53+
template <typename Iter> void reverse(Iter begin, Iter end);
54+
55+
template <class InputIt1, class InputIt2>
56+
bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2);
57+
58+
template <class ForwardIt1, class ForwardIt2>
59+
bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2,
60+
ForwardIt2 last2);
61+
62+
template <class BidirIt>
63+
bool next_permutation(BidirIt first, BidirIt last);
64+
65+
inline namespace inline_test{
66+
67+
template <class ForwardIt1, class ForwardIt2>
68+
bool equal(ForwardIt1 first1, ForwardIt1 last1,
69+
ForwardIt2 first2, ForwardIt2 last2);
70+
71+
template <class RandomIt>
72+
void push_heap(RandomIt first, RandomIt last);
73+
74+
template <class InputIt, class OutputIt, class UnaryPred>
75+
OutputIt copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPred pred);
76+
77+
template <class ForwardIt>
78+
ForwardIt is_sorted_until(ForwardIt first, ForwardIt last);
79+
80+
template <class InputIt>
81+
void reduce(InputIt first, InputIt last);
82+
83+
template <class InputIt, class T>
84+
T reduce(InputIt first, InputIt last, T init);
85+
86+
template <class InputIt, class T, class BinaryOp>
87+
T reduce(InputIt first, InputIt last, T init, BinaryOp op) {
88+
// Need a definition to suppress undefined_internal_type when invoked with lambda
89+
return init;
90+
}
91+
92+
template <class InputIt, class T>
93+
T accumulate(InputIt first, InputIt last, T init);
94+
95+
} // namespace inline_test
96+
97+
} // namespace std
98+
99+
#endif // USE_RANGES_FAKE_STD_H
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %check_clang_tidy -std=c++14 %s boost-use-ranges %t -check-suffixes=,PIPE \
2+
// RUN: -config="{CheckOptions: { \
3+
// RUN: boost-use-ranges.UseReversePipe: true }}" -- -I %S/Inputs/use-ranges/
4+
// RUN: %check_clang_tidy -std=c++14 %s boost-use-ranges %t -check-suffixes=,NOPIPE -- -I %S/Inputs/use-ranges/
5+
6+
// CHECK-FIXES: #include <boost/algorithm/cxx11/is_sorted.hpp>
7+
// CHECK-FIXES: #include <boost/range/adaptor/reversed.hpp>
8+
9+
#include "fake_std.h"
10+
11+
void stdLib() {
12+
std::vector<int> I;
13+
std::is_sorted_until(I.rbegin(), I.rend());
14+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use a boost version of this algorithm
15+
// CHECK-FIXES-NOPIPE: boost::algorithm::is_sorted_until(boost::adaptors::reverse(I));
16+
// CHECK-FIXES-PIPE: boost::algorithm::is_sorted_until(I | boost::adaptors::reversed);
17+
18+
}

0 commit comments

Comments
 (0)