Author: Victor Chernyakin
Date: 2025-10-26T21:38:02-07:00
New Revision: 81de86123fcf376b3833fdb1448ceb7b74064383

URL: 
https://github.com/llvm/llvm-project/commit/81de86123fcf376b3833fdb1448ceb7b74064383
DIFF: 
https://github.com/llvm/llvm-project/commit/81de86123fcf376b3833fdb1448ceb7b74064383.diff

LOG: [clang-tidy] Add new check: `readability-redundant-typename` (#161574)

Closes #158374.

Added: 
    clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
    clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
    clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst
    
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp
    
clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp

Modified: 
    clang-tools-extra/clang-tidy/readability/CMakeLists.txt
    clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/list.rst
    clang/include/clang/ASTMatchers/ASTMatchers.h
    clang/lib/ASTMatchers/ASTMatchersInternal.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 0d0641c4b22bf..91e9354d454d2 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 fcfac05b000e4..569302e6065f2 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 @@ class ReadabilityModule : public ClangTidyModule {
         "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 0000000000000..e70fb39aab533
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+#include "clang/Sema/DeclSpec.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 0000000000000..8e86b0c765fd7
--- /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 8a0151f567c24..061fb114276dc 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 a324d18704c01..d3c89e469188d 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 0000000000000..3f3e5de94d594
--- /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 0000000000000..8329926888d49
--- /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 0000000000000..2efafd1a9a649
--- /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;

diff  --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 492863ddfc4a1..98e62de2a9bfb 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2763,6 +2763,20 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, 
CXXDynamicCastExpr>
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr>
     cxxConstCastExpr;
 
+/// Matches any named cast expression.
+///
+/// Example: Matches all four of the casts in
+/// \code
+///   struct S { virtual void f(); };
+///   S* p = nullptr;
+///   S* ptr1 = static_cast<S*>(p);
+///   S* ptr2 = reinterpret_cast<S*>(p);
+///   S* ptr3 = dynamic_cast<S*>(p);
+///   S* ptr4 = const_cast<S*>(p);
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr>
+    cxxNamedCastExpr;
+
 /// Matches a C-style cast expression.
 ///
 /// Example: Matches (int) 2.2f in

diff  --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 1f0e007dafc65..42f124ba852ed 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1009,6 +1009,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, 
CXXDynamicCastExpr>
     cxxDynamicCastExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr>
     cxxConstCastExpr;
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr>
+    cxxNamedCastExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, CStyleCastExpr>
     cStyleCastExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, ExplicitCastExpr>


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to