[clang] [clang-tools-extra] [clang-tidy] Add new check: `readability-redundant-typename` (PR #161574)
Victor Chernyakin via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 8 08:06:31 PDT 2025
https://github.com/localspook updated https://github.com/llvm/llvm-project/pull/161574
>From 82c842a3e8f0f2e9dcfacca0eada9f6aeacd38d8 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 18:35:35 +0000
Subject: [PATCH 01/22] [clang-tidy] Add new check:
`readability-redundant-typename`
---
.../clang-tidy/readability/CMakeLists.txt | 1 +
.../readability/ReadabilityTidyModule.cpp | 3 +
.../readability/RedundantTypenameCheck.cpp | 71 +++++++
.../readability/RedundantTypenameCheck.h | 37 ++++
clang-tools-extra/docs/ReleaseNotes.rst | 5 +
.../docs/clang-tidy/checks/list.rst | 1 +
.../checks/readability/redundant-typename.rst | 26 +++
.../readability/redundant-typename.cpp | 191 ++++++++++++++++++
8 files changed, 335 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 4b4c49d3b17d1..881672e36eb7d 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -48,6 +48,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 d01882dfc9daa..6ff64209a2b0e 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -51,6 +51,7 @@
#include "RedundantSmartptrGetCheck.h"
#include "RedundantStringCStrCheck.h"
#include "RedundantStringInitCheck.h"
+#include "RedundantTypenameCheck.h"
#include "ReferenceToConstructedTemporaryCheck.h"
#include "SimplifyBooleanExprCheck.h"
#include "SimplifySubscriptExprCheck.h"
@@ -140,6 +141,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-redundant-member-init");
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..2861cbb19e534
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/Sema/DeclSpec.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang::tidy::readability {
+
+void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
+ // NOLINTNEXTLINE(readability-identifier-naming)
+ const VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc> typedefTypeLoc;
+ Finder->addMatcher(typedefTypeLoc().bind("typeloc"), this);
+
+ if (!getLangOpts().CPlusPlus20)
+ return;
+
+ // NOLINTBEGIN(readability-identifier-naming)
+ const VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr> cxxNamedCastExpr;
+ const auto inImplicitTypenameContext = [&] {
+ return anyOf(hasParent(typedefNameDecl()),
+ hasParent(templateTypeParmDecl()),
+ hasParent(nonTypeTemplateParmDecl()),
+ hasParent(cxxNamedCastExpr()), hasParent(cxxNewExpr()),
+ hasParent(friendDecl()), hasParent(fieldDecl()),
+ hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
+ hasParent(parmVarDecl(hasParent(typeLoc(hasParent(namedDecl(
+ anyOf(cxxMethodDecl(), hasParent(friendDecl()),
+ functionDecl(has(nestedNameSpecifier()))))))))),
+ // Match return types.
+ hasParent(functionDecl(unless(cxxConversionDecl()))));
+ };
+ // NOLINTEND(readability-identifier-naming)
+ Finder->addMatcher(typeLoc(inImplicitTypenameContext()).bind("typeloc"),
+ this);
+}
+
+void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
+ const SourceLocation TypenameKeywordLoc = [&] {
+ if (const auto *TTL = Result.Nodes.getNodeAs<TypedefTypeLoc>("typeloc"))
+ return TTL->getElaboratedKeywordLoc();
+
+ TypeLoc InnermostTypeLoc = *Result.Nodes.getNodeAs<TypeLoc>("typeloc");
+ while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc())
+ InnermostTypeLoc = Next;
+
+ if (const auto DNTL = InnermostTypeLoc.getAs<DependentNameTypeLoc>())
+ return DNTL.getElaboratedKeywordLoc();
+
+ return SourceLocation();
+ }();
+
+ if (!TypenameKeywordLoc.isValid())
+ return;
+
+ diag(TypenameKeywordLoc, "redundant 'typename'")
+ << FixItHint::CreateRemoval(TypenameKeywordLoc);
+}
+
+} // 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..2df5b38dcef0b
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
@@ -0,0 +1,37 @@
+
+//===----------------------------------------------------------------------===//
+//
+// 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 unnecessary uses of the `typename` keyword.
+///
+/// For the user-facing documentation see:
+/// http://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 3f403c42a168a..8f87864eff036 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -199,6 +199,11 @@ New checks
Finds virtual function overrides with different visibility than the function
in the base class.
+- New :doc:`readability-redundant-typename
+ <clang-tidy/checks/readability/redundant-typename>` check.
+
+ Finds unnecessary 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 e06849c419389..2373edc3a2e96 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -408,6 +408,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..1c4040fbd12df
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - readability-redundant-typename
+
+readability-redundant-typename
+==============================
+
+Finds unnecessary uses of the ``typename`` keyword.
+
+``typename`` is unnecessary 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>
+ 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.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
new file mode 100644
index 0000000000000..3e77213564f89
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
@@ -0,0 +1,191 @@
+// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s readability-redundant-typename %t \
+// RUN: -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++20-or-later -check-suffixes=,20 %s readability-redundant-typename %t \
+// RUN: -- -- -fno-delayed-template-parsing
+
+struct NotDependent {
+ using R = int;
+};
+
+auto f(typename NotDependent::R)
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant 'typename' [readability-redundant-typename]
+ // CHECK-FIXES: auto f(NotDependent::R)
+ -> typename NotDependent::R
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant 'typename' [readability-redundant-typename]
+ // CHECK-FIXES: -> NotDependent::R
+{
+ 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);
+
+ 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>
+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();
+
+#endif // __cplusplus >= 202002L
+
+template <typename T, typename>
+struct PartiallySpecializedType {};
+
+template <typename T>
+struct PartiallySpecializedType<T, typename T::R> {};
+
+template <typename T>
+auto v = typename T::type();
+
+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);
+
+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 T>
+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()) {}
+
+ 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) {}
+
+ enum E1 : typename T::R {};
+ enum class E2 : typename T::R {};
+ operator typename T::R();
+ void m() { this->operator typename T::R(); }
+};
>From 4bae981f5a1946d01f4581dc50ad44007dba1832 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 20:51:07 +0000
Subject: [PATCH 02/22] Move matcher out of lambda
---
.../readability/RedundantTypenameCheck.cpp | 26 ++++++++-----------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 2861cbb19e534..d464060273da2 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -28,22 +28,18 @@ void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
// NOLINTBEGIN(readability-identifier-naming)
const VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr> cxxNamedCastExpr;
- const auto inImplicitTypenameContext = [&] {
- return anyOf(hasParent(typedefNameDecl()),
- hasParent(templateTypeParmDecl()),
- hasParent(nonTypeTemplateParmDecl()),
- hasParent(cxxNamedCastExpr()), hasParent(cxxNewExpr()),
- hasParent(friendDecl()), hasParent(fieldDecl()),
- hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
- hasParent(parmVarDecl(hasParent(typeLoc(hasParent(namedDecl(
- anyOf(cxxMethodDecl(), hasParent(friendDecl()),
- functionDecl(has(nestedNameSpecifier()))))))))),
- // Match return types.
- hasParent(functionDecl(unless(cxxConversionDecl()))));
- };
+ const auto inImplicitTypenameContext = anyOf(
+ hasParent(typedefNameDecl()), hasParent(templateTypeParmDecl()),
+ hasParent(nonTypeTemplateParmDecl()), hasParent(cxxNamedCastExpr()),
+ hasParent(cxxNewExpr()), hasParent(friendDecl()), hasParent(fieldDecl()),
+ hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
+ hasParent(parmVarDecl(hasParent(typeLoc(hasParent(
+ namedDecl(anyOf(cxxMethodDecl(), hasParent(friendDecl()),
+ functionDecl(has(nestedNameSpecifier()))))))))),
+ // Match return types.
+ hasParent(functionDecl(unless(cxxConversionDecl()))));
// NOLINTEND(readability-identifier-naming)
- Finder->addMatcher(typeLoc(inImplicitTypenameContext()).bind("typeloc"),
- this);
+ Finder->addMatcher(typeLoc(inImplicitTypenameContext).bind("typeloc"), this);
}
void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
>From 8f0118acefa993998724ac315699fa224cf90d56 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 20:57:33 +0000
Subject: [PATCH 03/22] Use different names for bound nodes
---
.../clang-tidy/readability/RedundantTypenameCheck.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index d464060273da2..24f5b4c05892d 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -21,7 +21,7 @@ namespace clang::tidy::readability {
void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
// NOLINTNEXTLINE(readability-identifier-naming)
const VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc> typedefTypeLoc;
- Finder->addMatcher(typedefTypeLoc().bind("typeloc"), this);
+ Finder->addMatcher(typedefTypeLoc().bind("typedefTypeLoc"), this);
if (!getLangOpts().CPlusPlus20)
return;
@@ -44,7 +44,8 @@ void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
const SourceLocation TypenameKeywordLoc = [&] {
- if (const auto *TTL = Result.Nodes.getNodeAs<TypedefTypeLoc>("typeloc"))
+ if (const auto *TTL =
+ Result.Nodes.getNodeAs<TypedefTypeLoc>("typedefTypeLoc"))
return TTL->getElaboratedKeywordLoc();
TypeLoc InnermostTypeLoc = *Result.Nodes.getNodeAs<TypeLoc>("typeloc");
>From 21d3d44337e678bd09b6982635b9a008bc49430b Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 20:58:27 +0000
Subject: [PATCH 04/22] Use `isInvalid`
---
.../clang-tidy/readability/RedundantTypenameCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 24f5b4c05892d..543ef5e60ff3e 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -58,7 +58,7 @@ void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
return SourceLocation();
}();
- if (!TypenameKeywordLoc.isValid())
+ if (TypenameKeywordLoc.isInvalid())
return;
diag(TypenameKeywordLoc, "redundant 'typename'")
>From 7e100c333bc8040ccc0de6c20a391dd43f6cd1b5 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 15:34:42 -0700
Subject: [PATCH 05/22] Update
clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
.../clang-tidy/readability/RedundantTypenameCheck.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
index 2df5b38dcef0b..e34df450432f4 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
@@ -17,7 +17,7 @@ namespace clang::tidy::readability {
/// Finds unnecessary uses of the `typename` keyword.
///
/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-typename.html
+/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-typename.html
class RedundantTypenameCheck : public ClangTidyCheck {
public:
RedundantTypenameCheck(StringRef Name, ClangTidyContext *Context)
>From 3e362cd9520d77574da4989c7e708dd28422a2df Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 23:11:29 +0000
Subject: [PATCH 06/22] Add C++98 tests, guard variable template behind C++14
---
.../readability/redundant-typename-cxx98.cpp | 19 +++++++++++++++++++
.../readability/redundant-typename.cpp | 8 +++++++-
2 files changed, 26 insertions(+), 1 deletion(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp
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..5cad980ee271d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp
@@ -0,0 +1,19 @@
+// RUN: %check_clang_tidy -std=c++98 %s readability-redundant-typename %t \
+// RUN: -- -- -fno-delayed-template-parsing
+
+struct NotDependent {
+ typedef int R;
+};
+
+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;
+
+ 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
index 3e77213564f89..6b440a22191ad 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
@@ -122,8 +122,14 @@ struct PartiallySpecializedType {};
template <typename T>
struct PartiallySpecializedType<T, typename T::R> {};
+#if __cplusplus >= 201402L
+
template <typename T>
-auto v = typename T::type();
+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();
>From b7a23d927cb9741ab3ef33136388ce963bc5cce5 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 23:33:49 +0000
Subject: [PATCH 07/22] fix false negative with variable templates
---
.../clang-tidy/readability/RedundantTypenameCheck.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 543ef5e60ff3e..70d46969f61f6 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -32,6 +32,7 @@ void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
hasParent(typedefNameDecl()), hasParent(templateTypeParmDecl()),
hasParent(nonTypeTemplateParmDecl()), hasParent(cxxNamedCastExpr()),
hasParent(cxxNewExpr()), hasParent(friendDecl()), hasParent(fieldDecl()),
+ hasParent(varDecl(unless(hasDeclContext(functionDecl())))),
hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
hasParent(parmVarDecl(hasParent(typeLoc(hasParent(
namedDecl(anyOf(cxxMethodDecl(), hasParent(friendDecl()),
>From fb68c3ca79c8f3036d80a965c15c423c6025f8b3 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 23:47:06 +0000
Subject: [PATCH 08/22] fix false negative with variable templates: take two
---
.../clang-tidy/readability/RedundantTypenameCheck.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 70d46969f61f6..91de1accb3dd9 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -32,7 +32,8 @@ void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
hasParent(typedefNameDecl()), hasParent(templateTypeParmDecl()),
hasParent(nonTypeTemplateParmDecl()), hasParent(cxxNamedCastExpr()),
hasParent(cxxNewExpr()), hasParent(friendDecl()), hasParent(fieldDecl()),
- hasParent(varDecl(unless(hasDeclContext(functionDecl())))),
+ hasParent(varDecl(
+ hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())))),
hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
hasParent(parmVarDecl(hasParent(typeLoc(hasParent(
namedDecl(anyOf(cxxMethodDecl(), hasParent(friendDecl()),
>From 8f33b21096bb23898db6cffd47135662566692b5 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 18:25:20 -0700
Subject: [PATCH 09/22] test fixes, move simple matchers into `ASTMatchers.h`
---
.../readability/RedundantTypenameCheck.cpp | 14 ++++-------
clang/include/clang/ASTMatchers/ASTMatchers.h | 25 +++++++++++++++++++
clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 4 +++
3 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 91de1accb3dd9..88cb0413e8186 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -19,29 +19,25 @@ using namespace clang::ast_matchers::internal;
namespace clang::tidy::readability {
void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
- // NOLINTNEXTLINE(readability-identifier-naming)
- const VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc> typedefTypeLoc;
Finder->addMatcher(typedefTypeLoc().bind("typedefTypeLoc"), this);
if (!getLangOpts().CPlusPlus20)
return;
- // NOLINTBEGIN(readability-identifier-naming)
- const VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr> cxxNamedCastExpr;
- const auto inImplicitTypenameContext = anyOf(
+ const auto InImplicitTypenameContext = anyOf(
hasParent(typedefNameDecl()), hasParent(templateTypeParmDecl()),
hasParent(nonTypeTemplateParmDecl()), hasParent(cxxNamedCastExpr()),
hasParent(cxxNewExpr()), hasParent(friendDecl()), hasParent(fieldDecl()),
- hasParent(varDecl(
- hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())))),
+ hasParent(
+ varDecl(hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())),
+ unless(parmVarDecl()))),
hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
hasParent(parmVarDecl(hasParent(typeLoc(hasParent(
namedDecl(anyOf(cxxMethodDecl(), hasParent(friendDecl()),
functionDecl(has(nestedNameSpecifier()))))))))),
// Match return types.
hasParent(functionDecl(unless(cxxConversionDecl()))));
- // NOLINTEND(readability-identifier-naming)
- Finder->addMatcher(typeLoc(inImplicitTypenameContext).bind("typeloc"), this);
+ Finder->addMatcher(typeLoc(InImplicitTypenameContext).bind("typeloc"), this);
}
void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 492863ddfc4a1..15abdd5758ea3 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2763,6 +2763,17 @@ 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(); };
+/// void* ptr = dynamic_cast<void*>(reinterpret_cast<S*>(
+/// const_cast<int*>(static_cast<int*>(nullptr))));
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr>
+ cxxNamedCastExpr;
+
/// Matches a C-style cast expression.
///
/// Example: Matches (int) 2.2f in
@@ -6987,6 +6998,20 @@ extern const internal::VariadicDynCastAllOfMatcher<
TypeLoc, TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;
+/// Matches `TypedefTypeLoc`s.
+///
+/// Given
+/// \code
+/// using t1 = int;
+/// template <typename T> class C { using t2 = int; };
+/// t1 var1;
+/// const C<char>::t2* var2;
+/// \endcode
+/// typedefTypeLoc()
+/// matches `t1` (in the declaration of var1) and `C<char>::t2`.
+extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc>
+ typedefTypeLoc;
+
/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one `TemplateArgumentLoc` matching the given
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 1f0e007dafc65..516882232cdf5 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -810,6 +810,8 @@ const internal::VariadicDynCastAllOfMatcher<TypeLoc, ReferenceTypeLoc>
const internal::VariadicDynCastAllOfMatcher<TypeLoc,
TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;
+const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc>
+ typedefTypeLoc;
const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryExprOrTypeTraitExpr>
unaryExprOrTypeTraitExpr;
@@ -1009,6 +1011,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>
>From 99a7c14d4f1e4b08238aea21aee0825b9f13fe05 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 19:21:52 -0700
Subject: [PATCH 10/22] reduce duplication in matchers
---
.../readability/RedundantTypenameCheck.cpp | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 88cb0413e8186..9a5fb78846bb5 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -25,18 +25,18 @@ void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
return;
const auto InImplicitTypenameContext = anyOf(
- hasParent(typedefNameDecl()), hasParent(templateTypeParmDecl()),
- hasParent(nonTypeTemplateParmDecl()), hasParent(cxxNamedCastExpr()),
- hasParent(cxxNewExpr()), hasParent(friendDecl()), hasParent(fieldDecl()),
- hasParent(
+ hasParent(decl(anyOf(
+ typedefNameDecl(), templateTypeParmDecl(), nonTypeTemplateParmDecl(),
+ friendDecl(), fieldDecl(),
varDecl(hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())),
- unless(parmVarDecl()))),
- hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
- hasParent(parmVarDecl(hasParent(typeLoc(hasParent(
- namedDecl(anyOf(cxxMethodDecl(), hasParent(friendDecl()),
- functionDecl(has(nestedNameSpecifier()))))))))),
- // Match return types.
- hasParent(functionDecl(unless(cxxConversionDecl()))));
+ unless(parmVarDecl())),
+ parmVarDecl(hasParent(expr(requiresExpr()))),
+ parmVarDecl(hasParent(typeLoc(hasParent(
+ decl(anyOf(cxxMethodDecl(), hasParent(friendDecl()),
+ functionDecl(has(nestedNameSpecifier())))))))),
+ // Match return types.
+ functionDecl(unless(cxxConversionDecl()))))),
+ hasParent(expr(anyOf(cxxNamedCastExpr(), cxxNewExpr()))));
Finder->addMatcher(typeLoc(InImplicitTypenameContext).bind("typeloc"), this);
}
>From 2309f33b3a3da0f072e58510d1d967c0e3f7be6e Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 19:26:55 -0700
Subject: [PATCH 11/22] Remove stray newline
---
.../clang-tidy/readability/RedundantTypenameCheck.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
index e34df450432f4..02224403dc47a 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
@@ -1,4 +1,3 @@
-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
>From 41b823cc5eefcc148824170ee8de18bea11acf8b Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 1 Oct 2025 20:21:49 -0700
Subject: [PATCH 12/22] Add tests with pack expansions
---
.../checkers/readability/redundant-typename.cpp | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
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
index 6b440a22191ad..217f0e8210f6b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
@@ -156,7 +156,10 @@ void ns::f(
// CHECK-FIXES-20: T::R2
);
-template <typename T>
+template <typename... Ts>
+void p(typename Ts::R...);
+
+template <typename T, typename... Ts>
class A {
public:
friend typename T::R;
@@ -186,6 +189,10 @@ class A {
// 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) {}
>From 893b3ae6e9eb7764901a9ccab9994cc258d3ba8d Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Thu, 2 Oct 2025 17:06:22 -0700
Subject: [PATCH 13/22] Fix false negative and false positive
---
.../readability/RedundantTypenameCheck.cpp | 19 +++++++++++++++----
.../readability/redundant-typename.cpp | 6 ++++++
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 9a5fb78846bb5..7da6c3decf90c 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -11,6 +11,7 @@
#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;
@@ -41,7 +42,7 @@ void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
}
void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
- const SourceLocation TypenameKeywordLoc = [&] {
+ const SourceLocation ElaboratedKeywordLoc = [&] {
if (const auto *TTL =
Result.Nodes.getNodeAs<TypedefTypeLoc>("typedefTypeLoc"))
return TTL->getElaboratedKeywordLoc();
@@ -53,14 +54,24 @@ void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto DNTL = InnermostTypeLoc.getAs<DependentNameTypeLoc>())
return DNTL.getElaboratedKeywordLoc();
+ if (const auto TSTL =
+ InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>())
+ return TSTL.getElaboratedKeywordLoc();
+
return SourceLocation();
}();
- if (TypenameKeywordLoc.isInvalid())
+ if (ElaboratedKeywordLoc.isInvalid())
+ return;
+
+ if (Token ElaboratedKeyword;
+ Lexer::getRawToken(ElaboratedKeywordLoc, ElaboratedKeyword,
+ *Result.SourceManager, getLangOpts()) ||
+ ElaboratedKeyword.getRawIdentifier() != "typename")
return;
- diag(TypenameKeywordLoc, "redundant 'typename'")
- << FixItHint::CreateRemoval(TypenameKeywordLoc);
+ diag(ElaboratedKeywordLoc, "redundant 'typename'")
+ << FixItHint::CreateRemoval(ElaboratedKeywordLoc);
}
} // namespace clang::tidy::readability
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
index 217f0e8210f6b..20ff86886080c 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
@@ -98,6 +98,11 @@ 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();
@@ -197,6 +202,7 @@ class A {
// CHECK-MESSAGES-20: :[[@LINE-1]]:17: warning: redundant 'typename' [readability-redundant-typename]
// CHECK-FIXES-20: friend void k(T::R) {}
+ friend struct T::R;
enum E1 : typename T::R {};
enum class E2 : typename T::R {};
operator typename T::R();
>From e6944fa0bff0b42e7b752c26cc3b8932452c321b Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Thu, 2 Oct 2025 18:53:52 -0700
Subject: [PATCH 14/22] Add test case
---
.../test/clang-tidy/checkers/readability/redundant-typename.cpp | 1 +
1 file changed, 1 insertion(+)
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
index 20ff86886080c..2ac0e034b88bb 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
@@ -203,6 +203,7 @@ class A {
// CHECK-FIXES-20: friend void k(T::R) {}
friend struct T::R;
+ using typename T::R;
enum E1 : typename T::R {};
enum class E2 : typename T::R {};
operator typename T::R();
>From e897eb78830cd966668f4caf3f426cc1009aaafe Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Fri, 3 Oct 2025 13:34:01 -0700
Subject: [PATCH 15/22] Test C++03
---
.../checkers/readability/redundant-typename-cxx98.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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
index 5cad980ee271d..74b0b49cdae8d 100644
--- 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
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++98 %s readability-redundant-typename %t \
+// RUN: %check_clang_tidy -std=c++98,c++03 %s readability-redundant-typename %t \
// RUN: -- -- -fno-delayed-template-parsing
struct NotDependent {
>From efb594a61091466080ddf59f4049debf0d47c886 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Fri, 3 Oct 2025 13:34:30 -0700
Subject: [PATCH 16/22] Adjust matcher usage examples
---
clang/include/clang/ASTMatchers/ASTMatchers.h | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 15abdd5758ea3..56186f7ee2342 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2768,8 +2768,11 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr>
/// Example: Matches all four of the casts in
/// \code
/// struct S { virtual void f(); };
-/// void* ptr = dynamic_cast<void*>(reinterpret_cast<S*>(
-/// const_cast<int*>(static_cast<int*>(nullptr))));
+/// 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;
@@ -7003,9 +7006,9 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// Given
/// \code
/// using t1 = int;
-/// template <typename T> class C { using t2 = int; };
+/// template <typename T> struct S { using t2 = int; };
/// t1 var1;
-/// const C<char>::t2* var2;
+/// const S<char>::t2* var2;
/// \endcode
/// typedefTypeLoc()
/// matches `t1` (in the declaration of var1) and `C<char>::t2`.
>From 809c8a48c155ff158c5d78aab8ee968c1d65e929 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Fri, 3 Oct 2025 13:37:06 -0700
Subject: [PATCH 17/22] unnecessary -> redundant
---
.../clang-tidy/readability/RedundantTypenameCheck.h | 2 +-
clang-tools-extra/docs/ReleaseNotes.rst | 2 +-
.../docs/clang-tidy/checks/readability/redundant-typename.rst | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
index 02224403dc47a..8e86b0c765fd7 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
@@ -13,7 +13,7 @@
namespace clang::tidy::readability {
-/// Finds unnecessary uses of the `typename` keyword.
+/// 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
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 09a5ad0230128..52cf855ac9598 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -211,7 +211,7 @@ New checks
- New :doc:`readability-redundant-typename
<clang-tidy/checks/readability/redundant-typename>` check.
- Finds unnecessary uses of the ``typename`` keyword.
+ Finds redundant uses of the ``typename`` keyword.
New check aliases
^^^^^^^^^^^^^^^^^
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
index 1c4040fbd12df..7f5737f4e72b4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst
@@ -3,9 +3,9 @@
readability-redundant-typename
==============================
-Finds unnecessary uses of the ``typename`` keyword.
+Finds redundant uses of the ``typename`` keyword.
-``typename`` is unnecessary in two cases. First, before non-dependent names:
+``typename`` is redundant in two cases. First, before non-dependent names:
.. code-block:: c++
>From beb67d4aa008c4c0b45765f6c4865391866d73f8 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Fri, 3 Oct 2025 13:39:26 -0700
Subject: [PATCH 18/22] Fix typo
---
clang/include/clang/ASTMatchers/ASTMatchers.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 56186f7ee2342..9e833bf2f96a2 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7011,7 +7011,7 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// const S<char>::t2* var2;
/// \endcode
/// typedefTypeLoc()
-/// matches `t1` (in the declaration of var1) and `C<char>::t2`.
+/// matches `t1` (in the declaration of var1) and `S<char>::t2`.
extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc>
typedefTypeLoc;
>From 2f3eee7aef66cedf85a68c8f8d296d48162190bd Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 8 Oct 2025 06:21:57 -0700
Subject: [PATCH 19/22] Fix false positive and negative
---
.../readability/RedundantTypenameCheck.cpp | 35 ++++++++++++-------
.../readability/redundant-typename.cpp | 9 +++--
clang/include/clang/ASTMatchers/ASTMatchers.h | 14 --------
clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 2 --
4 files changed, 28 insertions(+), 32 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
index 7da6c3decf90c..42f1d2e660339 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -20,7 +20,9 @@ using namespace clang::ast_matchers::internal;
namespace clang::tidy::readability {
void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
- Finder->addMatcher(typedefTypeLoc().bind("typedefTypeLoc"), this);
+ Finder->addMatcher(typeLoc(unless(hasAncestor(decl(isInstantiated()))))
+ .bind("nonDependentTypeLoc"),
+ this);
if (!getLangOpts().CPlusPlus20)
return;
@@ -38,25 +40,32 @@ void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
// Match return types.
functionDecl(unless(cxxConversionDecl()))))),
hasParent(expr(anyOf(cxxNamedCastExpr(), cxxNewExpr()))));
- Finder->addMatcher(typeLoc(InImplicitTypenameContext).bind("typeloc"), this);
+ Finder->addMatcher(
+ typeLoc(InImplicitTypenameContext).bind("dependentTypeLoc"), this);
}
void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
const SourceLocation ElaboratedKeywordLoc = [&] {
- if (const auto *TTL =
- Result.Nodes.getNodeAs<TypedefTypeLoc>("typedefTypeLoc"))
- return TTL->getElaboratedKeywordLoc();
+ if (const auto *NonDependentTypeLoc =
+ Result.Nodes.getNodeAs<TypeLoc>("nonDependentTypeLoc")) {
+ if (const auto TTL = NonDependentTypeLoc->getAs<TypedefTypeLoc>())
+ return TTL.getElaboratedKeywordLoc();
- TypeLoc InnermostTypeLoc = *Result.Nodes.getNodeAs<TypeLoc>("typeloc");
- while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc())
- InnermostTypeLoc = Next;
+ if (const auto TTL = NonDependentTypeLoc->getAs<TagTypeLoc>())
+ return TTL.getElaboratedKeywordLoc();
+ } else {
+ TypeLoc InnermostTypeLoc =
+ *Result.Nodes.getNodeAs<TypeLoc>("dependentTypeLoc");
+ while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc())
+ InnermostTypeLoc = Next;
- if (const auto DNTL = InnermostTypeLoc.getAs<DependentNameTypeLoc>())
- return DNTL.getElaboratedKeywordLoc();
+ if (const auto DNTL = InnermostTypeLoc.getAs<DependentNameTypeLoc>())
+ return DNTL.getElaboratedKeywordLoc();
- if (const auto TSTL =
- InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>())
- return TSTL.getElaboratedKeywordLoc();
+ if (const auto TSTL =
+ InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>())
+ return TSTL.getElaboratedKeywordLoc();
+ }
return SourceLocation();
}();
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
index 2ac0e034b88bb..e5ba955e5fdbd 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
@@ -5,11 +5,12 @@
struct NotDependent {
using R = int;
+ struct S {};
};
-auto f(typename NotDependent::R)
+auto f(typename NotDependent::S)
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant 'typename' [readability-redundant-typename]
- // CHECK-FIXES: auto f(NotDependent::R)
+ // CHECK-FIXES: auto f(NotDependent::S)
-> typename NotDependent::R
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant 'typename' [readability-redundant-typename]
// CHECK-FIXES: -> NotDependent::R
@@ -142,7 +143,9 @@ typename T::R f();
// CHECK-FIXES-20: T::R f();
template <typename T>
-void n(typename T::R);
+void n(typename T::R *) {}
+
+template void n<NotDependent>(int *);
namespace ns {
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 9e833bf2f96a2..98e62de2a9bfb 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7001,20 +7001,6 @@ extern const internal::VariadicDynCastAllOfMatcher<
TypeLoc, TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;
-/// Matches `TypedefTypeLoc`s.
-///
-/// Given
-/// \code
-/// using t1 = int;
-/// template <typename T> struct S { using t2 = int; };
-/// t1 var1;
-/// const S<char>::t2* var2;
-/// \endcode
-/// typedefTypeLoc()
-/// matches `t1` (in the declaration of var1) and `S<char>::t2`.
-extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc>
- typedefTypeLoc;
-
/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one `TemplateArgumentLoc` matching the given
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 516882232cdf5..42f124ba852ed 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -810,8 +810,6 @@ const internal::VariadicDynCastAllOfMatcher<TypeLoc, ReferenceTypeLoc>
const internal::VariadicDynCastAllOfMatcher<TypeLoc,
TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;
-const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc>
- typedefTypeLoc;
const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryExprOrTypeTraitExpr>
unaryExprOrTypeTraitExpr;
>From 994d620f8f8ca6ba03a3754ad8044f8e06b283f4 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 8 Oct 2025 07:36:44 -0700
Subject: [PATCH 20/22] Make release note a bit more detailed
---
clang-tools-extra/docs/ReleaseNotes.rst | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 52cf855ac9598..929148337704d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -211,7 +211,9 @@ New checks
- New :doc:`readability-redundant-typename
<clang-tidy/checks/readability/redundant-typename>` check.
- Finds redundant uses of the ``typename`` keyword.
+ Finds redundant uses of the ``typename`` keyword. Can be used
+ to modernize code to take advantage of the C++20 rules that make
+ ``typename`` redundant in many cases where it was mandatory before.
New check aliases
^^^^^^^^^^^^^^^^^
>From 93e27b358783f225eeeaee9a409a1e9d7351fe91 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 8 Oct 2025 07:45:25 -0700
Subject: [PATCH 21/22] adjust test
---
.../test/clang-tidy/checkers/readability/redundant-typename.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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
index e5ba955e5fdbd..cbff6e2ec8bb7 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp
@@ -145,7 +145,7 @@ typename T::R f();
template <typename T>
void n(typename T::R *) {}
-template void n<NotDependent>(int *);
+template void n<NotDependent>(NotDependent::R *);
namespace ns {
>From de7e96c6852cb3a1fc3865fd150877849d130b04 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Wed, 8 Oct 2025 08:05:21 -0700
Subject: [PATCH 22/22] Revert "Make release note a bit more detailed"
---
clang-tools-extra/docs/ReleaseNotes.rst | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 929148337704d..52cf855ac9598 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -211,9 +211,7 @@ New checks
- New :doc:`readability-redundant-typename
<clang-tidy/checks/readability/redundant-typename>` check.
- Finds redundant uses of the ``typename`` keyword. Can be used
- to modernize code to take advantage of the C++20 rules that make
- ``typename`` redundant in many cases where it was mandatory before.
+ Finds redundant uses of the ``typename`` keyword.
New check aliases
^^^^^^^^^^^^^^^^^
More information about the cfe-commits
mailing list