clang-tools 23.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 "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_copy",
41 "remove_copy_if",
42 "unique_copy",
43 "sample",
44 "partition_point",
45 "lower_bound",
46 "upper_bound",
47 "equal_range",
48 "binary_search",
49 "push_heap",
50 "pop_heap",
51 "make_heap",
52 "sort_heap",
53 "next_permutation",
54 "prev_permutation",
55 "reverse",
56 "reverse_copy",
57 "shift_left",
58 "shift_right",
59 "is_partitioned",
60 "partition_copy",
61 "sort",
62 "stable_sort",
63 "is_sorted",
64 "is_sorted_until",
65 "is_heap",
66 "is_heap_until",
67 "max_element",
68 "min_element",
69 "minmax_element",
70 "uninitialized_copy",
71 "uninitialized_fill",
72 "uninitialized_move",
73 "uninitialized_default_construct",
74 "uninitialized_value_construct",
75 "destroy",
76};
77
78static constexpr const char *SingleRangeBeginResultNames[] = {
79 "remove", "remove_if", "stable_partition", "partition", "unique"};
80
81static constexpr const char *TwoRangeNames[] = {
82 "equal",
83 "mismatch",
84 "partial_sort_copy",
85 "includes",
86 "set_union",
87 "set_intersection",
88 "set_difference",
89 "set_symmetric_difference",
90 "merge",
91 "lexicographical_compare",
92 "find_end",
93 "search",
94 "is_permutation",
95};
96
97static constexpr const char *SinglePivotRangeNames[] = {"rotate_copy",
98 "inplace_merge"};
99
100static constexpr const char *SinglePivotRangeBeginResultNames[] = {"rotate"};
101
102namespace {
103class StdReplacer : public utils::UseRangesCheck::Replacer {
104public:
106
107 explicit StdReplacer(SmallVector<UseRangesCheck::Signature> Signatures,
108 ResultUsePolicy ResultPolicy = {})
109 : Signatures(std::move(Signatures)), ResultPolicy(ResultPolicy) {}
110 std::optional<std::string>
111 getReplaceName(const NamedDecl &OriginalName) const override {
112 return ("std::ranges::" + OriginalName.getName()).str();
113 }
114 ArrayRef<UseRangesCheck::Signature>
115 getReplacementSignatures() const override {
116 return Signatures;
117 }
118 ResultUsePolicy getResultUsePolicy(const NamedDecl &, bool) const override {
119 return ResultPolicy;
120 }
121
122private:
123 SmallVector<UseRangesCheck::Signature> Signatures;
124 ResultUsePolicy ResultPolicy;
125};
126
127class StdAlgorithmReplacer : public StdReplacer {
128 using StdReplacer::StdReplacer;
129 std::optional<std::string>
130 getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
131 return "<algorithm>";
132 }
133};
134
135class StdNumericReplacer : public StdReplacer {
136 using StdReplacer::StdReplacer;
137 std::optional<std::string>
138 getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
139 return "<numeric>";
140 }
141};
142} // namespace
143
146
147 // template<typename Iter> Func(Iter first, Iter last,...).
148 static const Signature SingleRangeArgs = {{0}};
149 // template<typename Iter1, typename Iter2>
150 // Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...).
151 static const Signature TwoRangeArgs = {{0}, {2}};
152
153 // template<typename Iter> Func(Iter first, Iter pivot, Iter last,...).
154 static const Signature SinglePivotRange = {{0, 2}};
155
156 static const Signature SingleRangeFunc[] = {SingleRangeArgs};
157
158 static const Signature TwoRangeFunc[] = {TwoRangeArgs};
159
160 static const Signature SinglePivotFunc[] = {SinglePivotRange};
161
162 using ResultPolicy = StdReplacer::ResultUsePolicy;
163 using PolicyKind = ResultPolicy::Kind;
164 const ResultPolicy DefaultPolicy;
165 const ResultPolicy BeginResultPolicy = {
166 PolicyKind::AppendAccessorForUsedResult, ".begin()"};
167
168 struct AlgorithmGroup {
169 ArrayRef<Signature> Signatures;
170 ArrayRef<const char *> Names;
171 ResultPolicy Policy;
172 };
173 const AlgorithmGroup AlgorithmNames[] = {
174 {SingleRangeFunc, SingleRangeNames, DefaultPolicy},
175 {SingleRangeFunc, SingleRangeBeginResultNames, BeginResultPolicy},
176 {TwoRangeFunc, TwoRangeNames, DefaultPolicy},
177 {SinglePivotFunc, SinglePivotRangeNames, DefaultPolicy},
178 {SinglePivotFunc, SinglePivotRangeBeginResultNames, BeginResultPolicy},
179 };
180 SmallString<64> Buff;
181 for (const auto &[Signatures, Values, Policy] : AlgorithmNames) {
182 auto Replacer = llvm::makeIntrusiveRefCnt<StdAlgorithmReplacer>(
183 SmallVector<UseRangesCheck::Signature>{Signatures}, Policy);
184 for (const auto &Name : Values) {
185 Buff.assign({"::std::", Name});
186 Result.try_emplace(Buff, Replacer);
187 }
188 }
189 if (getLangOpts().CPlusPlus23)
190 Result.try_emplace(
191 "::std::iota",
192 llvm::makeIntrusiveRefCnt<StdNumericReplacer>(
193 SmallVector<UseRangesCheck::Signature>{std::begin(SingleRangeFunc),
194 std::end(SingleRangeFunc)}));
195 return Result;
196}
197
199 : utils::UseRangesCheck(Name, Context),
200 UseReversePipe(Options.get("UseReversePipe", false)) {}
201
204 Options.store(Opts, "UseReversePipe", UseReversePipe);
205}
206
208 const LangOptions &LangOpts) const {
209 return LangOpts.CPlusPlus20;
210}
211ArrayRef<std::pair<StringRef, StringRef>>
213 static constexpr std::pair<StringRef, StringRef> Refs[] = {
214 {"::std::begin", "::std::end"}, {"::std::cbegin", "::std::cend"}};
215 return Refs;
216}
217std::optional<UseRangesCheck::ReverseIteratorDescriptor>
219 static constexpr std::pair<StringRef, StringRef> Refs[] = {
220 {"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}};
221 return ReverseIteratorDescriptor{"std::views::reverse", "<ranges>", Refs,
222 UseReversePipe};
223}
224} // 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 * TwoRangeNames[]
static constexpr const char * SinglePivotRangeNames[]
static constexpr const char * SinglePivotRangeBeginResultNames[]
static constexpr const char * SingleRangeNames[]
llvm::StringMap< ClangTidyValue > OptionMap