llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: Nathan James (njames93) <details> <summary>Changes</summary> --- Patch is 48.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/97764.diff 17 Files Affected: - (modified) clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp (+2) - (modified) clang-tools-extra/clang-tidy/boost/CMakeLists.txt (+1) - (added) clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp (+208) - (added) clang-tools-extra/clang-tidy/boost/UseRangesCheck.h (+34) - (modified) clang-tools-extra/clang-tidy/modernize/CMakeLists.txt (+1) - (modified) clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp (+2) - (added) clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp (+148) - (added) clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h (+31) - (modified) clang-tools-extra/clang-tidy/utils/CMakeLists.txt (+1) - (added) clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp (+253) - (added) clang-tools-extra/clang-tidy/utils/UseRangesCheck.h (+58) - (modified) clang-tools-extra/docs/ReleaseNotes.rst (+12) - (added) clang-tools-extra/docs/clang-tidy/checks/boost/use-ranges.rst (+24) - (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+2) - (added) clang-tools-extra/docs/clang-tidy/checks/modernize/use-ranges.rst (+24) - (added) clang-tools-extra/test/clang-tidy/checkers/boost/use-ranges.cpp (+132) - (added) clang-tools-extra/test/clang-tidy/checkers/modernize/use-ranges.cpp (+171) ``````````diff diff --git a/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp b/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp index 4c5808daa6ae7..79d0e380e402d 100644 --- a/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/boost/BoostTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "UseRangesCheck.h" #include "UseToStringCheck.h" using namespace clang::ast_matchers; @@ -18,6 +19,7 @@ namespace boost { class BoostModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck<UseRangesCheck>("boost-use-ranges"); CheckFactories.registerCheck<UseToStringCheck>("boost-use-to-string"); } }; diff --git a/clang-tools-extra/clang-tidy/boost/CMakeLists.txt b/clang-tools-extra/clang-tidy/boost/CMakeLists.txt index 167b6fab774b7..fed3c3ba01c16 100644 --- a/clang-tools-extra/clang-tidy/boost/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/boost/CMakeLists.txt @@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangTidyBoostModule BoostTidyModule.cpp + UseRangesCheck.cpp UseToStringCheck.cpp LINK_LIBS diff --git a/clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp new file mode 100644 index 0000000000000..eb9e9a262d63a --- /dev/null +++ b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.cpp @@ -0,0 +1,208 @@ +//===--- 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/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include <initializer_list> +#include <string> + +using namespace clang::ast_matchers; + +namespace clang::tidy::boost { + +namespace { +/// Base replacer that handles the boost include path and namespace +class BoostReplacer : public UseRangesCheck::Replacer { +public: + BoostReplacer(ArrayRef<ArrayRef<Indexes>> Signature, bool IncludeSystem) + : Signature(Signature), IncludeSystem(IncludeSystem) {} + + ArrayRef<ArrayRef<Indexes>> getReplacementSignatures() const final { + return Signature; + } + + virtual std::pair<StringRef, StringRef> + getBoostName(const NamedDecl &OriginalName) const = 0; + virtual std::pair<StringRef, StringRef> + getBoostHeader(const NamedDecl &OriginalName) const = 0; + + std::string getReplaceName(const NamedDecl &OriginalName) const final { + auto [Namespace, Function] = getBoostName(OriginalName); + return ("boost::" + Namespace + (Namespace.empty() ? "" : "::") + Function) + .str(); + } + + std::optional<std::string> + getHeaderInclusion(const NamedDecl &OriginalName) const final { + auto [Path, HeaderName] = getBoostHeader(OriginalName); + return ((IncludeSystem ? "<boost/" : "boost/") + Path + + (Path.empty() ? "" : "/") + HeaderName + + (IncludeSystem ? ".hpp>" : ".hpp")) + .str(); + } + +private: + ArrayRef<ArrayRef<Indexes>> Signature; + bool IncludeSystem; +}; + +/// Creates replaces where the header file lives in +/// `boost/algorithm/<FUNC_NAME>.hpp and the function is named +/// `boost::range::<FUNC_NAME>` +class BoostRangeAlgorithmReplacer : public BoostReplacer { +public: + using BoostReplacer::BoostReplacer; + std::pair<StringRef, StringRef> + getBoostName(const NamedDecl &OriginalName) const override { + return {"range", OriginalName.getName()}; + } + + std::pair<StringRef, StringRef> + getBoostHeader(const NamedDecl &OriginalName) const override { + return {"range/algorithm", OriginalName.getName()}; + } +}; + +/// Creates replaces where the header file lives in +/// `boost/algorithm/<CUSTOM_HEADER>.hpp and the function is named +/// `boost::range::<FUNC_NAME>` +class CustomBoostAlgorithmHeaderReplacer : public BoostRangeAlgorithmReplacer { +public: + CustomBoostAlgorithmHeaderReplacer(StringRef HeaderName, + ArrayRef<ArrayRef<Indexes>> Signature, + bool IncludeSystem) + : BoostRangeAlgorithmReplacer(Signature, IncludeSystem), + HeaderName(HeaderName) {} + + std::pair<StringRef, StringRef> + getBoostHeader(const NamedDecl & /*OriginalName*/) const override { + return {"range/algorithm", HeaderName}; + } + +private: + StringRef HeaderName; +}; + +/// Creates replaces where the header file lives in +/// `boost/algorithm/<SUB_HEADER>.hpp and the function is named +/// `boost::algorithm::<FUNC_NAME>` +class BoostAlgorithmReplacer : public BoostReplacer { +public: + BoostAlgorithmReplacer(StringRef SubHeader, + ArrayRef<ArrayRef<Indexes>> Signature, + bool IncludeSystem) + : BoostReplacer(Signature, IncludeSystem), + SubHeader(("algorithm/" + SubHeader).str()) {} + std::pair<StringRef, StringRef> + getBoostName(const NamedDecl &OriginalName) const override { + return {"algorithm", OriginalName.getName()}; + } + + std::pair<StringRef, StringRef> + getBoostHeader(const NamedDecl &OriginalName) const override { + return {SubHeader, OriginalName.getName()}; + } + + std::string SubHeader; +}; + +/// Creates replaces where the header file lives in +/// `boost/algorithm/<SUB_HEADER>/<HEADER_NAME>.hpp and the function is named +/// `boost::algorithm::<FUNC_NAME>` +class CustomBoostAlgorithmReplacer : public BoostReplacer { +public: + CustomBoostAlgorithmReplacer(StringRef SubHeader, StringRef HeaderName, + ArrayRef<ArrayRef<Indexes>> Signature, + bool IncludeSystem) + : BoostReplacer(Signature, IncludeSystem), + SubHeader(("algorithm/" + SubHeader).str()), HeaderName(HeaderName) {} + std::pair<StringRef, StringRef> + getBoostName(const NamedDecl &OriginalName) const override { + return {"algorithm", OriginalName.getName()}; + } + + std::pair<StringRef, StringRef> + getBoostHeader(const NamedDecl & /*OriginalName*/) const override { + return {SubHeader, HeaderName}; + } + + std::string SubHeader; + StringRef HeaderName; +}; + +} // namespace + +utils::UseRangesCheck::ReplacerMap UseRangesCheck::GetReplacerMap() const { + + ReplacerMap Results; + static const Replacer::Indexes SingleSig[] = {{0}}; + static const Replacer::Indexes TwoSig[] = {{0}, {2}}; + static const ArrayRef<Replacer::Indexes> Single = {SingleSig}; + static const ArrayRef<Replacer::Indexes> Two = {TwoSig}; + static const auto Add = + [&Results](llvm::IntrusiveRefCntPtr<BoostReplacer> Replacer, + std::initializer_list<StringRef> Names) { + for (const auto &Name : Names) { + Results.try_emplace(("::std::" + Name).str(), Replacer); + } + }; + + Add(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>( + "set_algorithm", Two, IncludeBoostSystem), + {"includes", "set_union", "set_intersection", "set_difference", + "set_symmetric_difference"}); + Add(llvm::makeIntrusiveRefCnt<BoostRangeAlgorithmReplacer>( + Single, IncludeBoostSystem), + {"unique", "lower_bound", "stable_sort", + "equal_range", "remove_if", "sort", + "random_shuffle", "remove_copy", "stable_partition", + "remove_copy_if", "count", "copy_backward", + "reverse_copy", "adjacent_find", "remove", + "upper_bound", "binary_search", "replace_copy_if", + "for_each", "generate", "count_if", + "min_element", "reverse", "replace_copy", + "fill", "unique_copy", "transform", + "copy", "replace", "find", + "replace_if", "find_if", "partition", + "max_element"}); + Add(llvm::makeIntrusiveRefCnt<BoostRangeAlgorithmReplacer>( + Two, IncludeBoostSystem), + {"find_end", "merge", "partial_sort_copy", "find_first_of", "search", + "lexicographical_compare", "equal", "mismatch"}); + Add(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>( + "permutation", Single, IncludeBoostSystem), + {"next_permutation", "prev_permutation"}); + Add(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>( + "heap_algorithm", Single, IncludeBoostSystem), + {"push_heap", "pop_heap", "make_heap", "sort_heap"}); + Add(llvm::makeIntrusiveRefCnt<BoostAlgorithmReplacer>("cxx11", Single, + IncludeBoostSystem), + {"copy_if", "is_permutation", "is_partitioned", "find_if_not", + "partition_copy", "any_of", "iota", "all_of", "partition_point", + "is_sorted", "none_of"}); + Add(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmReplacer>( + "cxx11", "is_sorted", Single, IncludeBoostSystem), + {"is_sorted_until"}); + Add(llvm::makeIntrusiveRefCnt<BoostAlgorithmReplacer>("cxx17", Single, + IncludeBoostSystem), + {"reduce"}); + + return Results; +} + +UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context) + : utils::UseRangesCheck(Name, Context), + IncludeBoostSystem(Options.get("IncludeBoostSystem", true)) {} + +void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + utils::UseRangesCheck::storeOptions(Opts); + Options.store(Opts, "IncludeBoostSystem", IncludeBoostSystem); +} +} // namespace clang::tidy::boost diff --git a/clang-tools-extra/clang-tidy/boost/UseRangesCheck.h b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.h new file mode 100644 index 0000000000000..8ae21e2c5262b --- /dev/null +++ b/clang-tools-extra/clang-tidy/boost/UseRangesCheck.h @@ -0,0 +1,34 @@ +//===--- UseRangesCheck.h - clang-tidy --------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USERANGESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USERANGESCHECK_H + +#include "../utils/UseRangesCheck.h" + +namespace clang::tidy::boost { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/boost/use-ranges.html +class UseRangesCheck : public utils::UseRangesCheck { +public: + UseRangesCheck(StringRef Name, ClangTidyContext *Context); + + void storeOptions(ClangTidyOptions::OptionMap &Options) override; + + ReplacerMap GetReplacerMap() const override; + +private: + bool IncludeBoostSystem; +}; + +} // namespace clang::tidy::boost + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BOOST_USERANGESCHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 576805c4c7f18..4f68c487cac9d 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -40,6 +40,7 @@ add_clang_library(clangTidyModernizeModule UseNoexceptCheck.cpp UseNullptrCheck.cpp UseOverrideCheck.cpp + UseRangesCheck.cpp UseStartsEndsWithCheck.cpp UseStdFormatCheck.cpp UseStdNumbersCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index b9c7a2dc383e8..1860759332063 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -41,6 +41,7 @@ #include "UseNoexceptCheck.h" #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" +#include "UseRangesCheck.h" #include "UseStartsEndsWithCheck.h" #include "UseStdFormatCheck.h" #include "UseStdNumbersCheck.h" @@ -75,6 +76,7 @@ class ModernizeModule : public ClangTidyModule { CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value"); CheckFactories.registerCheck<UseDesignatedInitializersCheck>( "modernize-use-designated-initializers"); + CheckFactories.registerCheck<UseRangesCheck>("modernize-use-ranges"); CheckFactories.registerCheck<UseStartsEndsWithCheck>( "modernize-use-starts-ends-with"); CheckFactories.registerCheck<UseStdFormatCheck>("modernize-use-std-format"); diff --git a/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp new file mode 100644 index 0000000000000..e40428a8217b7 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.cpp @@ -0,0 +1,148 @@ +//===--- 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/StringRef.h" + +namespace clang::tidy::modernize { + +utils::UseRangesCheck::ReplacerMap UseRangesCheck::GetReplacerMap() const { + class StdReplacer : public utils::UseRangesCheck::Replacer { + public: + explicit StdReplacer(ArrayRef<ArrayRef<Indexes>> Indexes) + : Indexes(Indexes) {} + std::string getReplaceName(const NamedDecl &OriginalName) const override { + return ("std::ranges::" + OriginalName.getName()).str(); + } + ArrayRef<ArrayRef<Indexes>> getReplacementSignatures() const override { + return Indexes; + } + std::optional<std::string> + getHeaderInclusion(const NamedDecl &OriginalName) const override { + return "<algorithm>"; + } + + private: + ArrayRef<ArrayRef<Indexes>> Indexes; + }; + using Indexes = UseRangesCheck::Replacer::Indexes; + // using Signatures = Signature[]; + utils::UseRangesCheck::ReplacerMap Result; + // template<typename Iter> Func(Iter first, Iter last,...). + static const Indexes SingleRangeArgs[] = {{0}}; + // template<typename Policy, typename Iter> + // Func(Policy policy, Iter first, // Iter last,...). + static const Indexes SingleRangeExecPolicy[] = {{1}}; + // template<typename Iter1, typename Iter2> + // Func(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2,...). + static const Indexes TwoRangeArgs[] = {{0}, {2}}; + // template<typename Policy, typename Iter1, typename Iter2> + // Func(Policy policy, Iter1 first1, Iter1 last1, Iter2 first2, Iter2 + // last2,...). + static const Indexes TwoRangeExecPolicy[] = {{1}, {3}}; + + static const ArrayRef<Indexes> SingleRangeFunc[] = {SingleRangeArgs}; + + static const ArrayRef<Indexes> SingleRangeExecFunc[] = { + SingleRangeArgs, SingleRangeExecPolicy}; + static const ArrayRef<Indexes> TwoRangeExecFunc[] = {TwoRangeArgs, + TwoRangeExecPolicy}; + static const ArrayRef<Indexes> OneOrTwoFunc[] = {SingleRangeArgs, + TwoRangeArgs}; + static const ArrayRef<Indexes> OneOrTwoExecFunc[] = { + SingleRangeArgs, SingleRangeExecPolicy, TwoRangeArgs, TwoRangeExecPolicy}; + + static const std::pair<ArrayRef<ArrayRef<Indexes>>, ArrayRef<StringRef>> + Names[] = { + {SingleRangeFunc, + {"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", + "iota"}}, + {SingleRangeExecFunc, + {"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"}}, + {TwoRangeExecFunc, + {"partial_sort_copy", "includes", "set_union", "set_intersection", + "set_difference", "set_symmetric_difference", "merge", + "lexicographical_compare", "find_end", "search"}}, + {OneOrTwoFunc, {"is_permutation"}}, + {OneOrTwoExecFunc, {"equal", "mismatch"}}}; + SmallString<64> Buff; + for (const auto &[Signature, Values] : Names) { + auto Replacer = llvm::makeIntrusiveRefCnt<StdReplacer>(Signature); + for (const auto &Name : Values) { + Buff.clear(); + Result.try_emplace(("::std::" + Name).toStringRef(Buff), Replacer); + } + } + return Result; +} + +bool UseRangesCheck::isLanguageVersionSupported( + const LangOptions &LangOpts) const { + return LangOpts.CPlusPlus20; +} +} // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h new file mode 100644 index 0000000000000..4cb82016d45cf --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseRangesCheck.h @@ -0,0 +1,31 @@ +//===--- UseRangesCheck.h - clang-tidy --------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USERANGESCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USERANGESCHECK_H + +#include "../utils/UseRangesCheck.h" + +namespace clang::tidy::modernize { + +/// Detects calls to standard library iterator algorithms that could be +/// replaced with a ranges version instead +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-ranges.html +class UseRangesCheck : public utils::UseRangesCheck { +public: + using utils::UseRangesCheck::UseRangesCheck; + + ReplacerMap GetReplacerMap() const override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override; +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USERANGESCHECK_H diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt index 9cff7d475425d..1841ea981359c 100644 --- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(clangTidyUtils TransformerClangTidyCheck.cpp TypeTraits.cpp UsingInserter.cpp + UseRangesCheck.cpp LINK_LIBS clangTidy diff --git a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp b... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/97764 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits