//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "UseRangesCheck.h" #include "clang/AST/Decl.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include // FixItHint - Let the docs script know that this class does provide fixits namespace clang::tidy::modernize { static constexpr const char *SingleRangeNames[] = { "all_of", "any_of", "none_of", "for_each", "find", "find_if", "find_if_not", "adjacent_find", "copy", "copy_if", "copy_backward", "move", "move_backward", "fill", "transform", "replace", "replace_if", "generate", "remove_copy", "remove_copy_if", "unique_copy", "sample", "partition_point", "lower_bound", "upper_bound", "equal_range", "binary_search", "push_heap", "pop_heap", "make_heap", "sort_heap", "next_permutation", "prev_permutation", "reverse", "reverse_copy", "shift_left", "shift_right", "is_partitioned", "partition_copy", "sort", "stable_sort", "is_sorted", "is_sorted_until", "is_heap", "is_heap_until", "max_element", "min_element", "minmax_element", "uninitialized_copy", "uninitialized_fill", "uninitialized_move", "uninitialized_default_construct", "uninitialized_value_construct", "destroy", }; static constexpr const char *SingleRangeBeginResultNames[] = { "remove", "remove_if", "stable_partition", "partition", "unique"}; static constexpr const char *TwoRangeNames[] = { "equal", "mismatch", "partial_sort_copy", "includes", "set_union", "set_intersection", "set_difference", "set_symmetric_difference", "merge", "lexicographical_compare", "find_end", "search", "is_permutation", }; static constexpr const char *SinglePivotRangeNames[] = {"rotate_copy", "inplace_merge"}; static constexpr const char *SinglePivotRangeBeginResultNames[] = {"rotate"}; namespace { class StdReplacer : public utils::UseRangesCheck::Replacer { public: using ResultUsePolicy = utils::UseRangesCheck::Replacer::ResultUsePolicy; explicit StdReplacer(SmallVector Signatures, ResultUsePolicy ResultPolicy = {}) : Signatures(std::move(Signatures)), ResultPolicy(ResultPolicy) {} std::optional getReplaceName(const NamedDecl &OriginalName) const override { return ("std::ranges::" + OriginalName.getName()).str(); } ArrayRef getReplacementSignatures() const override { return Signatures; } ResultUsePolicy getResultUsePolicy(const NamedDecl &, bool) const override { return ResultPolicy; } private: SmallVector Signatures; ResultUsePolicy ResultPolicy; }; class StdAlgorithmReplacer : public StdReplacer { using StdReplacer::StdReplacer; std::optional getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override { return ""; } }; class StdNumericReplacer : public StdReplacer { using StdReplacer::StdReplacer; std::optional getHeaderInclusion(const NamedDecl & /*OriginalName*/) const override { return ""; } }; } // namespace utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const { utils::UseRangesCheck::ReplacerMap Result; // template Func(Iter first, Iter last,...). static const Signature SingleRangeArgs = {{0}}; // template // Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...). static const Signature TwoRangeArgs = {{0}, {2}}; // template Func(Iter first, Iter pivot, Iter last,...). static const Signature SinglePivotRange = {{0, 2}}; static const Signature SingleRangeFunc[] = {SingleRangeArgs}; static const Signature TwoRangeFunc[] = {TwoRangeArgs}; static const Signature SinglePivotFunc[] = {SinglePivotRange}; using ResultPolicy = StdReplacer::ResultUsePolicy; using PolicyKind = ResultPolicy::Kind; const ResultPolicy DefaultPolicy; const ResultPolicy BeginResultPolicy = { PolicyKind::AppendAccessorForUsedResult, ".begin()"}; struct AlgorithmGroup { ArrayRef Signatures; ArrayRef Names; ResultPolicy Policy; }; const AlgorithmGroup AlgorithmNames[] = { {SingleRangeFunc, SingleRangeNames, DefaultPolicy}, {SingleRangeFunc, SingleRangeBeginResultNames, BeginResultPolicy}, {TwoRangeFunc, TwoRangeNames, DefaultPolicy}, {SinglePivotFunc, SinglePivotRangeNames, DefaultPolicy}, {SinglePivotFunc, SinglePivotRangeBeginResultNames, BeginResultPolicy}, }; SmallString<64> Buff; for (const auto &[Signatures, Values, Policy] : AlgorithmNames) { auto Replacer = llvm::makeIntrusiveRefCnt( SmallVector{Signatures}, Policy); for (const auto &Name : Values) { Buff.assign({"::std::", Name}); Result.try_emplace(Buff, Replacer); } } if (getLangOpts().CPlusPlus23) Result.try_emplace( "::std::iota", llvm::makeIntrusiveRefCnt( SmallVector{std::begin(SingleRangeFunc), std::end(SingleRangeFunc)})); return Result; } UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context) : utils::UseRangesCheck(Name, Context), UseReversePipe(Options.get("UseReversePipe", false)) {} void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { utils::UseRangesCheck::storeOptions(Opts); Options.store(Opts, "UseReversePipe", UseReversePipe); } bool UseRangesCheck::isLanguageVersionSupported( const LangOptions &LangOpts) const { return LangOpts.CPlusPlus20; } ArrayRef> UseRangesCheck::getFreeBeginEndMethods() const { static constexpr std::pair Refs[] = { {"::std::begin", "::std::end"}, {"::std::cbegin", "::std::cend"}}; return Refs; } std::optional UseRangesCheck::getReverseDescriptor() const { static constexpr std::pair Refs[] = { {"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}}; return ReverseIteratorDescriptor{"std::views::reverse", "", Refs, UseReversePipe}; } } // namespace clang::tidy::modernize