[clang-tools-extra] 81de861 - [clang-tidy] Add new check: `readability-redundant-typename` (#161574)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 26 21:38:06 PDT 2025
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>
More information about the cfe-commits
mailing list