205 lines · cpp
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-exception6//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 fixits18 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",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 83static 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 99static constexpr const char *SinglePivotRangeNames[] = {"rotate", "rotate_copy",100 "inplace_merge"};101 102namespace {103class StdReplacer : public utils::UseRangesCheck::Replacer {104public: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 116private:117 SmallVector<UseRangesCheck::Signature> Signatures;118};119 120class 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 128class 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} // namespace136 137utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {138 utils::UseRangesCheck::ReplacerMap Result;139 140 // template<typename Iter> Func(Iter first, Iter last,...).141 static const Signature SingleRangeArgs = {{0}};142 // template<typename Iter1, typename Iter2>143 // Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...).144 static const Signature TwoRangeArgs = {{0}, {2}};145 146 // template<typename Iter> Func(Iter first, Iter pivot, Iter last,...).147 static const Signature SinglePivotRange = {{0, 2}};148 149 static const Signature SingleRangeFunc[] = {SingleRangeArgs};150 151 static const Signature TwoRangeFunc[] = {TwoRangeArgs};152 153 static const Signature SinglePivotFunc[] = {SinglePivotRange};154 155 static const std::pair<ArrayRef<Signature>, ArrayRef<const char *>>156 AlgorithmNames[] = {{SingleRangeFunc, SingleRangeNames},157 {TwoRangeFunc, TwoRangeNames},158 {SinglePivotFunc, SinglePivotRangeNames}};159 SmallString<64> Buff;160 for (const auto &[Signatures, Values] : AlgorithmNames) {161 auto Replacer = llvm::makeIntrusiveRefCnt<StdAlgorithmReplacer>(162 SmallVector<UseRangesCheck::Signature>{Signatures});163 for (const auto &Name : Values) {164 Buff.assign({"::std::", Name});165 Result.try_emplace(Buff, Replacer);166 }167 }168 if (getLangOpts().CPlusPlus23)169 Result.try_emplace(170 "::std::iota",171 llvm::makeIntrusiveRefCnt<StdNumericReplacer>(172 SmallVector<UseRangesCheck::Signature>{std::begin(SingleRangeFunc),173 std::end(SingleRangeFunc)}));174 return Result;175}176 177UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context)178 : utils::UseRangesCheck(Name, Context),179 UseReversePipe(Options.get("UseReversePipe", false)) {}180 181void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {182 utils::UseRangesCheck::storeOptions(Opts);183 Options.store(Opts, "UseReversePipe", UseReversePipe);184}185 186bool UseRangesCheck::isLanguageVersionSupported(187 const LangOptions &LangOpts) const {188 return LangOpts.CPlusPlus20;189}190ArrayRef<std::pair<StringRef, StringRef>>191UseRangesCheck::getFreeBeginEndMethods() const {192 static const std::pair<StringRef, StringRef> Refs[] = {193 {"::std::begin", "::std::end"}, {"::std::cbegin", "::std::cend"}};194 return Refs;195}196std::optional<UseRangesCheck::ReverseIteratorDescriptor>197UseRangesCheck::getReverseDescriptor() const {198 static const std::pair<StringRef, StringRef> Refs[] = {199 {"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}};200 return ReverseIteratorDescriptor{UseReversePipe ? "std::views::reverse"201 : "std::ranges::reverse_view",202 "<ranges>", Refs, UseReversePipe};203}204} // namespace clang::tidy::modernize205