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