//===--- UseRangesCheck.cpp - clang-tidy ----------------------------------===// // // 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", "remove_if", "remove_copy", "remove_copy_if", "unique", "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", "partition_copy", "stable_partition", "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 *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", "rotate_copy", "inplace_merge"}; namespace { class StdReplacer : public utils::UseRangesCheck::Replacer { public: explicit StdReplacer(SmallVector Signatures) : Signatures(std::move(Signatures)) {} std::optional getReplaceName(const NamedDecl &OriginalName) const override { return ("std::ranges::" + OriginalName.getName()).str(); } ArrayRef getReplacementSignatures() const override { return Signatures; } private: SmallVector Signatures; }; 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}; static const std::pair, ArrayRef> AlgorithmNames[] = {{SingleRangeFunc, SingleRangeNames}, {TwoRangeFunc, TwoRangeNames}, {SinglePivotFunc, SinglePivotRangeNames}}; SmallString<64> Buff; for (const auto &[Signatures, Values] : AlgorithmNames) { auto Replacer = llvm::makeIntrusiveRefCnt( SmallVector{Signatures}); 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 const std::pair Refs[] = { {"::std::begin", "::std::end"}, {"::std::cbegin", "::std::cend"}}; return Refs; } std::optional UseRangesCheck::getReverseDescriptor() const { static const std::pair Refs[] = { {"::std::rbegin", "::std::rend"}, {"::std::crbegin", "::std::crend"}}; return ReverseIteratorDescriptor{UseReversePipe ? "std::views::reverse" : "std::ranges::reverse_view", "", Refs, UseReversePipe}; } } // namespace clang::tidy::modernize