[clang-tools-extra] 376168b - [clang-tidy] Add modernize-type-traits check

Nathan James via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 7 10:38:29 PDT 2023


Author: Nathan James
Date: 2023-04-07T18:38:15+01:00
New Revision: 376168babb51aa08bc864d4797db4a6dbd53fdbc

URL: https://github.com/llvm/llvm-project/commit/376168babb51aa08bc864d4797db4a6dbd53fdbc
DIFF: https://github.com/llvm/llvm-project/commit/376168babb51aa08bc864d4797db4a6dbd53fdbc.diff

LOG: [clang-tidy] Add modernize-type-traits check

This check will look for usages of standard library type traits of the form `traits<...>::type` and `traits<...>::value` and convert them into `traits_t<...>` and `traits_v<...>` respectively.
This expands on the work in D135404 by supporting dependent traits with no instantiations as well as types.

Differential Revision: https://reviews.llvm.org/D137302

Added: 
    clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
    clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.h
    clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst
    clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits.cpp

Modified: 
    clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
    clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/list.rst

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 9d13001037b8e..91e2d8d5ee4e5 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -25,6 +25,7 @@ add_clang_library(clangTidyModernizeModule
   ReplaceRandomShuffleCheck.cpp
   ReturnBracedInitListCheck.cpp
   ShrinkToFitCheck.cpp
+  TypeTraitsCheck.cpp
   UnaryStaticAssertCheck.cpp
   UseAutoCheck.cpp
   UseBoolLiteralsCheck.cpp

diff  --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 9f116f92c1fb1..ee0fab18d2068 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -26,6 +26,7 @@
 #include "ReplaceRandomShuffleCheck.h"
 #include "ReturnBracedInitListCheck.h"
 #include "ShrinkToFitCheck.h"
+#include "TypeTraitsCheck.h"
 #include "UnaryStaticAssertCheck.h"
 #include "UseAutoCheck.h"
 #include "UseBoolLiteralsCheck.h"
@@ -76,6 +77,7 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<ReturnBracedInitListCheck>(
         "modernize-return-braced-init-list");
     CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
+    CheckFactories.registerCheck<TypeTraitsCheck>("modernize-type-traits");
     CheckFactories.registerCheck<UnaryStaticAssertCheck>(
         "modernize-unary-static-assert");
     CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");

diff  --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
new file mode 100644
index 0000000000000..c0766395ec5cc
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
@@ -0,0 +1,316 @@
+//===--- TypeTraitsCheck.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 "TypeTraitsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+static const llvm::StringSet<> ValueTraits = {
+    "alignment_of",
+    "conjunction",
+    "disjunction",
+    "extent",
+    "has_unique_object_representations",
+    "has_virtual_destructor",
+    "is_abstract",
+    "is_aggregate",
+    "is_arithmetic",
+    "is_array",
+    "is_assignable",
+    "is_base_of",
+    "is_bounded_array",
+    "is_class",
+    "is_compound",
+    "is_const",
+    "is_constructible",
+    "is_convertible",
+    "is_copy_assignable",
+    "is_copy_constructible",
+    "is_default_constructible",
+    "is_destructible",
+    "is_empty",
+    "is_enum",
+    "is_final",
+    "is_floating_point",
+    "is_function",
+    "is_fundamental",
+    "is_integral",
+    "is_invocable",
+    "is_invocable_r",
+    "is_layout_compatible",
+    "is_lvalue_reference",
+    "is_member_function_pointer",
+    "is_member_object_pointer",
+    "is_member_pointer",
+    "is_move_assignable",
+    "is_move_constructible",
+    "is_nothrow_assignable",
+    "is_nothrow_constructible",
+    "is_nothrow_convertible",
+    "is_nothrow_copy_assignable",
+    "is_nothrow_copy_constructible",
+    "is_nothrow_default_constructible",
+    "is_nothrow_destructible",
+    "is_nothrow_invocable",
+    "is_nothrow_invocable_r",
+    "is_nothrow_move_assignable",
+    "is_nothrow_move_constructible",
+    "is_nothrow_swappable",
+    "is_nothrow_swappable_with",
+    "is_null_pointer",
+    "is_object",
+    "is_pointer",
+    "is_pointer_interconvertible_base_of",
+    "is_polymorphic",
+    "is_reference",
+    "is_rvalue_reference",
+    "is_same",
+    "is_scalar",
+    "is_scoped_enum",
+    "is_signed",
+    "is_standard_layout",
+    "is_swappable",
+    "is_swappable_with",
+    "is_trivial",
+    "is_trivially_assignable",
+    "is_trivially_constructible",
+    "is_trivially_copy_assignable",
+    "is_trivially_copy_constructible",
+    "is_trivially_copyable",
+    "is_trivially_default_constructible",
+    "is_trivially_destructible",
+    "is_trivially_move_assignable",
+    "is_trivially_move_constructible",
+    "is_unbounded_array",
+    "is_union",
+    "is_unsigned",
+    "is_void",
+    "is_volatile",
+    "negation",
+    "rank",
+    "reference_constructs_from_temporary",
+    "reference_converts_from_temporary",
+};
+
+static const llvm::StringSet<> TypeTraits = {
+    "remove_cv",
+    "remove_const",
+    "remove_volatile",
+    "add_cv",
+    "add_const",
+    "add_volatile",
+    "remove_reference",
+    "add_lvalue_reference",
+    "add_rvalue_reference",
+    "remove_pointer",
+    "add_pointer",
+    "make_signed",
+    "make_unsigned",
+    "remove_extent",
+    "remove_all_extents",
+    "aligned_storage",
+    "aligned_union",
+    "decay",
+    "remove_cvref",
+    "enable_if",
+    "conditional",
+    "common_type",
+    "common_reference",
+    "underlying_type",
+    "result_of",
+    "invoke_result",
+    "type_identity",
+};
+
+static DeclarationName getName(const DependentScopeDeclRefExpr &D) {
+  return D.getDeclName();
+}
+
+static DeclarationName getName(const DeclRefExpr &D) {
+  return D.getDecl()->getDeclName();
+}
+
+static bool isNamedType(const ElaboratedTypeLoc &ETL) {
+  if (const auto *TFT =
+          ETL.getNamedTypeLoc().getTypePtr()->getAs<TypedefType>()) {
+    const TypedefNameDecl *Decl = TFT->getDecl();
+    return Decl->getDeclName().isIdentifier() && Decl->getName() == "type";
+  }
+  return false;
+}
+
+static bool isNamedType(const DependentNameTypeLoc &DTL) {
+  return DTL.getTypePtr()->getIdentifier()->getName() == "type";
+}
+
+namespace {
+AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES(
+                                     DeclRefExpr, DependentScopeDeclRefExpr)) {
+  const IdentifierInfo *Ident = getName(Node).getAsIdentifierInfo();
+  return Ident && Ident->isStr("value");
+}
+
+AST_POLYMORPHIC_MATCHER(isType,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(ElaboratedTypeLoc,
+                                                        DependentNameTypeLoc)) {
+  return Node.getBeginLoc().isValid() && isNamedType(Node);
+}
+} // namespace
+
+static constexpr char Bind[] = "";
+
+void TypeTraitsCheck::registerMatchers(MatchFinder *Finder) {
+  const ast_matchers::internal::VariadicDynCastAllOfMatcher<
+      Stmt,
+      DependentScopeDeclRefExpr>
+      dependentScopeDeclRefExpr; // NOLINT(readability-identifier-naming)
+  const ast_matchers::internal::VariadicDynCastAllOfMatcher<
+      TypeLoc,
+      DependentNameTypeLoc>
+      dependentNameTypeLoc; // NOLINT(readability-identifier-naming)
+
+  // Only register matchers for trait<...>::value in c++17 mode.
+  if (getLangOpts().CPlusPlus17) {
+    Finder->addMatcher(mapAnyOf(declRefExpr, dependentScopeDeclRefExpr)
+                           .with(isValue())
+                           .bind(Bind),
+                       this);
+  }
+  Finder->addMatcher(mapAnyOf(elaboratedTypeLoc, dependentNameTypeLoc)
+                         .with(isType())
+                         .bind(Bind),
+                     this);
+}
+
+static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND,
+                                      const llvm::StringSet<> &Set) {
+  return ND->isInStdNamespace() && ND->getDeclName().isIdentifier() &&
+         Set.contains(ND->getName());
+}
+
+static bool checkTemplatedDecl(const NestedNameSpecifier *NNS,
+                               const llvm::StringSet<> &Set) {
+  if (!NNS)
+    return false;
+  const Type *NNST = NNS->getAsType();
+  if (!NNST)
+    return false;
+  const auto *TST = NNST->getAs<TemplateSpecializationType>();
+  if (!TST)
+    return false;
+  if (const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) {
+    return isNamedDeclInStdTraitsSet(TD, Set);
+  }
+  return false;
+}
+
+TypeTraitsCheck::TypeTraitsCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", false)) {}
+
+void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
+  auto EmitValueWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc,
+                                          SourceLocation EndLoc) {
+    SourceLocation TemplateNameEndLoc;
+    if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
+        !TSTL.isNull())
+      TemplateNameEndLoc = Lexer::getLocForEndOfToken(
+          TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
+          Result.Context->getLangOpts());
+    else
+      return;
+
+    if (EndLoc.isMacroID() || QualLoc.getEndLoc().isMacroID() ||
+        TemplateNameEndLoc.isMacroID()) {
+      if (IgnoreMacros)
+        return;
+      diag(QualLoc.getBeginLoc(), "use c++17 style variable templates");
+      return;
+    }
+    diag(QualLoc.getBeginLoc(), "use c++17 style variable templates")
+        << FixItHint::CreateInsertion(TemplateNameEndLoc, "_v")
+        << FixItHint::CreateRemoval({QualLoc.getEndLoc(), EndLoc});
+  };
+
+  auto EmitTypeWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc,
+                                         SourceLocation EndLoc,
+                                         SourceLocation TypenameLoc) {
+    SourceLocation TemplateNameEndLoc;
+    if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
+        !TSTL.isNull())
+      TemplateNameEndLoc = Lexer::getLocForEndOfToken(
+          TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
+          Result.Context->getLangOpts());
+    else
+      return;
+
+    if (EndLoc.isMacroID() || QualLoc.getEndLoc().isMacroID() ||
+        TemplateNameEndLoc.isMacroID() || TypenameLoc.isMacroID()) {
+      if (IgnoreMacros)
+        return;
+      diag(QualLoc.getBeginLoc(), "use c++14 style type templates");
+      return;
+    }
+    auto Diag = diag(QualLoc.getBeginLoc(), "use c++14 style type templates");
+
+    if (TypenameLoc.isValid())
+      Diag << FixItHint::CreateRemoval(TypenameLoc);
+    Diag << FixItHint::CreateInsertion(TemplateNameEndLoc, "_t")
+         << FixItHint::CreateRemoval({QualLoc.getEndLoc(), EndLoc});
+  };
+
+  if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>(Bind)) {
+    if (!DRE->hasQualifier())
+      return;
+    if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
+            DRE->getQualifier()->getAsRecordDecl())) {
+      if (isNamedDeclInStdTraitsSet(CTSD, ValueTraits))
+        EmitValueWarning(DRE->getQualifierLoc(), DRE->getEndLoc());
+    }
+    return;
+  }
+
+  if (const auto *ETL = Result.Nodes.getNodeAs<ElaboratedTypeLoc>(Bind)) {
+    const NestedNameSpecifierLoc QualLoc = ETL->getQualifierLoc();
+    const auto *NNS = QualLoc.getNestedNameSpecifier();
+    if (!NNS)
+      return;
+    if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
+            NNS->getAsRecordDecl())) {
+      if (isNamedDeclInStdTraitsSet(CTSD, TypeTraits))
+        EmitTypeWarning(ETL->getQualifierLoc(), ETL->getEndLoc(),
+                        ETL->getElaboratedKeywordLoc());
+    }
+    return;
+  }
+
+  if (const auto *DSDRE =
+          Result.Nodes.getNodeAs<DependentScopeDeclRefExpr>(Bind)) {
+    if (checkTemplatedDecl(DSDRE->getQualifier(), ValueTraits))
+      EmitValueWarning(DSDRE->getQualifierLoc(), DSDRE->getEndLoc());
+    return;
+  }
+
+  if (const auto *DNTL = Result.Nodes.getNodeAs<DependentNameTypeLoc>(Bind)) {
+    NestedNameSpecifierLoc QualLoc = DNTL->getQualifierLoc();
+    if (checkTemplatedDecl(QualLoc.getNestedNameSpecifier(), TypeTraits))
+      EmitTypeWarning(QualLoc, DNTL->getEndLoc(),
+                      DNTL->getElaboratedKeywordLoc());
+    return;
+  }
+}
+
+void TypeTraitsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IgnoreMacros", IgnoreMacros);
+}
+} // namespace clang::tidy::modernize

