brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.8 KiB · 06982b8 Raw
319 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 "TypeTraitsCheck.h"10#include "clang/ASTMatchers/ASTMatchFinder.h"11#include "clang/ASTMatchers/ASTMatchers.h"12#include "clang/Lex/Lexer.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::modernize {17 18// FIXME: Add chrono::treat_as_floating_point_v and chrono::is_clock_v.19// This will require restructuring the code to handle type traits not20// defined directly in std.21static const llvm::StringSet<> ValueTraits = {22    "alignment_of",23    "conjunction",24    "disjunction",25    "extent",26    "has_unique_object_representations",27    "has_virtual_destructor",28    "is_abstract",29    "is_aggregate",30    "is_arithmetic",31    "is_array",32    "is_assignable",33    "is_base_of",34    "is_bind_expression",35    "is_bounded_array",36    "is_class",37    "is_compound",38    "is_const",39    "is_constructible",40    "is_convertible",41    "is_copy_assignable",42    "is_copy_constructible",43    "is_default_constructible",44    "is_destructible",45    "is_empty",46    "is_enum",47    "is_error_code_enum",48    "is_error_condition_enum",49    "is_execution_policy",50    "is_final",51    "is_floating_point",52    "is_function",53    "is_fundamental",54    "is_implicit_lifetime",55    "is_integral",56    "is_invocable",57    "is_invocable_r",58    "is_layout_compatible",59    "is_lvalue_reference",60    "is_member_function_pointer",61    "is_member_object_pointer",62    "is_member_pointer",63    "is_move_assignable",64    "is_move_constructible",65    "is_nothrow_assignable",66    "is_nothrow_constructible",67    "is_nothrow_convertible",68    "is_nothrow_copy_assignable",69    "is_nothrow_copy_constructible",70    "is_nothrow_default_constructible",71    "is_nothrow_destructible",72    "is_nothrow_invocable",73    "is_nothrow_invocable_r",74    "is_nothrow_move_assignable",75    "is_nothrow_move_constructible",76    "is_nothrow_relocatable",77    "is_nothrow_swappable",78    "is_nothrow_swappable_with",79    "is_null_pointer",80    "is_object",81    "is_placeholder",82    "is_pointer",83    "is_pointer_interconvertible_base_of",84    "is_polymorphic",85    "is_reference",86    "is_replaceable",87    "is_rvalue_reference",88    "is_same",89    "is_scalar",90    "is_scoped_enum",91    "is_signed",92    "is_standard_layout",93    "is_swappable",94    "is_swappable_with",95    "is_trivial",96    "is_trivially_assignable",97    "is_trivially_constructible",98    "is_trivially_copy_assignable",99    "is_trivially_copy_constructible",100    "is_trivially_copyable",101    "is_trivially_default_constructible",102    "is_trivially_destructible",103    "is_trivially_move_assignable",104    "is_trivially_move_constructible",105    "is_trivially_relocatable",106    "is_unbounded_array",107    "is_union",108    "is_unsigned",109    "is_virtual_base_of",110    "is_void",111    "is_volatile",112    "negation",113    "rank",114    "ratio_equal",115    "ratio_greater_equal",116    "ratio_greater",117    "ratio_less_equal",118    "ratio_less",119    "ratio_not_equal",120    "reference_constructs_from_temporary",121    "reference_converts_from_temporary",122    "tuple_size",123    "uses_allocator",124    "variant_size",125};126 127static const llvm::StringSet<> TypeTraits = {128    "remove_cv",129    "remove_const",130    "remove_volatile",131    "add_cv",132    "add_const",133    "add_volatile",134    "remove_reference",135    "add_lvalue_reference",136    "add_rvalue_reference",137    "remove_pointer",138    "add_pointer",139    "make_signed",140    "make_unsigned",141    "remove_extent",142    "remove_all_extents",143    "aligned_storage",144    "aligned_union",145    "decay",146    "remove_cvref",147    "enable_if",148    "conditional",149    "common_type",150    "common_reference",151    "underlying_type",152    "result_of",153    "invoke_result",154    "type_identity",155    "compare_three_way_result",156    "common_comparison_category",157    "unwrap_ref_decay",158    "unwrap_reference",159    "tuple_element",160    "variant_alternative",161};162 163static DeclarationName getName(const DependentScopeDeclRefExpr &D) {164  return D.getDeclName();165}166 167static DeclarationName getName(const DeclRefExpr &D) {168  return D.getDecl()->getDeclName();169}170 171namespace {172AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES(173                                     DeclRefExpr, DependentScopeDeclRefExpr)) {174  const IdentifierInfo *Ident = getName(Node).getAsIdentifierInfo();175  return Ident && Ident->isStr("value");176}177 178AST_MATCHER(TypeLoc, isType) {179  if (auto TL = Node.getAs<TypedefTypeLoc>()) {180    const auto *TD = TL.getDecl();181    return TD->getDeclName().isIdentifier() && TD->getName() == "type";182  }183  if (auto TL = Node.getAs<DependentNameTypeLoc>())184    return TL.getTypePtr()->getIdentifier()->getName() == "type";185  return false;186}187} // namespace188 189static constexpr char Bind[] = "";190 191void TypeTraitsCheck::registerMatchers(MatchFinder *Finder) {192  // Only register matchers for trait<...>::value in c++17 mode.193  if (getLangOpts().CPlusPlus17) {194    Finder->addMatcher(mapAnyOf(declRefExpr, dependentScopeDeclRefExpr)195                           .with(isValue())196                           .bind(Bind),197                       this);198  }199  Finder->addMatcher(typeLoc(isType()).bind(Bind), this);200}201 202static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND,203                                      const llvm::StringSet<> &Set) {204  return ND->isInStdNamespace() && ND->getDeclName().isIdentifier() &&205         Set.contains(ND->getName());206}207 208static bool checkTemplatedDecl(NestedNameSpecifier NNS,209                               const llvm::StringSet<> &Set) {210  if (NNS.getKind() != NestedNameSpecifier::Kind::Type)211    return false;212  const auto *TST = NNS.getAsType()->getAs<TemplateSpecializationType>();213  if (!TST)214    return false;215  if (const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) {216    return isNamedDeclInStdTraitsSet(TD, Set);217  }218  return false;219}220 221TypeTraitsCheck::TypeTraitsCheck(StringRef Name, ClangTidyContext *Context)222    : ClangTidyCheck(Name, Context),223      IgnoreMacros(Options.get("IgnoreMacros", false)) {}224 225void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {226  auto EmitValueWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc,227                                          SourceLocation EndLoc) {228    SourceLocation TemplateNameEndLoc;229    if (auto TSTL =230            QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>())231      TemplateNameEndLoc = Lexer::getLocForEndOfToken(232          TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,233          Result.Context->getLangOpts());234    else235      return;236 237    if (EndLoc.isMacroID() || QualLoc.getEndLoc().isMacroID() ||238        TemplateNameEndLoc.isMacroID()) {239      if (IgnoreMacros)240        return;241      diag(QualLoc.getBeginLoc(), "use c++17 style variable templates");242      return;243    }244    diag(QualLoc.getBeginLoc(), "use c++17 style variable templates")245        << FixItHint::CreateInsertion(TemplateNameEndLoc, "_v")246        << FixItHint::CreateRemoval({QualLoc.getEndLoc(), EndLoc});247  };248 249  auto EmitTypeWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc,250                                         SourceLocation EndLoc,251                                         SourceLocation TypenameLoc) {252    SourceLocation TemplateNameEndLoc;253    if (auto TSTL =254            QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>())255      TemplateNameEndLoc = Lexer::getLocForEndOfToken(256          TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,257          Result.Context->getLangOpts());258    else259      return;260 261    if (EndLoc.isMacroID() || QualLoc.getEndLoc().isMacroID() ||262        TemplateNameEndLoc.isMacroID() || TypenameLoc.isMacroID()) {263      if (IgnoreMacros)264        return;265      diag(QualLoc.getBeginLoc(), "use c++14 style type templates");266      return;267    }268    auto Diag = diag(QualLoc.getBeginLoc(), "use c++14 style type templates");269 270    if (TypenameLoc.isValid())271      Diag << FixItHint::CreateRemoval(TypenameLoc);272    Diag << FixItHint::CreateInsertion(TemplateNameEndLoc, "_t")273         << FixItHint::CreateRemoval({QualLoc.getEndLoc(), EndLoc});274  };275 276  if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>(Bind)) {277    if (!DRE->hasQualifier())278      return;279    if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(280            DRE->getQualifier().getAsRecordDecl())) {281      if (isNamedDeclInStdTraitsSet(CTSD, ValueTraits))282        EmitValueWarning(DRE->getQualifierLoc(), DRE->getEndLoc());283    }284    return;285  }286 287  if (const auto *TL = Result.Nodes.getNodeAs<TypedefTypeLoc>(Bind)) {288    const NestedNameSpecifierLoc QualLoc = TL->getQualifierLoc();289    const NestedNameSpecifier NNS = QualLoc.getNestedNameSpecifier();290    if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(291            NNS.getAsRecordDecl())) {292      if (isNamedDeclInStdTraitsSet(CTSD, TypeTraits))293        EmitTypeWarning(TL->getQualifierLoc(), TL->getEndLoc(),294                        TL->getElaboratedKeywordLoc());295    }296    return;297  }298 299  if (const auto *DSDRE =300          Result.Nodes.getNodeAs<DependentScopeDeclRefExpr>(Bind)) {301    if (checkTemplatedDecl(DSDRE->getQualifier(), ValueTraits))302      EmitValueWarning(DSDRE->getQualifierLoc(), DSDRE->getEndLoc());303    return;304  }305 306  if (const auto *DNTL = Result.Nodes.getNodeAs<DependentNameTypeLoc>(Bind)) {307    const NestedNameSpecifierLoc QualLoc = DNTL->getQualifierLoc();308    if (checkTemplatedDecl(QualLoc.getNestedNameSpecifier(), TypeTraits))309      EmitTypeWarning(QualLoc, DNTL->getEndLoc(),310                      DNTL->getElaboratedKeywordLoc());311    return;312  }313}314 315void TypeTraitsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {316  Options.store(Opts, "IgnoreMacros", IgnoreMacros);317}318} // namespace clang::tidy::modernize319