brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.5 KiB · 970cbd9 Raw
375 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 "clang/Basic/Diagnostic.h"12#include "clang/Basic/LLVM.h"13#include "llvm/ADT/ArrayRef.h"14#include "llvm/ADT/IntrusiveRefCntPtr.h"15#include "llvm/ADT/SmallString.h"16#include "llvm/ADT/SmallVector.h"17#include "llvm/ADT/StringRef.h"18#include <initializer_list>19#include <optional>20#include <string>21#include <utility>22 23// FixItHint - Let the docs script know that this class does provide fixits24 25namespace clang::tidy::boost {26 27namespace {28/// Base replacer that handles the boost include path and namespace29class BoostReplacer : public UseRangesCheck::Replacer {30public:31  BoostReplacer(ArrayRef<UseRangesCheck::Signature> Signatures,32                bool IncludeSystem)33      : Signatures(Signatures), IncludeSystem(IncludeSystem) {}34 35  ArrayRef<UseRangesCheck::Signature> getReplacementSignatures() const final {36    return Signatures;37  }38 39  virtual std::pair<StringRef, StringRef>40  getBoostName(const NamedDecl &OriginalName) const = 0;41 42  virtual std::pair<StringRef, StringRef>43  getBoostHeader(const NamedDecl &OriginalName) const = 0;44 45  std::optional<std::string>46  getReplaceName(const NamedDecl &OriginalName) const final {47    auto [Namespace, Function] = getBoostName(OriginalName);48    return ("boost::" + Namespace + (Namespace.empty() ? "" : "::") + Function)49        .str();50  }51 52  std::optional<std::string>53  getHeaderInclusion(const NamedDecl &OriginalName) const final {54    auto [Path, HeaderName] = getBoostHeader(OriginalName);55    return ((IncludeSystem ? "<boost/" : "boost/") + Path +56            (Path.empty() ? "" : "/") + HeaderName +57            (IncludeSystem ? ".hpp>" : ".hpp"))58        .str();59  }60 61private:62  SmallVector<UseRangesCheck::Signature> Signatures;63  bool IncludeSystem;64};65 66/// Creates replaces where the header file lives in67/// `boost/algorithm/<FUNC_NAME>.hpp` and the function is named68/// `boost::range::<FUNC_NAME>`69class BoostRangeAlgorithmReplacer : public BoostReplacer {70public:71  using BoostReplacer::BoostReplacer;72 73  std::pair<StringRef, StringRef>74  getBoostName(const NamedDecl &OriginalName) const override {75    return {"range", OriginalName.getName()};76  }77 78  std::pair<StringRef, StringRef>79  getBoostHeader(const NamedDecl &OriginalName) const override {80    return {"range/algorithm", OriginalName.getName()};81  }82};83 84/// Creates replaces where the header file lives in85/// `boost/algorithm/<CUSTOM_HEADER>.hpp` and the function is named86/// `boost::range::<FUNC_NAME>`87class CustomBoostAlgorithmHeaderReplacer : public BoostRangeAlgorithmReplacer {88public:89  CustomBoostAlgorithmHeaderReplacer(90      StringRef HeaderName, ArrayRef<UseRangesCheck::Signature> Signatures,91      bool IncludeSystem)92      : BoostRangeAlgorithmReplacer(Signatures, IncludeSystem),93        HeaderName(HeaderName) {}94 95  std::pair<StringRef, StringRef>96  getBoostHeader(const NamedDecl & /*OriginalName*/) const override {97    return {"range/algorithm", HeaderName};98  }99 100private:101  StringRef HeaderName;102};103 104/// Creates replaces where the header file lives in105/// `boost/algorithm/<SUB_HEADER>.hpp` and the function is named106/// `boost::algorithm::<FUNC_NAME>`107class BoostAlgorithmReplacer : public BoostReplacer {108public:109  BoostAlgorithmReplacer(StringRef SubHeader,110                         ArrayRef<UseRangesCheck::Signature> Signatures,111                         bool IncludeSystem)112      : BoostReplacer(Signatures, IncludeSystem),113        SubHeader(("algorithm/" + SubHeader).str()) {}114  std::pair<StringRef, StringRef>115  getBoostName(const NamedDecl &OriginalName) const override {116    return {"algorithm", OriginalName.getName()};117  }118 119  std::pair<StringRef, StringRef>120  getBoostHeader(const NamedDecl &OriginalName) const override {121    return {SubHeader, OriginalName.getName()};122  }123 124private:125  std::string SubHeader;126};127 128/// Creates replaces where the header file lives in129/// `boost/algorithm/<SUB_HEADER>/<HEADER_NAME>.hpp` and the function is named130/// `boost::algorithm::<FUNC_NAME>`131class CustomBoostAlgorithmReplacer : public BoostReplacer {132public:133  CustomBoostAlgorithmReplacer(StringRef SubHeader, StringRef HeaderName,134                               ArrayRef<UseRangesCheck::Signature> Signatures,135                               bool IncludeSystem)136      : BoostReplacer(Signatures, IncludeSystem),137        SubHeader(("algorithm/" + SubHeader).str()), HeaderName(HeaderName) {}138  std::pair<StringRef, StringRef>139  getBoostName(const NamedDecl &OriginalName) const override {140    return {"algorithm", OriginalName.getName()};141  }142 143  std::pair<StringRef, StringRef>144  getBoostHeader(const NamedDecl & /*OriginalName*/) const override {145    return {SubHeader, HeaderName};146  }147 148private:149  std::string SubHeader;150  StringRef HeaderName;151};152 153/// A Replacer that is used for functions that just call a new overload154class MakeOverloadReplacer : public UseRangesCheck::Replacer {155public:156  explicit MakeOverloadReplacer(ArrayRef<UseRangesCheck::Signature> Signatures)157      : Signatures(Signatures) {}158 159  ArrayRef<UseRangesCheck::Signature>160  getReplacementSignatures() const override {161    return Signatures;162  }163 164  std::optional<std::string>165  getReplaceName(const NamedDecl & /* OriginalName */) const override {166    return std::nullopt;167  }168 169  std::optional<std::string>170  getHeaderInclusion(const NamedDecl & /* OriginalName */) const override {171    return std::nullopt;172  }173 174private:175  SmallVector<UseRangesCheck::Signature> Signatures;176};177 178/// A replacer that replaces functions with an equivalent named function in the179/// root boost namespace180class FixedBoostReplace : public BoostReplacer {181public:182  FixedBoostReplace(StringRef Header,183                    ArrayRef<UseRangesCheck::Signature> Signatures,184                    bool IncludeBoostSystem)185      : BoostReplacer(Signatures, IncludeBoostSystem), Header(Header) {}186 187  std::pair<StringRef, StringRef>188  getBoostName(const NamedDecl &OriginalName) const override {189    return {{}, OriginalName.getName()};190  }191 192  std::pair<StringRef, StringRef>193  getBoostHeader(const NamedDecl & /* OriginalName */) const override {194    return {{}, Header};195  }196 197private:198  StringRef Header;199};200 201} // namespace202 203utils::UseRangesCheck::ReplacerMap UseRangesCheck::getReplacerMap() const {204  ReplacerMap Results;205  static const Signature SingleSig = {{0}};206  static const Signature TwoSig = {{0}, {2}};207  const auto AddFrom =208      [&Results](llvm::IntrusiveRefCntPtr<UseRangesCheck::Replacer> Replacer,209                 std::initializer_list<StringRef> Names, StringRef Prefix) {210        llvm::SmallString<64> Buffer;211        for (const auto &Name : Names) {212          Buffer.assign({"::", Prefix, (Prefix.empty() ? "" : "::"), Name});213          Results.try_emplace(Buffer, Replacer);214        }215      };216 217  const auto AddFromStd =218      [&](llvm::IntrusiveRefCntPtr<UseRangesCheck::Replacer> Replacer,219          std::initializer_list<StringRef> Names) {220        AddFrom(std::move(Replacer), Names, "std");221      };222 223  const auto AddFromBoost =224      [&](const llvm::IntrusiveRefCntPtr<UseRangesCheck::Replacer> &Replacer,225          std::initializer_list<226              std::pair<StringRef, std::initializer_list<StringRef>>>227              NamespaceAndNames) {228        for (auto [Namespace, Names] : NamespaceAndNames)229          AddFrom(Replacer, Names,230                  SmallString<64>{"boost", (Namespace.empty() ? "" : "::"),231                                  Namespace});232      };233 234  AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>(235                 "set_algorithm", TwoSig, IncludeBoostSystem),236             {"includes", "set_union", "set_intersection", "set_difference",237              "set_symmetric_difference"});238 239  AddFromStd(llvm::makeIntrusiveRefCnt<BoostRangeAlgorithmReplacer>(240                 SingleSig, IncludeBoostSystem),241             {"unique",         "lower_bound",   "stable_sort",242              "equal_range",    "remove_if",     "sort",243              "random_shuffle", "remove_copy",   "stable_partition",244              "remove_copy_if", "count",         "copy_backward",245              "reverse_copy",   "adjacent_find", "remove",246              "upper_bound",    "binary_search", "replace_copy_if",247              "for_each",       "generate",      "count_if",248              "min_element",    "reverse",       "replace_copy",249              "fill",           "unique_copy",   "transform",250              "copy",           "replace",       "find",251              "replace_if",     "find_if",       "partition",252              "max_element"});253 254  AddFromStd(llvm::makeIntrusiveRefCnt<BoostRangeAlgorithmReplacer>(255                 TwoSig, IncludeBoostSystem),256             {"find_end", "merge", "partial_sort_copy", "find_first_of",257              "search", "lexicographical_compare", "equal", "mismatch"});258 259  AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>(260                 "permutation", SingleSig, IncludeBoostSystem),261             {"next_permutation", "prev_permutation"});262 263  AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmHeaderReplacer>(264                 "heap_algorithm", SingleSig, IncludeBoostSystem),265             {"push_heap", "pop_heap", "make_heap", "sort_heap"});266 267  AddFromStd(llvm::makeIntrusiveRefCnt<BoostAlgorithmReplacer>(268                 "cxx11", SingleSig, IncludeBoostSystem),269             {"copy_if", "is_permutation", "is_partitioned", "find_if_not",270              "partition_copy", "any_of", "iota", "all_of", "partition_point",271              "is_sorted", "none_of"});272 273  AddFromStd(llvm::makeIntrusiveRefCnt<CustomBoostAlgorithmReplacer>(274                 "cxx11", "is_sorted", SingleSig, IncludeBoostSystem),275             {"is_sorted_until"});276 277  AddFromStd(llvm::makeIntrusiveRefCnt<FixedBoostReplace>(278                 "range/numeric", SingleSig, IncludeBoostSystem),279             {"accumulate", "partial_sum", "adjacent_difference"});280 281  if (getLangOpts().CPlusPlus17)282    AddFromStd(llvm::makeIntrusiveRefCnt<BoostAlgorithmReplacer>(283                   "cxx17", SingleSig, IncludeBoostSystem),284               {"reduce"});285 286  AddFromBoost(llvm::makeIntrusiveRefCnt<MakeOverloadReplacer>(SingleSig),287               {{"algorithm",288                 {"reduce",289                  "find_backward",290                  "find_not_backward",291                  "find_if_backward",292                  "find_if_not_backward",293                  "hex",294                  "hex_lower",295                  "unhex",296                  "is_partitioned_until",297                  "is_palindrome",298                  "copy_if",299                  "copy_while",300                  "copy_until",301                  "copy_if_while",302                  "copy_if_until",303                  "is_permutation",304                  "is_partitioned",305                  "one_of",306                  "one_of_equal",307                  "find_if_not",308                  "partition_copy",309                  "any_of",310                  "any_of_equal",311                  "iota",312                  "all_of",313                  "all_of_equal",314                  "partition_point",315                  "is_sorted_until",316                  "is_sorted",317                  "is_increasing",318                  "is_decreasing",319                  "is_strictly_increasing",320                  "is_strictly_decreasing",321                  "none_of",322                  "none_of_equal",323                  "clamp_range"}}});324 325  AddFromBoost(326      llvm::makeIntrusiveRefCnt<MakeOverloadReplacer>(TwoSig),327      {{"algorithm", {"apply_permutation", "apply_reverse_permutation"}}});328 329  return Results;330}331 332UseRangesCheck::UseRangesCheck(StringRef Name, ClangTidyContext *Context)333    : utils::UseRangesCheck(Name, Context),334      IncludeBoostSystem(Options.get("IncludeBoostSystem", true)),335      UseReversePipe(Options.get("UseReversePipe", false)) {}336 337void UseRangesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {338  utils::UseRangesCheck::storeOptions(Opts);339  Options.store(Opts, "IncludeBoostSystem", IncludeBoostSystem);340  Options.store(Opts, "UseReversePipe", UseReversePipe);341}342 343DiagnosticBuilder UseRangesCheck::createDiag(const CallExpr &Call) {344  const DiagnosticBuilder D =345      diag(Call.getBeginLoc(), "use a %0 version of this algorithm");346  D << (Call.getDirectCallee()->isInStdNamespace() ? "boost" : "ranged");347  return D;348}349ArrayRef<std::pair<StringRef, StringRef>>350UseRangesCheck::getFreeBeginEndMethods() const {351  static const std::pair<StringRef, StringRef> Refs[] = {352      {"::std::begin", "::std::end"},353      {"::std::cbegin", "::std::cend"},354      {"::boost::range_adl_barrier::begin", "::boost::range_adl_barrier::end"},355      {"::boost::range_adl_barrier::const_begin",356       "::boost::range_adl_barrier::const_end"},357  };358  return Refs;359}360std::optional<UseRangesCheck::ReverseIteratorDescriptor>361UseRangesCheck::getReverseDescriptor() const {362  static const std::pair<StringRef, StringRef> Refs[] = {363      {"::std::rbegin", "::std::rend"},364      {"::std::crbegin", "::std::crend"},365      {"::boost::rbegin", "::boost::rend"},366      {"::boost::const_rbegin", "::boost::const_rend"},367  };368  return ReverseIteratorDescriptor{369      UseReversePipe ? "boost::adaptors::reversed" : "boost::adaptors::reverse",370      IncludeBoostSystem ? "<boost/range/adaptor/reversed.hpp>"371                         : "boost/range/adaptor/reversed.hpp",372      Refs, UseReversePipe};373}374} // namespace clang::tidy::boost375