diff  --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.h b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.h
new file mode 100644
index 0000000000000..a08b96fd9f13e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.h
@@ -0,0 +1,40 @@
+//===--- TypeTraitsCheck.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_TYPETRAITSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_TYPETRAITSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Converts standard library type traits of the form `traits<...>::type` and
+/// `traits<...>::value` into `traits_t<...>` and `traits_v<...>` respectively.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/type-traits.html
+class TypeTraitsCheck : public ClangTidyCheck {
+public:
+  TypeTraitsCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus14;
+  }
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  const bool IgnoreMacros;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_TYPETRAITSCHECK_H

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index c10c6fd9d93d1..e67495b045512 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -133,6 +133,12 @@ New checks
   Checks that all implicit and explicit inline functions in header files are
   tagged with the ``LIBC_INLINE`` macro.
 
+- New :doc:`modernize-type-traits
+  <clang-tidy/checks/modernize/type-traits>` check.
+
+  Converts standard library type traits of the form ``traits<...>::type`` and
+  ``traits<...>::value`` into ``traits_t<...>`` and ``traits_v<...>`` respectively.
+
 - New :doc:`readability-avoid-unconditional-preprocessor-if
   <clang-tidy/checks/readability/avoid-unconditional-preprocessor-if>` check.
 

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 44530a09b2479..f44523f77bd6d 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -284,6 +284,7 @@ Clang-Tidy Checks
    `modernize-replace-random-shuffle <modernize/replace-random-shuffle.html>`_, "Yes"
    `modernize-return-braced-init-list <modernize/return-braced-init-list.html>`_, "Yes"
    `modernize-shrink-to-fit <modernize/shrink-to-fit.html>`_, "Yes"
