[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 1 16:34:34 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 1/7] [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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 7/7] 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()),
More information about the cfe-commits
mailing list