clang-tools 22.0.0git
boost/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 "clang/Basic/Diagnostic.h"
12#include "clang/Basic/LLVM.h"
13#include "llvm/ADT/ArrayRef.h"
14#include "llvm/ADT/IntrusiveRefCntPtr.h"
15#include "llvm/ADT/SmallString.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/StringRef.h"
18#include <initializer_list>
19#include <optional>
20#include <string>
21#include <utility>
22
23// FixItHint - Let the docs script know that this class does provide fixits
24
25namespace clang::tidy::boost {
26
27namespace {
28/// Base replacer that handles the boost include path and namespace
29class BoostReplacer : public UseRangesCheck::Replacer {
30public:
31 BoostReplacer(ArrayRef<UseRangesCheck::Signature> Signatures,
32 bool IncludeSystem)
33 : Signatures(Signatures), IncludeSystem(IncludeSystem) {}
34
35 ArrayRef<UseRangesCheck::Signature> getReplacementSignatures() const final {
36 return Signatures;
37 }
38
39 virtual std::pair<StringRef, StringRef>
40 getBoostName(const NamedDecl &OriginalName) const = 0;
41
42 virtual std::pair<StringRef, StringRef>
43 getBoostHeader(const NamedDecl &OriginalName) const = 0;
44
45 std::optional<std::string>
46 getReplaceName(const NamedDecl &OriginalName) const final {
47 auto [Namespace, Function] = getBoostName(OriginalName);
48 return ("boost::" + Namespace + (Namespace.empty() ? "" : "::") + Function)
49 .str();
50 }
51
52 std::optional<std::string>
53 getHeaderInclusion(const NamedDecl &OriginalName) const final {
54 auto [Path, HeaderName] = getBoostHeader(OriginalName);
55 return ((IncludeSystem ? "<boost/" : "boost/") + Path +
56 (Path.empty() ? "" : "/") + HeaderName +
57 (IncludeSystem ? ".hpp>" : ".hpp"))
58 .str();
59 }
60
61private:
62 SmallVector<UseRangesCheck::Signature> Signatures;
63 bool IncludeSystem;
64};
65
66/// Creates replaces where the header file lives in
67/// `boost/algorithm/<FUNC_NAME>.hpp` and the function is named
68/// `boost::range::<FUNC_NAME>`
69class BoostRangeAlgorithmReplacer : public BoostReplacer {
70public:
71 using BoostReplacer::BoostReplacer;
72
73 std::pair<StringRef, StringRef>
74 getBoostName(const NamedDecl &OriginalName) const override {
75 return {"range", OriginalName.getName()};
76 }
77
78 std::pair<StringRef, StringRef>
79 getBoostHeader(const NamedDecl &OriginalName) const override {
80 return {"range/algorithm", OriginalName.getName()};
81 }
82};
83
84/// Creates replaces where the header file lives in
85/// `boost/algorithm/<CUSTOM_HEADER>.hpp` and the function is named
86/// `boost::range::<FUNC_NAME>`
87class CustomBoostAlgorithmHeaderReplacer : public BoostRangeAlgorithmReplacer {
88public:
89 CustomBoostAlgorithmHeaderReplacer(
90 StringRef HeaderName, ArrayRef<UseRangesCheck::Signature> Signatures,
91 bool IncludeSystem)
92 : BoostRangeAlgorithmReplacer(Signatures, IncludeSystem),
93 HeaderName(HeaderName) {}
94
95 std::pair<StringRef, StringRef>
96 getBoostHeader(const NamedDecl & /*OriginalName*/) const override {
97 return {"range/algorithm", HeaderName};
98 }
99
100private:
101 StringRef HeaderName;
102};
103
104/// Creates replaces where the header file lives in
105/// `boost/algorithm/<SUB_HEADER>.hpp` and the function is named
106/// `boost::algorithm::<FUNC_NAME>`
107class BoostAlgorithmReplacer : public BoostReplacer {
108public:
109 BoostAlgorithmReplacer(StringRef SubHeader,
110 ArrayRef<UseRangesCheck::Signature> Signatures,
111 bool IncludeSystem)
112 : BoostReplacer(Signatures, IncludeSystem),
113 SubHeader(("algorithm/" + SubHeader).str()) {}
114 std::pair<StringRef, StringRef>
115 getBoostName(const NamedDecl &OriginalName) const override {
116 return {"algorithm", OriginalName.getName()};
117 }
118
119 std::pair<StringRef, StringRef>
120 getBoostHeader(const NamedDecl &OriginalName) const override {
121 return {SubHeader, OriginalName.getName()};
122 }
123
124private:
125 std::string SubHeader;
126};
127
128/// Creates replaces where the header file lives in
129/// `boost/algorithm/<SUB_HEADER>/<HEADER_NAME>.hpp` and the function is named
130/// `boost::algorithm::<FUNC_NAME>`
131class CustomBoostAlgorithmReplacer : public BoostReplacer {
132public:
133 CustomBoostAlgorithmReplacer(StringRef SubHeader, StringRef HeaderName,
134 ArrayRef<UseRangesCheck::Signature> Signatures,
135 bool IncludeSystem)
136 : BoostReplacer(Signatures, IncludeSystem),
137 SubHeader(("algorithm/" + SubHeader).str()), HeaderName(HeaderName) {}
138 std::pair<StringRef, StringRef>
139 getBoostName(const NamedDecl &OriginalName) const override {
140 return {"algorithm", OriginalName.getName()};
141 }
142
143 std::pair<StringRef, StringRef>
144 getBoostHeader(const NamedDecl & /*OriginalName*/) const override {
145 return {SubHeader, HeaderName};
146 }
147
148private:
149 std::string SubHeader;
150 StringRef HeaderName;
151};
152
153/// A Replacer that is used for functions that just call a new overload
154class MakeOverloadReplacer : public UseRangesCheck::Replacer {
155public:
156 explicit MakeOverloadReplacer(ArrayRef<UseRangesCheck::Signature> Signatures)
157 : Signatures(Signatures) {}
158
159 ArrayRef<UseRangesCheck::Signature>
160 getReplacementSignatures() const override {
161 return Signatures;
162 }
163
164 std::optional<std::string>
165 getReplaceName(const NamedDecl & /* OriginalName */) const override {
166 return std::nullopt;
167 }
168
169 std::optional<std::string>
170 getHeaderInclusion(const NamedDecl & /* OriginalName */) const override {
171 return std::nullopt;
172 }
173
174private:
175 SmallVector<UseRangesCheck::Signature> Signatures;
176};
177
178/// A replacer that replaces functions with an equivalent named function in the
179/// root boost namespace
180class FixedBoostReplace : public BoostReplacer {
181public:
182 FixedBoostReplace(StringRef Header,
183 ArrayRef<UseRangesCheck::Signature> Signatures,
184 bool IncludeBoostSystem)
185 : BoostReplacer(Signatures, IncludeBoostSystem), Header(Header) {}
186
187 std::pair<StringRef, StringRef>
188 getBoostName(const NamedDecl &OriginalName) const override {
189 return {{}, OriginalName.getName()};
190 }
191
192 std::pair<StringRef, StringRef>
193 getBoostHeader(const NamedDecl & /* OriginalName */) const override {
194 return {{}, Header};
195 }
196
197private:
198 StringRef Header;
199};
200
201} // namespace
202
204
205 ReplacerMap Results;
206 static const Signature SingleSig = {{0}};
207 static const Signature TwoSig = {{0}, {2}};
208 const auto AddFrom =
209 [&Results](llvm::IntrusiveRefCntPtr<UseRangesCheck::Replacer> Replacer,
210 std::initializer_list<StringRef> Names, StringRef Prefix) {
211 llvm::SmallString<64> Buffer;
212 for (const auto &Name : Names) {
213 Buffer.assign({"::", Prefix, (Prefix.empty() ? "" : "::"), Name});
214 Results.try_emplace(Buffer, Replacer);
215 }
216 };
217
218 const auto AddFromStd =
219 [&](llvm::IntrusiveRefCntPtr<UseRangesCheck::Replacer> Replacer,
220 std::initializer_list<StringRef> Names) {
221 AddFrom(std::move(Replacer), Names, "std");
222 };
223
224 const auto AddFromBoost =
225 [&](const llvm::IntrusiveRefCntPtr<UseRangesCheck::Replacer> &Replacer,
226 std::initializer_list<
227 std::pair<StringRef, std::initializer_list<StringRef>>>
228 NamespaceAndNames) {
229 for (auto [Namespace, Names] : NamespaceAndNames)
230 AddFrom(Replacer, Names,
231 SmallString<64>{"boost", (Namespace.empty() ? "" : "::"),
232 Namespace});
233 };
234
235 AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>(
236 "set_algorithm", TwoSig, IncludeBoostSystem),
237 {"includes", "set_union", "set_intersection", "set_difference",
238 "set_symmetric_difference"});
239
240 AddFromStd(llvm::makeIntrusiveRefCnt<BoostRangeAlgorithmReplacer>(
241 SingleSig, IncludeBoostSystem),
242 {"unique", "lower_bound", "stable_sort",
243 "equal_range", "remove_if", "sort",
244 "random_shuffle", "remove_copy", "stable_partition",
245 "remove_copy_if", "count", "copy_backward",
246 "reverse_copy", "adjacent_find", "remove",
247 "upper_bound", "binary_search", "replace_copy_if",
248 "for_each", "generate", "count_if",
249 "min_element", "reverse", "replace_copy",
250 "fill", "unique_copy", "transform",
251 "copy", "replace", "find",
252 "replace_if", "find_if", "partition",
253 "max_element"});
254
255 AddFromStd(llvm::makeIntrusiveRefCnt<BoostRangeAlgorithmReplacer>(
256 TwoSig, IncludeBoostSystem),
257 {"find_end", "merge", "partial_sort_copy", "find_first_of",
258 "search", "lexicographical_compare", "equal", "mismatch"});
259
260 AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>(
261 "permutation", SingleSig, IncludeBoostSystem),
262 {"next_permutation", "prev_permutation"});
263
264 AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>(
265 "heap_algorithm", SingleSig, IncludeBoostSystem),
266 {"push_heap", "pop_heap", "make_heap", "sort_heap"});
267
268 AddFromStd(llvm::makeIntrusiveRefCnt<BoostAlgorithmReplacer>(
269 "cxx11", SingleSig, IncludeBoostSystem),
270 {"copy_if", "is_permutation", "is_partitioned", "find_if_not",
271 "partition_copy", "any_of", "iota", "all_of", "partition_point",
272 "is_sorted", "none_of"});
273
274 AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmReplacer>(
275 "cxx11", "is_sorted", SingleSig, IncludeBoostSystem),
276 {"is_sorted_until"});
277
278 AddFromStd(llvm::makeIntrusiveRefCnt<FixedBoostReplace>(
279 "range/numeric", SingleSig, IncludeBoostSystem),
280 {"accumulate", "partial_sum", "adjacent_difference"});
281
282 if (getLangOpts().CPlusPlus17)
283 AddFromStd(llvm::makeIntrusiveRefCnt<BoostAlgorithmReplacer>(
284 "cxx17", SingleSig, IncludeBoostSystem),
285 {"reduce"});
286
287 AddFromBoost(llvm::makeIntrusiveRefCnt<MakeOverloadReplacer>(SingleSig),
288 {{"algorithm",
289 {"reduce",
290 "find_backward",
291 "find_not_backward",
292 "find_if_backward",
293 "find_if_not_backward",
294 "hex",
295 "hex_lower",
296 "unhex",
297 "is_partitioned_until",
298 "is_palindrome",
299 "copy_if",
300 "copy_while",
301 "copy_until",
302 "copy_if_while",
303 "copy_if_until",
304 "is_permutation",
305 "is_partitioned",
306 "one_of",
307 "one_of_equal",
308 "find_if_not",
309 "partition_copy",
310 "any_of",
311 "any_of_equal",
312 "iota",
313 "all_of",
314 "all_of_equal",
315 "partition_point",
316 "is_sorted_until",
317 "is_sorted",
318 "is_increasing",
319 "is_decreasing",
320 "is_strictly_increasing",
321 "is_strictly_decreasing",
322 "none_of",
323 "none_of_equal",
324 "clamp_range"}}});
325
326 AddFromBoost(
327 llvm::makeIntrusiveRefCnt<MakeOverloadReplacer>(TwoSig),
328 {{"algorithm", {"apply_permutation", "apply_reverse_permutation"}}});
329
330 return Results;
331}
332
334 : utils::UseRangesCheck(Name, Context),
335 IncludeBoostSystem(Options.get("IncludeBoostSystem", true)),
336 UseReversePipe(Options.get("UseReversePipe", false)) {}
337
340 Options.store(Opts, "IncludeBoostSystem", IncludeBoostSystem);
341 Options.store(Opts, "UseReversePipe", UseReversePipe);
342}
343
344DiagnosticBuilder UseRangesCheck::createDiag(const CallExpr &Call) {
345 const DiagnosticBuilder D =
346 diag(Call.getBeginLoc(), "use a %0 version of this algorithm");
347 D << (Call.getDirectCallee()->isInStdNamespace() ? "boost" : "ranged");
348 return D;
349}
350ArrayRef<std::pair<StringRef, StringRef>>
352 static const std::pair<StringRef, StringRef> Refs[] = {
353 {"::std::begin", "::std::end"},
354 {"::std::cbegin", "::std::cend"},
355 {"::boost::range_adl_barrier::begin", "::boost::range_adl_barrier::end"},
356 {"::boost::range_adl_barrier::const_begin",
357 "::boost::range_adl_barrier::const_end"},
358 };
359 return Refs;
360}
361std::optional<UseRangesCheck::ReverseIteratorDescriptor>
363 static const std::pair<StringRef, StringRef> Refs[] = {
364 {"::std::rbegin", "::std::rend"},
365 {"::std::crbegin", "::std::crend"},
366 {"::boost::rbegin", "::boost::rend"},
367 {"::boost::const_rbegin", "::boost::const_rend"},
368 };
370 UseReversePipe ? "boost::adaptors::reversed" : "boost::adaptors::reverse",
371 IncludeBoostSystem ? "<boost/range/adaptor/reversed.hpp>"
372 : "boost/range/adaptor/reversed.hpp",
373 Refs, UseReversePipe};
374}
375} // namespace clang::tidy::boost
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
ArrayRef< std::pair< StringRef, StringRef > > getFreeBeginEndMethods() const override
Gets the fully qualified names of begin and end functions.
UseRangesCheck(StringRef Name, ClangTidyContext *Context)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
DiagnosticBuilder createDiag(const CallExpr &Call) override
Create a diagnostic for the CallExpr Override this to support custom diagnostic messages.
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
std::string Path
A typedef to represent a file path.
Definition Path.h:26
llvm::StringMap< ClangTidyValue > OptionMap