+   `modernize-type-traits <modernize/type-traits.html>`_, "Yes"
    `modernize-unary-static-assert <modernize/unary-static-assert.html>`_, "Yes"
    `modernize-use-auto <modernize/use-auto.html>`_, "Yes"
    `modernize-use-bool-literals <modernize/use-bool-literals.html>`_, "Yes"

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst
new file mode 100644
index 0000000000000..c2abde856c90f
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst
@@ -0,0 +1,40 @@
+.. title:: clang-tidy - modernize-type-traits
+
+modernize-type-traits
+=====================
+
+Converts standard library type traits of the form ``traits<...>::type`` and
+``traits<...>::value`` into ``traits_t<...>`` and ``traits_v<...>`` respectively.
+
+For example:
+
+.. code-block:: c++
+
+  std::is_integral<T>::value
+  std::is_same<int, float>::value
+  typename std::add_const<T>::type
+  std::make_signed<unsigned>::type
+
+Would be converted into:
+
+.. code-block:: c++
+
+  std::is_integral_v<T>
+  std::is_same_v<int, float>
+  std::add_const_t<T>
+  std::make_signed_t<unsigned>
+
+Options
+-------
+
+.. option:: IgnoreMacros
+
+  If `true` don't diagnose traits defined in macros.
+
+  Note: Fixes will never be emitted for code inside of macros.
+
+  .. code-block:: c++
+
+    #define IS_SIGNED(T) std::is_signed<T>::value
+
+  Defaults to `false`. 

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits.cpp
new file mode 100644
index 0000000000000..72241846384bc
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits.cpp
@@ -0,0 +1,119 @@
+// RUN: %check_clang_tidy -std=c++14 %s modernize-type-traits %t -check-suffixes=',MACRO'
+// RUN: %check_clang_tidy -std=c++14 %s modernize-type-traits %t -- \
+// RUN:   -config='{CheckOptions: {modernize-type-traits.IgnoreMacros: true}}'
+// RUN: %check_clang_tidy -std=c++17 %s modernize-type-traits %t -check-suffixes=',CXX17,MACRO,CXX17MACRO'
+
+namespace std {
+  template <typename>
+  struct is_const {
+    static constexpr bool value = true;
+  };
+
+  template <typename, typename>
+  struct is_same {
+    static constexpr bool value = true;
+  };
+
+  template<bool, typename T = void>
+  struct enable_if {
+    using type = T;
+  };
+
+inline namespace __std_lib_version1 {
+  template<typename T>
+  struct add_const {
+    using type = T;
+  };
+} // namespace __std_lib_version1
+
+namespace ext {
+  template<typename T>
+  struct add_const {
+    using type = T;
+  };
+} // namespace ext
+
+} // namespace std
+
+bool NoTemplate = std::is_const<bool>::value;
+// CHECK-MESSAGES-CXX17: :[[@LINE-1]]:19: warning: use c++17 style variable templates
+// CHECK-FIXES-CXX17: bool NoTemplate = std::is_const_v<bool>
+
+template<typename T>
+constexpr bool InTemplate = std::is_const<T>::value;
+// CHECK-MESSAGES-CXX17: :[[@LINE-1]]:29: warning: use c++17 style variable templates
+// CHECK-FIXES-CXX17: constexpr bool InTemplate = std::is_const_v<T>;
+
+template<typename U, typename V>
+constexpr bool Template2Params = std::is_same<U,V>::value;
+// CHECK-MESSAGES-CXX17: :[[@LINE-1]]:34: warning: use c++17 style variable templates
+// CHECK-FIXES-CXX17: constexpr bool Template2Params = std::is_same_v<U,V>;
+
+template<bool b>
+typename std::enable_if<b>::type inTemplate();
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use c++14 style type templates
+// CHECK-FIXES: std::enable_if_t<b>inTemplate();
+
+typename std::enable_if<true>::type noTemplate();
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use c++14 style type templates
+// CHECK-FIXES: std::enable_if_t<true>noTemplate();
+
+std::enable_if<true>::type noTemplateOrTypename();
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use c++14 style type templates
+// CHECK-FIXES: std::enable_if_t<true>noTemplateOrTypename();
+
+using UsingNoTypename = std::enable_if<true>::type;
+// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use c++14 style type templates
+// CHECK-FIXES: using UsingNoTypename = std::enable_if_t<true>;
+
+using UsingSpace = std::enable_if <true>::type;
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use c++14 style type templates
+// CHECK-FIXES: using UsingSpace = std::enable_if_t <true>;
+
+template<bool b>
+using UsingSpaceTemplate = typename std::enable_if <b>::type;
+// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: use c++14 style type templates
+// CHECK-FIXES: using UsingSpaceTemplate = std::enable_if_t <b>;
+
+bool NoTemplateSpace = std::is_const <bool> ::value;
+// CHECK-MESSAGES-CXX17: :[[@LINE-1]]:24: warning: use c++17 style variable templates
+// CHECK-FIXES-CXX17: bool NoTemplateSpace = std::is_const_v <bool> ;
+
+template<typename T>
+constexpr bool InTemplateSpace = std::is_const  <T> ::value;
+// CHECK-MESSAGES-CXX17: :[[@LINE-1]]:34: warning: use c++17 style variable templates
+// CHECK-FIXES-CXX17: constexpr bool InTemplateSpace = std::is_const_v  <T> ;
+
+// For macros, no diagnostics if IgnoreMacros is set,
+// No fixes emitted even if IgnoreMacros is unset.
+
+#define VALUE_MACRO std::is_same<int, int>::value
+bool MacroValue = VALUE_MACRO;
+// CHECK-MESSAGES-CXX17MACRO: :[[@LINE-1]]:19: warning: use c++17 style variable templates
+// CHECK-FIXES-CXX17MACRO: #define VALUE_MACRO std::is_same<int, int>::value
+
+#define TYPE_MACRO typename std::enable_if<true>::type
+using MacroType = TYPE_MACRO;
+// CHECK-MESSAGES-MACRO: :[[@LINE-1]]:19: warning: use c++14 style type templates
+// CHECK-FIXES-MACRO: #define TYPE_MACRO typename std::enable_if<true>::type
+
+
+// Names defined and accessed inside an inline namespace should be converted.
+// Whether or not the inline namespace is specified
+
+using InlineUnspecified = std::add_const<bool>::type;
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use c++14 style type templates
+// CHECK-FIXES: using InlineUnspecified = std::add_const_t<bool>;
+
+using Inline = std::__std_lib_version1::add_const<bool>::type;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use c++14 style type templates
+// CHECK-FIXES: using Inline = std::__std_lib_version1::add_const_t<bool>;
+
+// Don't try to offer any fix if the name is an extension to the standard library
+using Ext = std::ext::add_const<bool>::type;
+
+namespace my_std = std;
+
+using Alias = my_std::add_const<bool>::type;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use c++14 style type templates
+// CHECK-FIXES: using Alias = my_std::add_const_t<bool>;


        


More information about the cfe-commits mailing list