diff options
Diffstat (limited to 'clang-tools-extra')
11 files changed, 475 insertions, 12 deletions
| diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp index d36cc3e..6e0c252 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp @@ -90,12 +90,10 @@ ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName) const {    return std::nullopt;  } -static std::optional<bool> getAsBool(StringRef Value, -                                     const llvm::Twine &LookupName) { - +static std::optional<bool> getAsBool(StringRef Value) {    if (std::optional<bool> Parsed = llvm::yaml::parseBool(Value))      return Parsed; -  // To maintain backwards compatability, we support parsing numbers as +  // To maintain backwards compatibility, we support parsing numbers as    // booleans, even though its not supported in YAML.    long long Number = 0;    if (!Value.getAsInteger(10, Number)) @@ -107,7 +105,7 @@ template <>  std::optional<bool>  ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const {    if (std::optional<StringRef> ValueOr = get(LocalName)) { -    if (auto Result = getAsBool(*ValueOr, NamePrefix + LocalName)) +    if (auto Result = getAsBool(*ValueOr))        return Result;      diagnoseBadBooleanOption(NamePrefix + LocalName, *ValueOr);    } @@ -119,7 +117,7 @@ std::optional<bool>  ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const {    auto Iter = findPriorityOption(CheckOptions, NamePrefix, LocalName, Context);    if (Iter != CheckOptions.end()) { -    if (auto Result = getAsBool(Iter->getValue().Value, Iter->getKey())) +    if (auto Result = getAsBool(Iter->getValue().Value))        return Result;      diagnoseBadBooleanOption(Iter->getKey(), Iter->getValue().Value);    } diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp index 0399af2..61ccd26 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp @@ -49,7 +49,7 @@ static StringRef getReplacementFor(StringRef FunctionName,      // Try to find a better replacement from Annex K first.      StringRef AnnexKReplacementFunction =          StringSwitch<StringRef>(FunctionName) -            .Cases("asctime", "asctime_r", "asctime_s") +            .Cases({"asctime", "asctime_r"}, "asctime_s")              .Case("gets", "gets_s")              .Default({});      if (!AnnexKReplacementFunction.empty()) @@ -59,7 +59,7 @@ static StringRef getReplacementFor(StringRef FunctionName,    // FIXME: Some of these functions are available in C++ under "std::", and    // should be matched and suggested.    return StringSwitch<StringRef>(FunctionName) -      .Cases("asctime", "asctime_r", "strftime") +      .Cases({"asctime", "asctime_r"}, "strftime")        .Case("gets", "fgets")        .Case("rewind", "fseek")        .Case("setbuf", "setvbuf"); @@ -90,13 +90,13 @@ static StringRef getReplacementForAdditional(StringRef FunctionName,  /// safer alternative.  static StringRef getRationaleFor(StringRef FunctionName) {    return StringSwitch<StringRef>(FunctionName) -      .Cases("asctime", "asctime_r", "ctime", +      .Cases({"asctime", "asctime_r", "ctime"},               "is not bounds-checking and non-reentrant") -      .Cases("bcmp", "bcopy", "bzero", "is deprecated") -      .Cases("fopen", "freopen", "has no exclusive access to the opened file") +      .Cases({"bcmp", "bcopy", "bzero"}, "is deprecated") +      .Cases({"fopen", "freopen"}, "has no exclusive access to the opened file")        .Case("gets", "is insecure, was deprecated and removed in C11 and C++14")        .Case("getpw", "is dangerous as it may overflow the provided buffer") -      .Cases("rewind", "setbuf", "has no error detection") +      .Cases({"rewind", "setbuf"}, "has no error detection")        .Case("vfork", "is insecure as it can lead to denial of service "                       "situations in the parent process")        .Default("is not bounds-checking"); diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index 0d0641c..91e9354 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -49,6 +49,7 @@ add_clang_library(clangTidyReadabilityModule STATIC    RedundantSmartptrGetCheck.cpp    RedundantStringCStrCheck.cpp    RedundantStringInitCheck.cpp +  RedundantTypenameCheck.cpp    ReferenceToConstructedTemporaryCheck.cpp    SimplifyBooleanExprCheck.cpp    SimplifySubscriptExprCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index fcfac05..569302e 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -52,6 +52,7 @@  #include "RedundantSmartptrGetCheck.h"  #include "RedundantStringCStrCheck.h"  #include "RedundantStringInitCheck.h" +#include "RedundantTypenameCheck.h"  #include "ReferenceToConstructedTemporaryCheck.h"  #include "SimplifyBooleanExprCheck.h"  #include "SimplifySubscriptExprCheck.h" @@ -143,6 +144,8 @@ public:          "readability-redundant-parentheses");      CheckFactories.registerCheck<RedundantPreprocessorCheck>(          "readability-redundant-preprocessor"); +    CheckFactories.registerCheck<RedundantTypenameCheck>( +        "readability-redundant-typename");      CheckFactories.registerCheck<ReferenceToConstructedTemporaryCheck>(          "readability-reference-to-constructed-temporary");      CheckFactories.registerCheck<SimplifySubscriptExprCheck>( diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp new file mode 100644 index 0000000..a4edd2b --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// 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 "RedundantTypenameCheck.h" +#include "clang/AST/TypeLoc.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) { +  Finder->addMatcher(typeLoc(unless(hasAncestor(decl(isInstantiated())))) +                         .bind("nonDependentTypeLoc"), +                     this); + +  if (!getLangOpts().CPlusPlus20) +    return; + +  const auto InImplicitTypenameContext = anyOf( +      hasParent(decl(anyOf( +          typedefNameDecl(), templateTypeParmDecl(), nonTypeTemplateParmDecl(), +          friendDecl(), fieldDecl(), +          varDecl(hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())), +                  unless(parmVarDecl())), +          parmVarDecl(hasParent(expr(requiresExpr()))), +          parmVarDecl(hasParent(typeLoc(hasParent(decl( +              anyOf(cxxMethodDecl(), hasParent(friendDecl()), +                    functionDecl(has(nestedNameSpecifier())), +                    cxxDeductionGuideDecl(hasDeclContext(recordDecl())))))))), +          // Match return types. +          functionDecl(unless(cxxConversionDecl()))))), +      hasParent(expr(anyOf(cxxNamedCastExpr(), cxxNewExpr())))); +  Finder->addMatcher( +      typeLoc(InImplicitTypenameContext).bind("dependentTypeLoc"), this); +} + +void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) { +  const SourceLocation ElaboratedKeywordLoc = [&] { +    if (const auto *NonDependentTypeLoc = +            Result.Nodes.getNodeAs<TypeLoc>("nonDependentTypeLoc")) { +      if (const auto TL = NonDependentTypeLoc->getAs<TypedefTypeLoc>()) +        return TL.getElaboratedKeywordLoc(); + +      if (const auto TL = NonDependentTypeLoc->getAs<TagTypeLoc>()) +        return TL.getElaboratedKeywordLoc(); + +      if (const auto TL = NonDependentTypeLoc +                              ->getAs<DeducedTemplateSpecializationTypeLoc>()) +        return TL.getElaboratedKeywordLoc(); + +      if (const auto TL = +              NonDependentTypeLoc->getAs<TemplateSpecializationTypeLoc>()) +        if (!TL.getType()->isDependentType()) +          return TL.getElaboratedKeywordLoc(); +    } else { +      TypeLoc InnermostTypeLoc = +          *Result.Nodes.getNodeAs<TypeLoc>("dependentTypeLoc"); +      while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc()) +        InnermostTypeLoc = Next; + +      if (const auto TL = InnermostTypeLoc.getAs<DependentNameTypeLoc>()) +        return TL.getElaboratedKeywordLoc(); + +      if (const auto TL = +              InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>()) +        return TL.getElaboratedKeywordLoc(); +    } + +    return SourceLocation(); +  }(); + +  if (ElaboratedKeywordLoc.isInvalid()) +    return; + +  if (Token ElaboratedKeyword; +      Lexer::getRawToken(ElaboratedKeywordLoc, ElaboratedKeyword, +                         *Result.SourceManager, getLangOpts()) || +      ElaboratedKeyword.getRawIdentifier() != "typename") +    return; + +  diag(ElaboratedKeywordLoc, "redundant 'typename'") +      << FixItHint::CreateRemoval(ElaboratedKeywordLoc); +} + +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h new file mode 100644 index 0000000..8e86b0c --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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_READABILITY_REDUNDANTTYPENAMECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::readability { + +/// Finds redundant uses of the `typename` keyword. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-typename.html +class RedundantTypenameCheck : public ClangTidyCheck { +public: +  RedundantTypenameCheck(StringRef Name, ClangTidyContext *Context) +      : ClangTidyCheck(Name, Context) {} +  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { +    return LangOpts.CPlusPlus; +  } +  void registerMatchers(ast_matchers::MatchFinder *Finder) override; +  void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +  std::optional<TraversalKind> getCheckTraversalKind() const override { +    return TK_IgnoreUnlessSpelledInSource; +  } +}; + +} // namespace clang::tidy::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 8a0151f..061fb114 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -221,6 +221,11 @@ New checks    Detect redundant parentheses. +- New :doc:`readability-redundant-typename +  <clang-tidy/checks/readability/redundant-typename>` check. + +  Finds redundant uses of the ``typename`` keyword. +  New check aliases  ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index a324d18..d3c89e4 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -410,6 +410,7 @@ Clang-Tidy Checks     :doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes"     :doc:`readability-redundant-string-cstr <readability/redundant-string-cstr>`, "Yes"     :doc:`readability-redundant-string-init <readability/redundant-string-init>`, "Yes" +   :doc:`readability-redundant-typename <readability/redundant-typename>`, "Yes"     :doc:`readability-reference-to-constructed-temporary <readability/reference-to-constructed-temporary>`,     :doc:`readability-simplify-boolean-expr <readability/simplify-boolean-expr>`, "Yes"     :doc:`readability-simplify-subscript-expr <readability/simplify-subscript-expr>`, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst new file mode 100644 index 0000000..3f3e5de --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst @@ -0,0 +1,31 @@ +.. title:: clang-tidy - readability-redundant-typename + +readability-redundant-typename +============================== + +Finds redundant uses of the ``typename`` keyword. + +``typename`` is redundant in two cases. First, before non-dependent names: + +.. code-block:: c++ + +  /*typename*/ std::vector<int>::size_type size; + +And second, since C++20, before dependent names that appear in a context +where only a type is allowed (the following example shows just a few of them): + +.. code-block:: c++ + +  template <typename T> +  using trait = /*typename*/ T::type; + +  template <typename T> +  /*typename*/ T::underlying_type as_underlying(T n) { +    return static_cast</*typename*/ T::underlying_type>(n); +  } + +  template <typename T> +  struct S { +    /*typename*/ T::type variable; +    /*typename*/ T::type function(/*typename*/ T::type); +  }; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp new file mode 100644 index 0000000..8329926 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp @@ -0,0 +1,25 @@ +// RUN: %check_clang_tidy -std=c++98,c++03 %s readability-redundant-typename %t \ +// RUN:   -- -- -fno-delayed-template-parsing + +struct NotDependent { +  typedef int R; +  template <typename = int> +  struct T {}; +}; + +template <typename T> +typename T::R f() { +  static_cast<typename T::R>(0); + +  typename NotDependent::R NotDependentVar; +  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES: NotDependent::R NotDependentVar; + +  typename NotDependent::T<int> V1; +  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES: NotDependent::T<int> V1; + +  void notDependentFunctionDeclaration(typename NotDependent::R); +  // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES: void notDependentFunctionDeclaration(NotDependent::R); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp new file mode 100644 index 0000000..2efafd1 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp @@ -0,0 +1,269 @@ +// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-typename %t \ +// RUN:   -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy -std=c++17 -check-suffixes=,17 %s readability-redundant-typename %t \ +// RUN:   -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy -std=c++20-or-later -check-suffixes=,17,20 %s readability-redundant-typename %t \ +// RUN:   -- -- -fno-delayed-template-parsing + +struct NotDependent { +  using R = int; +  struct S {}; +  template <typename = int> +  struct T {}; +}; + +auto f(typename NotDependent::S) +  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES: auto f(NotDependent::S) +  -> typename NotDependent::R +  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES: -> NotDependent::R +{ +  typename NotDependent::T<int> V1; +  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES: NotDependent::T<int> V1; + +#if __cplusplus >= 201703L +  typename NotDependent::T V2; +  // CHECK-MESSAGES-17: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-17: NotDependent::T V2; +#endif + +  return typename NotDependent::R(); +  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] +  // return NotDependent::R(); +} + +template < +  typename T, +  typename T::R V, +  // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: T::R V, +  typename U = typename T::R +  // CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: typename U = T::R +> +auto f() -> typename T::R +// CHECK-MESSAGES-20: :[[@LINE-1]]:13: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: auto f() -> T::R +{ +  static_cast<typename T::R>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:15: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: static_cast<T::R>(0); + +  dynamic_cast<typename T::R>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: dynamic_cast<T::R>(0); + +  reinterpret_cast<typename T::R>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: reinterpret_cast<T::R>(0); + +  const_cast<typename T::R>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: const_cast<T::R>(0); + +  static_cast<typename T::R&>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:15: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: static_cast<T::R&>(0); + +  dynamic_cast<typename T::R const volatile &&>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: dynamic_cast<T::R const volatile &&>(0); + +  reinterpret_cast<const typename T::template M<42>::R *>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:26: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: reinterpret_cast<const T::template M<42>::R *>(0); + +  const_cast<const typename T::R *const[100]>(0); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: const_cast<const T::R *const[100]>(0); + +  (typename T::R)(0); + +  alignof(typename T::R); + +  new typename T::R(); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:7: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: new T::R(); + +  // CHECK-MESSAGES-20: :[[@LINE+2]]:15: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: static_cast<decltype([] { +  static_cast<typename decltype([] { +    return typename T::R(); // Inner typename must stay. +  })::R>(0); + +  auto localFunctionDeclaration() -> typename T::R; +  // CHECK-MESSAGES-20: :[[@LINE-1]]:38: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: auto localFunctionDeclaration() -> T::R; + +  void (*PointerToFunction)(typename T::R); +  void anotherLocalFunctionDeclaration(typename T::R); + +  auto Lambda = [](typename T::R = typename T::R()) {}; +  // CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: auto Lambda = [](T::R = typename T::R()) {}; + +  typename T::R DependentVar; +  typename NotDependent::R NotDependentVar; +  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES: NotDependent::R NotDependentVar; + +  return typename T::R(); +} + +template <typename T> +using trait = const typename T::R ****; +// CHECK-MESSAGES-20: :[[@LINE-1]]:21: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: using trait = const T::R ****; + +template <typename T> +using t = typename T::template R<T>; +// CHECK-MESSAGES-20: :[[@LINE-1]]:11: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: using t = T::template R<T>; + +template <typename T> +trait<typename T::R> m(); + +#if __cplusplus >= 202002L + +template <typename T> +concept c = requires(typename T::R) { +// CHECK-MESSAGES-20: :[[@LINE-1]]:22: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: concept c = requires(T::R) { +  typename T::R; +}; + +template <typename T> +requires c<typename T::R> +void b(); + +auto GenericLambda = []<typename T>(typename T::R = typename T::R()) {}; +// CHECK-MESSAGES-20: :[[@LINE-1]]:37: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: auto GenericLambda = []<typename T>(T::R = typename T::R()) {}; + +#endif // __cplusplus >= 202002L + +template <typename T, typename> +struct PartiallySpecializedType {}; + +template <typename T> +struct PartiallySpecializedType<T, typename T::R> {}; + +#if __cplusplus >= 201402L + +template <typename T> +typename T::R v = typename T::R(); +// CHECK-MESSAGES-20: :[[@LINE-1]]:1: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: T::R v = typename T::R(); + +#endif // __cplusplus >= 201402L + +template <typename T> +typename T::R f(); +// CHECK-MESSAGES-20: :[[@LINE-1]]:1: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: T::R f(); + +template <typename T> +void n(typename T::R *) {} + +template void n<NotDependent>(NotDependent::R *); + +namespace ns { + +template <typename T> +void f(typename T::R1, typename T::R2); + +} // namespace ns + +template <typename T> +void ns::f( +  typename T::R1, +  // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: T::R1, +  typename T::R2 +  // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: T::R2 +); + +template <typename... Ts> +void p(typename Ts::R...); + +template <typename T, typename... Ts> +class A { +public: +  friend typename T::R; +  // CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: friend T::R; + +  typedef typename T::R a; +  // CHECK-MESSAGES-20: :[[@LINE-1]]:11: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: typedef T::R a; + +  const typename T::R typedef b; +  // CHECK-MESSAGES-20: :[[@LINE-1]]:9: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: const T::R typedef b; + +  typename T::R v; +  // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: T::R v; + +  typename T::R +  // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: T::R +  g(typename T::R) {} +  // CHECK-MESSAGES-20: :[[@LINE-1]]:5: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: g(T::R) {} + +  void h(typename T::R = typename T::R()) {} +  // CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: void h(T::R = typename T::R()) {} + +  void p(typename Ts::R...); +  // CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: void p(Ts::R...); + +  friend void k(typename T::R) {} +  // CHECK-MESSAGES-20: :[[@LINE-1]]:17: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: friend void k(T::R) {} + +  template <typename> +  struct Nested {}; + +#if __cplusplus >= 201703L +  template <typename U> +  Nested(U, const typename U::R *, typename U::R = typename U::R()) -> Nested<typename U::R>; +  // CHECK-MESSAGES-20: :[[@LINE-1]]:19: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-MESSAGES-20: :[[@LINE-2]]:36: warning: redundant 'typename' [readability-redundant-typename] +  // CHECK-FIXES-20: Nested(U, const U::R *, U::R = typename U::R()) -> Nested<typename U::R>; +#endif + +  friend struct T::R; +  using typename T::R; +  enum E1 : typename T::R {}; +  enum class E2 : typename T::R {}; +  operator typename T::R(); +  void m() { this->operator typename T::R(); } +#if __cplusplus >= 202002L +  T::R n; +  T::R q(T::R) {} +#endif +}; + +#if __cplusplus >= 201703L + +template <typename T, typename U = typename T::R> +// CHECK-MESSAGES-20: :[[@LINE-1]]:36: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: template <typename T, typename U = T::R> +A(T, typename T::R) -> A<typename T::R>; + +#endif + +#define TYPENAME_KEYWORD_IN_MACRO typename +TYPENAME_KEYWORD_IN_MACRO NotDependent::R Macro1; + +#define WHOLE_TYPE_IN_MACRO typename NotDependent::R +WHOLE_TYPE_IN_MACRO Macro2; + +#define WHOLE_DECLARATION_IN_MACRO typename NotDependent::R Macro3 +WHOLE_DECLARATION_IN_MACRO; | 
