[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