Skip to content

Commit 065d343

Browse files
committed
Add a modernize-use-ranges check
1 parent f190343 commit 065d343

File tree

11 files changed

+847
-0
lines changed

11 files changed

+847
-0
lines changed

clang-tools-extra/clang-tidy/modernize/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ add_clang_library(clangTidyModernizeModule
4040
UseNoexceptCheck.cpp
4141
UseNullptrCheck.cpp
4242
UseOverrideCheck.cpp
43+
UseRangesCheck.cpp
4344
UseStartsEndsWithCheck.cpp
4445
UseStdFormatCheck.cpp
4546
UseStdNumbersCheck.cpp

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "UseNoexceptCheck.h"
4242
#include "UseNullptrCheck.h"
4343
#include "UseOverrideCheck.h"
44+
#include "UseRangesCheck.h"
4445
#include "UseStartsEndsWithCheck.h"
4546
#include "UseStdFormatCheck.h"
4647
#include "UseStdNumbersCheck.h"
@@ -75,6 +76,7 @@ class ModernizeModule : public ClangTidyModule {
7576
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
7677
CheckFactories.registerCheck<UseDesignatedInitializersCheck>(
7778
"modernize-use-designated-initializers");
79+
CheckFactories.registerCheck<UseRangesCheck>("modernize-use-ranges");
7880
CheckFactories.registerCheck<UseStartsEndsWithCheck>(
7981
"modernize-use-starts-ends-with");
8082
CheckFactories.registerCheck<UseStdFormatCheck>("modernize-use-std-format");
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//===--- UseRangesCheck.cpp - clang-tidy ----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "UseRangesCheck.h"
10+
#include "clang/AST/Decl.h"
11+
#include "llvm/ADT/ArrayRef.h"
12+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
13+
#include "llvm/ADT/SmallVector.h"
14+
#include "llvm/ADT/StringRef.h"
15+
#include <initializer_list>
16+
17+
// FixItHint - Let the docs script know that this class does provide fixits
18+
19+
namespace clang::tidy::modernize {
20+
21+
static constexpr const char *SingleRangeNames[] = {
22+
"all_of",
23+
"any_of",
24+
"none_of",
25+
"for_each",
26+
"find",
27+
"find_if",
28+
"find_if_not",
29+
"adjacent_find",
30+
"copy",
31+
"copy_if",
32+
"copy_backward",
33+
"move",
34+
"move_backward",
35+
"fill",
36+
"transform",
37+
"replace",
38+
"replace_if",
39+
"generate",
40+
"remove",
41+
"remove_if",
42+
"remove_copy",
43+
"remove_copy_if",
44+
"unique",
45+
"unique_copy",
46+
"sample",
47+
"partition_point",
48+
"lower_bound",
49+
"upper_bound",
50+
"equal_range",
51+
"binary_search",
52+
"push_heap",
53+
"pop_heap",
54+
"make_heap",
55+
"sort_heap",
56+
"next_permutation",
57+
"prev_permutation",
58+
};
59+
60+
static constexpr const char *SingleRangeWithExecNames[] = {
61+
"reverse",
62+
"reverse_copy",
63+
"shift_left",
64+
"shift_right",
65+
"is_partitioned",
66+
"partition",
67+
"partition_copy",
68+
"stable_partition",
69+
"sort",
70+
"stable_sort",
71+
"is_sorted",
72+
"is_sorted_until",
73+
"is_heap",
74+
"is_heap_until",
75+
"max_element",
76+
"min_element",
77+
"minmax_element",
78+
"uninitialized_copy",
79+
"uninitialized_fill",
80+
"uninitialized_move",
81+
"uninitialized_default_construct",
82+
"uninitialized_value_construct",
83+
"destroy",
84+
};
85+
86+
static constexpr const char *TwoRangeWithExecNames[] = {
87+
"partial_sort_copy",
88+
"includes",
89+
"set_union",
90+
"set_intersection",
91+
"set_difference",
92+
"set_symmetric_difference",
93+
"merge",
94+
"lexicographical_compare",
95+
"find_end",
96+
"search",
97+
};
98+
99+
static constexpr const char *OneOrTwoRangeNames[] = {
100+
"is_permutation",
101+
};
102+
103+
static constexpr const char *OneOrTwoRangeWithExecNames[] = {
104+
"equal",
105+
"mismatch",
106+
};
107+
108+
namespace {
109+
class StdReplacer : public utils::UseRangesCheck::Replacer {
110+
public:
111+
explicit StdReplacer(SmallVector<UseRangesCheck::Signature> Signatures)
112+
: Signatures(std::move(Signatures)) {}
113+
std::optional<std::string>
114+
getReplaceName(const NamedDecl &OriginalName) const override {
115+
return ("std::ranges::" + OriginalName.getName()).str();
116+
}
117+
ArrayRef<UseRangesCheck::Signature>
118+
getReplacementSignatures() const override {
119+
return Signatures;
120+
}
121+
122+
private:
123+
SmallVector<UseRangesCheck::Signature> Signatures;
124+
};
125+
126+
class StdAlgorithmReplacer : public StdReplacer {
127+
using StdReplacer::StdReplacer;
128+
std::optional<std::string>
129+
getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
130+
return "<algorithm>";
131+
}
132+
};
133+
134+
class StdNumericReplacer : public StdReplacer {
135+
using StdReplacer::StdReplacer;
136+
std::optional<std::string>
137+
getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
138+
return "<numeric>";
139+
}
140+
};
141+
} // namespace
142+
143+
utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {
144+
145+
utils::UseRangesCheck::ReplacerMap Result;
146+
147+
// template<typename Iter> Func(Iter first, Iter last,...).
148+
static const Signature SingleRangeArgs = {{0}};
149+
// template<typename Policy, typename Iter>
150+
// Func(Policy policy, Iter first, // Iter last,...).
151+
static const Signature SingleRangeExecPolicy = {{1}};
152+
// template<typename Iter1, typename Iter2>
153+
// Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...).
154+
static const Signature TwoRangeArgs = {{0}, {2}};
155+
// template<typename Policy, typename Iter1, typename Iter2>
156+
// Func(Policy policy, Iter1 first1, Iter1 last1, Iter2 first2, Iter2
157+
// last2,...).
158+
static const Signature TwoRangeExecPolicy = {{1}, {3}};
159+
160+
static const Signature SingleRangeFunc[] = {SingleRangeArgs};
161+
162+
static const Signature SingleRangeExecFunc[] = {SingleRangeArgs,
163+
SingleRangeExecPolicy};
164+
static const Signature TwoRangeExecFunc[] = {TwoRangeArgs,
165+
TwoRangeExecPolicy};
166+
static const Signature OneOrTwoFunc[] = {SingleRangeArgs, TwoRangeArgs};
167+
static const Signature OneOrTwoExecFunc[] = {
168+
SingleRangeArgs, SingleRangeExecPolicy, TwoRangeArgs, TwoRangeExecPolicy};
169+
170+
static const std::pair<ArrayRef<Signature>, ArrayRef<const char *>>
171+
AlgorithmNames[] = {{SingleRangeFunc, SingleRangeNames},
172+
{SingleRangeExecFunc, SingleRangeWithExecNames},
173+
{TwoRangeExecFunc, TwoRangeWithExecNames},
174+
{OneOrTwoFunc, OneOrTwoRangeNames},
175+
{OneOrTwoExecFunc, OneOrTwoRangeWithExecNames}};
176+
SmallString<64> Buff;
177+
for (const auto &[Signatures, Values] : AlgorithmNames) {
178+
auto Replacer = llvm::makeIntrusiveRefCnt<StdAlgorithmReplacer>(
179+
SmallVector<UseRangesCheck::Signature>{Signatures});
180+
for (const auto &Name : Values) {
181+
Buff.assign({"::std::", Name});
182+
Result.try_emplace(Buff, Replacer);
183+
}
184+
}
185+
if (getLangOpts().CPlusPlus23)
186+
Result.try_emplace(
187+
"::std::iota",
188+
llvm::makeIntrusiveRefCnt<StdNumericReplacer>(
189+
SmallVector<UseRangesCheck::Signature>{std::begin(SingleRangeFunc),
190+
std::end(SingleRangeFunc)}));
191+
return Result;
192+
}
193+
194+
bool UseRangesCheck::isLanguageVersionSupported(
195+
const LangOptions &LangOpts) const {
196+
return LangOpts.CPlusPlus20;
197+
}
198+
ArrayRef<std::pair<StringRef, StringRef>>
199+
UseRangesCheck::getFreeBeginEndMethods() const {
200+
static const std::pair<StringRef, StringRef> Refs[] = {
201+
{"::std::begin", "::std::end"}, {"::std::cbegin", "::std::cend"}};
202+
return Refs;
203+
}
204+
} // namespace clang::tidy::modernize
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===--- UseRangesCheck.h - clang-tidy --------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USERANGESCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USERANGESCHECK_H
11+
12+
#include "../utils/UseRangesCheck.h"
13+
14+
namespace clang::tidy::modernize {
15+
16+
/// Detects calls to standard library iterator algorithms that could be
17+
/// replaced with a ranges version instead
18+
///
19+
/// For the user-facing documentation see:
20+
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-ranges.html
21+
class UseRangesCheck : public utils::UseRangesCheck {
22+
public:
23+
using utils::UseRangesCheck::UseRangesCheck;
24+
25+
ReplacerMap getReplacerMap() const override;
26+
ArrayRef<std::pair<StringRef, StringRef>>
27+
getFreeBeginEndMethods() const override;
28+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
29+
};
30+
31+
} // namespace clang::tidy::modernize
32+
33+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USERANGESCHECK_H

clang-tools-extra/clang-tidy/utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_clang_library(clangTidyUtils
2525
RenamerClangTidyCheck.cpp
2626
TransformerClangTidyCheck.cpp
2727
TypeTraits.cpp
28+
UseRangesCheck.cpp
2829
UsingInserter.cpp
2930

3031
LINK_LIBS

0 commit comments

Comments
 (0)