xref: /llvm-project/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp (revision 77b2c681677db02552475426f0f7cf2c009ff98d)
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     "reverse",
59     "reverse_copy",
60     "shift_left",
61     "shift_right",
62     "is_partitioned",
63     "partition",
64     "partition_copy",
65     "stable_partition",
66     "sort",
67     "stable_sort",
68     "is_sorted",
69     "is_sorted_until",
70     "is_heap",
71     "is_heap_until",
72     "max_element",
73     "min_element",
74     "minmax_element",
75     "uninitialized_copy",
76     "uninitialized_fill",
77     "uninitialized_move",
78     "uninitialized_default_construct",
79     "uninitialized_value_construct",
80     "destroy",
81 };
82 
83 static constexpr const char *TwoRangeNames[] = {
84     "equal",
85     "mismatch",
86     "partial_sort_copy",
87     "includes",
88     "set_union",
89     "set_intersection",
90     "set_difference",
91     "set_symmetric_difference",
92     "merge",
93     "lexicographical_compare",
94     "find_end",
95     "search",
96     "is_permutation",
97 };
98 
99 static constexpr const char *SinglePivotRangeNames[] = {"rotate", "rotate_copy",
100                                                         "inplace_merge"};
101 
102 namespace {
103 class StdReplacer : public utils::UseRangesCheck::Replacer {
104 public:
105   explicit StdReplacer(SmallVector<UseRangesCheck::Signature> Signatures)
106       : Signatures(std::move(Signatures)) {}
107   std::optional<std::string>
108   getReplaceName(const NamedDecl &OriginalName) const override {
109     return ("std::ranges::" + OriginalName.getName()).str();
110   }
111   ArrayRef<UseRangesCheck::Signature>
112   getReplacementSignatures() const override {
113     return Signatures;
114   }
115 
116 private:
117   SmallVector<UseRangesCheck::Signature> Signatures;
118 };
119 
120 class StdAlgorithmReplacer : public StdReplacer {
121   using StdReplacer::StdReplacer;
122   std::optional<std::string>
123   getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
124     return "<algorithm>";
125   }
126 };
127 
128 class StdNumericReplacer : public StdReplacer {
129   using StdReplacer::StdReplacer;
130   std::optional<std::string>
131   getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override {
132     return "<numeric>";
133   }
134 };
135 } // namespace
136 
137 utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {
138 
139   utils::UseRangesCheck::ReplacerMap Result;
140 
141   // template<typename Iter> Func(Iter first, Iter last,...).
142   static const Signature SingleRangeArgs = {{0}};
143   // template<typename Iter1, typename Iter2>
144   // Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...).
145   static const Signature TwoRangeArgs = {{0}, {2}};
146 
147   // template<typename Iter> Func(Iter first, Iter pivot, Iter last,...).
148   static const Signature SinglePivotRange = {{0, 2}};
149 
150   static const Signature SingleRangeFunc[] = {SingleRangeArgs};
151 
152   static const Signature TwoRangeFunc[] = {TwoRangeArgs};
153 
154   static const Signature SinglePivotFunc[] = {SinglePivotRange};
155 
156   static const std::pair<ArrayRef<Signature>, ArrayRef<const char *>>
157       AlgorithmNames[] = {{SingleRangeFunc, SingleRangeNames},
158                           {TwoRangeFunc, TwoRangeNames},
159                           {SinglePivotFunc, SinglePivotRangeNames}};
160   SmallString<64> Buff;
161   for (const auto &[Signatures, Values] : AlgorithmNames) {
162     auto Replacer = llvm::makeIntrusiveRefCnt<StdAlgorithmReplacer>(
163         SmallVector<UseRangesCheck::Signature>{Signatures});
164     for (const auto &Name : Values) {
165       Buff.assign({"::std::", Name});
166       Result.try_emplace(Buff, Replacer);
167     }
168   }
169   if (getLangOpts().CPlusPlus23)
170     Result.try_emplace(
171         "::std::iota",
172         llvm::makeIntrusiveRefCnt<StdNumericReplacer>(
173             SmallVector<UseRangesCheck::Signature>{std::begin(SingleRangeFunc),
174                                                    std::end(SingleRangeFunc)}));
175   return Result;
176 }
177 
178 UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context)
179     : utils::UseRangesCheck(Name, Context),
180       UseReversePipe(Options.get("UseReversePipe", false)) {}
181 
182 void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
183   utils::UseRangesCheck::storeOptions(Opts);
184   Options.store(Opts, "UseReversePipe", UseReversePipe);
185 }
186 
187 bool UseRangesCheck::isLanguageVersionSupported(
188     const LangOptions &LangOpts) const {
189   return LangOpts.CPlusPlus20;
190 }
191 ArrayRef<std::pair<StringRef, StringRef>>
192 UseRangesCheck::getFreeBeginEndMethods() const {
193   static const std::pair<StringRef, StringRef> Refs[] = {
194       {"::std::begin", "::std::end"}, {"::std::cbegin", "::std::cend"}};
195   return Refs;
196 }
197 std::optional<UseRangesCheck::ReverseIteratorDescriptor>
198 UseRangesCheck::getReverseDescriptor() const {
199   static const std::pair<StringRef, StringRef> Refs[] = {
200       {"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}};
201   return ReverseIteratorDescriptor{UseReversePipe ? "std::views::reverse"
202                                                   : "std::ranges::reverse_view",
203                                    "<ranges>", Refs, UseReversePipe};
204 }
205 } // namespace clang::tidy::modernize
206