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",
41 "remove_if",
42 "remove_copy",
43 "remove_copy_if",
44 "unique_copy",
45 "sample",
46 "partition_point",
47 "lower_bound",
48 "upper_bound",
49 "equal_range",
50 "binary_search",
51 "push_heap",
52 "pop_heap",
53 "make_heap",
54 "sort_heap",
55 "next_permutation",
56 "prev_permutation",
57 "reverse",
58 "reverse_copy",
59 "shift_left",
60 "shift_right",
61 "is_partitioned",
62 "partition",
63 "partition_copy",
64 "stable_partition",
65 "sort",
66 "stable_sort",
67 "is_sorted",
68 "is_sorted_until",
69 "is_heap",
70 "is_heap_until",
71 "max_element",
72 "min_element",
73 "minmax_element",
74 "uninitialized_copy",
75 "uninitialized_fill",
76 "uninitialized_move",
77 "uninitialized_default_construct",
78 "uninitialized_value_construct",
79 "destroy",
80};
81
82static constexpr const char *SingleRangeBeginResultNames[] = {"unique"};
83
84static constexpr const char *TwoRangeNames[] = {
85 "equal",
86 "mismatch",
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 "is_permutation",
98};
99
100static constexpr const char *SinglePivotRangeNames[] = {"rotate", "rotate_copy",
101 "inplace_merge"};
102
103namespace {
104class StdReplacer : public utils::UseRangesCheck::Replacer {
105public:
107
108 explicit StdReplacer(SmallVector<UseRangesCheck::Signature> Signatures,
109 ResultUsePolicy ResultPolicy = {})
110 : Signatures(std::move(Signatures)), ResultPolicy(ResultPolicy) {}
111 std::optional<std::string>
112 getReplaceName(const NamedDecl &OriginalName) const override {
113 return ("std::ranges::" + OriginalName.getName()).str();
114 }
115 ArrayRef<UseRangesCheck::Signature>
116 getReplacementSignatures() const override {
117 return Signatures;
118 }
119 ResultUsePolicy getResultUsePolicy(const NamedDecl &, bool) const override {
120 return ResultPolicy;
121 }
122
123private:
124 SmallVector<UseRangesCheck::Signature> Signatures;
125 ResultUsePolicy ResultPolicy;
126};
127
128class StdAlgorithmReplacer : public StdReplacer {
129 using StdReplacer::StdReplacer;
130 std::optional<std::string>
131 getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
132 return "<algorithm>";
133 }
134};
135
136class StdNumericReplacer : public StdReplacer {
137 using StdReplacer::StdReplacer;
138 std::optional<std::string>
139 getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
140 return "<numeric>";
141 }
142};
143} // namespace
144
147
148 // template<typename Iter> Func(Iter first, Iter last,...).
149 static const Signature SingleRangeArgs = {{0}};
150 // template<typename Iter1, typename Iter2>
151 // Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...).
152 static const Signature TwoRangeArgs = {{0}, {2}};
153
154 // template<typename Iter> Func(Iter first, Iter pivot, Iter last,...).
155 static const Signature SinglePivotRange = {{0, 2}};
156
157 static const Signature SingleRangeFunc[] = {SingleRangeArgs};
158
159 static const Signature TwoRangeFunc[] = {TwoRangeArgs};
160
161 static const Signature SinglePivotFunc[] = {SinglePivotRange};
162
163 using ResultPolicy = StdReplacer::ResultUsePolicy;
164 using PolicyKind = ResultPolicy::Kind;
165 const ResultPolicy DefaultPolicy;
166 const ResultPolicy BeginResultPolicy = {
167 PolicyKind::AppendAccessorForUsedResult, ".begin()"};
168
169 struct AlgorithmGroup {
170 ArrayRef<Signature> Signatures;
171 ArrayRef<const char *> Names;
172 ResultPolicy Policy;
173 };
174 const AlgorithmGroup AlgorithmNames[] = {
175 {SingleRangeFunc, SingleRangeNames, DefaultPolicy},
176 {SingleRangeFunc, SingleRangeBeginResultNames, BeginResultPolicy},
177 {TwoRangeFunc, TwoRangeNames, DefaultPolicy},
178 {SinglePivotFunc, SinglePivotRangeNames, DefaultPolicy},
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 * SingleRangeNames[]
llvm::StringMap< ClangTidyValue > OptionMap