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 <[email protected]> Date: Wed, 1 Oct 2025 18:35:35 +0000 Subject: [PATCH 01/23] [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 <[email protected]> Date: Wed, 1 Oct 2025 20:51:07 +0000 Subject: [PATCH 02/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 20:57:33 +0000 Subject: [PATCH 03/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 20:58:27 +0000 Subject: [PATCH 04/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 15:34:42 -0700 Subject: [PATCH 05/23] Update clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h Co-authored-by: EugeneZelenko <[email protected]> --- .../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 <[email protected]> Date: Wed, 1 Oct 2025 23:11:29 +0000 Subject: [PATCH 06/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 23:33:49 +0000 Subject: [PATCH 07/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 23:47:06 +0000 Subject: [PATCH 08/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 18:25:20 -0700 Subject: [PATCH 09/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 19:21:52 -0700 Subject: [PATCH 10/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 19:26:55 -0700 Subject: [PATCH 11/23] 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 <[email protected]> Date: Wed, 1 Oct 2025 20:21:49 -0700 Subject: [PATCH 12/23] 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 <[email protected]> Date: Thu, 2 Oct 2025 17:06:22 -0700 Subject: [PATCH 13/23] 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 <[email protected]> Date: Thu, 2 Oct 2025 18:53:52 -0700 Subject: [PATCH 14/23] 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 <[email protected]> Date: Fri, 3 Oct 2025 13:34:01 -0700 Subject: [PATCH 15/23] 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 <[email protected]> Date: Fri, 3 Oct 2025 13:34:30 -0700 Subject: [PATCH 16/23] 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 <[email protected]> Date: Fri, 3 Oct 2025 13:37:06 -0700 Subject: [PATCH 17/23] 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 <[email protected]> Date: Fri, 3 Oct 2025 13:39:26 -0700 Subject: [PATCH 18/23] 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 <[email protected]> Date: Wed, 8 Oct 2025 06:21:57 -0700 Subject: [PATCH 19/23] 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 <[email protected]> Date: Wed, 8 Oct 2025 07:36:44 -0700 Subject: [PATCH 20/23] 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 <[email protected]> Date: Wed, 8 Oct 2025 07:45:25 -0700 Subject: [PATCH 21/23] 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 <[email protected]> Date: Wed, 8 Oct 2025 08:05:21 -0700 Subject: [PATCH 22/23] 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 ^^^^^^^^^^^^^^^^^ >From 36380894446dc74794926978fed9aa040808708e Mon Sep 17 00:00:00 2001 From: Victor Chernyakin <[email protected]> Date: Thu, 23 Oct 2025 00:40:49 +0000 Subject: [PATCH 23/23] Fix more FNs with nondependent types, add more GOOD tests, bit more docs --- .../readability/RedundantTypenameCheck.cpp | 25 ++++++++++----- .../checks/readability/redundant-typename.rst | 9 ++++-- .../readability/redundant-typename-cxx98.cpp | 6 ++++ .../readability/redundant-typename.cpp | 31 +++++++++++++++++-- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp index 42f1d2e660339..874de6fb5e363 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp @@ -48,23 +48,32 @@ void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) { const SourceLocation ElaboratedKeywordLoc = [&] { if (const auto *NonDependentTypeLoc = Result.Nodes.getNodeAs<TypeLoc>("nonDependentTypeLoc")) { - if (const auto TTL = NonDependentTypeLoc->getAs<TypedefTypeLoc>()) - return TTL.getElaboratedKeywordLoc(); + if (const auto TL = NonDependentTypeLoc->getAs<TypedefTypeLoc>()) + return TL.getElaboratedKeywordLoc(); - if (const auto TTL = NonDependentTypeLoc->getAs<TagTypeLoc>()) - return TTL.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 DNTL = InnermostTypeLoc.getAs<DependentNameTypeLoc>()) - return DNTL.getElaboratedKeywordLoc(); + if (const auto TL = InnermostTypeLoc.getAs<DependentNameTypeLoc>()) + return TL.getElaboratedKeywordLoc(); - if (const auto TSTL = + if (const auto TL = InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>()) - return TSTL.getElaboratedKeywordLoc(); + return TL.getElaboratedKeywordLoc(); } return SourceLocation(); 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 7f5737f4e72b4..e8875c0415556 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 @@ -19,8 +19,13 @@ where only a type is allowed (the following example shows just a few of them): 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); + /*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 index 74b0b49cdae8d..8329926888d49 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 @@ -3,6 +3,8 @@ struct NotDependent { typedef int R; + template <typename = int> + struct T {}; }; template <typename T> @@ -13,6 +15,10 @@ typename T::R f() { // 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 index cbff6e2ec8bb7..65fa1f2fbfda4 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 @@ -1,11 +1,15 @@ -// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s readability-redundant-typename %t \ +// 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++20-or-later -check-suffixes=,20 %s readability-redundant-typename %t \ +// 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) @@ -15,6 +19,16 @@ auto f(typename NotDependent::S) // 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(); @@ -211,4 +225,17 @@ class A { 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 }; + +#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; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
