clang-tools 24.0.0git
modernize/UseRangesCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
19namespace clang::tidy::modernize {
20
21static constexpr const char *SingleRangeNames[] = {
22 "all_of",
23 "any_of",
24 "none_of",
25 "find",
26 "find_if",
27 "find_if_not",
28 "adjacent_find",
29 "fill",
30 "replace",
31 "replace_if",
32 "generate",
33 "sample",
34 "partition_point",
35 "lower_bound",
36 "upper_bound",
37 "binary_search",
38 "push_heap",
39 "pop_heap",
40 "make_heap",
41 "sort_heap",
42 "next_permutation",
43 "prev_permutation",
44 "reverse",
45 "shift_left",
46 "shift_right",
47 "is_partitioned",
48 "sort",
49 "stable_sort",
50 "is_sorted",
51 "is_sorted_until",
52 "is_heap",
53 "is_heap_until",
54 "max_element",
55 "min_element",
56 "uninitialized_fill",
57 "uninitialized_default_construct",
58 "uninitialized_value_construct",
59 "destroy",
60};
61
62static constexpr const char *SingleRangeBeginResultNames[] = {
63 "remove", "remove_if", "stable_partition", "partition", "unique"};
64
65static constexpr const char *SingleRangeOutResultNames[] = {
66 "copy", "copy_if", "copy_backward", "move",
67 "move_backward", "remove_copy", "remove_copy_if", "reverse_copy",
68 "transform", "unique_copy", "uninitialized_copy", "uninitialized_move",
69};
70
71static constexpr const char *SingleRangeFunctionResultNames[] = {"for_each"};
72
73static constexpr const char *SingleRangeStructuredBindingNames[] = {
74 "equal_range", "minmax_element"};
75
76static constexpr const char *SingleRangeDiagnosticOnlyNames[] = {
77 "partition_copy"};
78
79static constexpr const char *TwoRangeNames[] = {
80 "equal", "includes", "lexicographical_compare",
81 "find_end", "search", "is_permutation",
82};
83
84static constexpr const char *TwoRangeOutResultNames[] = {
85 "merge",
86 "partial_sort_copy",
87 "set_difference",
88 "set_intersection",
89 "set_symmetric_difference",
90 "set_union",
91};
92
93static constexpr const char *TwoRangeStructuredBindingNames[] = {"mismatch"};
94
95static constexpr const char *SinglePivotRangeNames[] = {"inplace_merge"};
96
97static constexpr const char *SinglePivotRangeBeginResultNames[] = {"rotate"};
98
99static constexpr const char *SinglePivotRangeOutResultNames[] = {"rotate_copy"};
100
101namespace {
102class StdReplacer : public utils::UseRangesCheck::Replacer {
103public:
105
106 explicit StdReplacer(SmallVector<UseRangesCheck::Signature> Signatures,
107 ResultUsePolicy ResultPolicy = {})
108 : Signatures(std::move(Signatures)), ResultPolicy(ResultPolicy) {}
109 std::optional<std::string>
110 getReplaceName(const NamedDecl &OriginalName) const override {
111 return ("std::ranges::" + OriginalName.getName()).str();
112 }
113 ArrayRef<UseRangesCheck::Signature>
114 getReplacementSignatures() const override {
115 return Signatures;
116 }
117 ResultUsePolicy getResultUsePolicy(const NamedDecl &, bool) const override {
118 return ResultPolicy;
119 }
120
121private:
122 SmallVector<UseRangesCheck::Signature> Signatures;
123 ResultUsePolicy ResultPolicy;
124};
125
126class 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
134class 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
145
146 // template<typename Iter> Func(Iter first, Iter last,...).
147 static const Signature SingleRangeArgs = {{0}};
148 // template<typename Iter1, typename Iter2>
149 // Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...).
150 static const Signature TwoRangeArgs = {{0}, {2}};
151
152 // template<typename Iter> Func(Iter first, Iter pivot, Iter last,...).
153 static const Signature SinglePivotRange = {{0, 2}};
154
155 static const Signature SingleRangeFunc[] = {SingleRangeArgs};
156
157 static const Signature TwoRangeFunc[] = {TwoRangeArgs};
158
159 static const Signature SinglePivotFunc[] = {SinglePivotRange};
160
161 using ResultPolicy = StdReplacer::ResultUsePolicy;
162 using PolicyKind = ResultPolicy::Kind;
163 const ResultPolicy DefaultPolicy;
164 const ResultPolicy BeginResultPolicy = {
165 PolicyKind::AppendAccessorForUsedResult, ".begin()"};
166 const ResultPolicy OutResultPolicy = {PolicyKind::AppendAccessorForUsedResult,
167 ".out"};
168 const ResultPolicy FunctionResultPolicy = {
169 PolicyKind::AppendAccessorForUsedResult, ".fun"};
170 const ResultPolicy StructuredBindingPolicy = {
171 PolicyKind::KeepFixItOnlyForStructuredBinding, {}};
172 const ResultPolicy DiagnosticOnlyPolicy = {
173 PolicyKind::SuppressFixItForUsedResult, {}};
174
175 struct AlgorithmGroup {
176 ArrayRef<Signature> Signatures;
177 ArrayRef<const char *> Names;
178 ResultPolicy Policy;
179 };
180 const AlgorithmGroup AlgorithmNames[] = {
181 {SingleRangeFunc, SingleRangeNames, DefaultPolicy},
182 {SingleRangeFunc, SingleRangeBeginResultNames, BeginResultPolicy},
183 {SingleRangeFunc, SingleRangeOutResultNames, OutResultPolicy},
184 {SingleRangeFunc, SingleRangeFunctionResultNames, FunctionResultPolicy},
185 {SingleRangeFunc, SingleRangeStructuredBindingNames,
186 StructuredBindingPolicy},
187 {SingleRangeFunc, SingleRangeDiagnosticOnlyNames, DiagnosticOnlyPolicy},
188 {TwoRangeFunc, TwoRangeNames, DefaultPolicy},
189 {TwoRangeFunc, TwoRangeOutResultNames, OutResultPolicy},
190 {TwoRangeFunc, TwoRangeStructuredBindingNames, StructuredBindingPolicy},
191 {SinglePivotFunc, SinglePivotRangeNames, DefaultPolicy},
192 {SinglePivotFunc, SinglePivotRangeBeginResultNames, BeginResultPolicy},
193 {SinglePivotFunc, SinglePivotRangeOutResultNames, OutResultPolicy},
194 };
195 SmallString<64> Buff;
196 for (const auto &[Signatures, Values, Policy] : AlgorithmNames) {
197 auto Replacer = llvm::makeIntrusiveRefCnt<StdAlgorithmReplacer>(
198 SmallVector<UseRangesCheck::Signature>{Signatures}, Policy);
199 for (const auto &Name : Values) {
200 Buff.assign({"::std::", Name});
201 Result.try_emplace(Buff, Replacer);
202 }
203 }
204 if (getLangOpts().CPlusPlus23)
205 Result.try_emplace(
206 "::std::iota",
207 llvm::makeIntrusiveRefCnt<StdNumericReplacer>(
208 SmallVector<UseRangesCheck::Signature>{std::begin(SingleRangeFunc),
209 std::end(SingleRangeFunc)}));
210 return Result;
211}
212
214 : utils::UseRangesCheck(Name, Context),
215 UseReversePipe(Options.get("UseReversePipe", false)) {}
216
219 Options.store(Opts, "UseReversePipe", UseReversePipe);
220}
221
223 const LangOptions &LangOpts) const {
224 return LangOpts.CPlusPlus20;
225}
226ArrayRef<std::pair<StringRef, StringRef>>
228 static constexpr std::pair<StringRef, StringRef> Refs[] = {
229 {"::std::begin", "::std::end"}, {"::std::cbegin", "::std::cend"}};
230 return Refs;
231}
232std::optional<UseRangesCheck::ReverseIteratorDescriptor>
234 static constexpr std::pair<StringRef, StringRef> Refs[] = {
235 {"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}};
236 return ReverseIteratorDescriptor{"std::views::reverse", "<ranges>", Refs,
237 UseReversePipe};
238}
239} // namespace clang::tidy::modernize
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override
ArrayRef< std::pair< StringRef, StringRef > > getFreeBeginEndMethods() const override
Gets the fully qualified names of begin and end functions.
UseRangesCheck(StringRef CheckName, ClangTidyContext *Context)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
ReplacerMap getReplacerMap() const override
Gets a map of function to replace and methods to create the replacements.
std::optional< ReverseIteratorDescriptor > getReverseDescriptor() const override
llvm::StringMap< llvm::IntrusiveRefCntPtr< Replacer > > ReplacerMap
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
static constexpr const char * SingleRangeBeginResultNames[]
static constexpr const char * TwoRangeOutResultNames[]
static constexpr const char * TwoRangeNames[]
static constexpr const char * SinglePivotRangeNames[]
static constexpr const char * SingleRangeStructuredBindingNames[]
static constexpr const char * SinglePivotRangeBeginResultNames[]
static constexpr const char * SinglePivotRangeOutResultNames[]
static constexpr const char * TwoRangeStructuredBindingNames[]
static constexpr const char * SingleRangeNames[]
static constexpr const char * SingleRangeOutResultNames[]
static constexpr const char * SingleRangeFunctionResultNames[]
static constexpr const char * SingleRangeDiagnosticOnlyNames[]
llvm::StringMap< ClangTidyValue > OptionMap