Author: Victor Chernyakin Date: 2025-10-26T21:38:02-07:00 New Revision: 81de86123fcf376b3833fdb1448ceb7b74064383
URL: https://github.com/llvm/llvm-project/commit/81de86123fcf376b3833fdb1448ceb7b74064383 DIFF: https://github.com/llvm/llvm-project/commit/81de86123fcf376b3833fdb1448ceb7b74064383.diff LOG: [clang-tidy] Add new check: `readability-redundant-typename` (#161574) Closes #158374. Added: clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp Modified: clang-tools-extra/clang-tidy/readability/CMakeLists.txt clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index 0d0641c4b22bf..91e9354d454d2 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -49,6 +49,7 @@ add_clang_library(clangTidyReadabilityModule STATIC RedundantSmartptrGetCheck.cpp RedundantStringCStrCheck.cpp RedundantStringInitCheck.cpp + RedundantTypenameCheck.cpp ReferenceToConstructedTemporaryCheck.cpp SimplifyBooleanExprCheck.cpp SimplifySubscriptExprCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index fcfac05b000e4..569302e6065f2 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -52,6 +52,7 @@ #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" +#include "RedundantTypenameCheck.h" #include "ReferenceToConstructedTemporaryCheck.h" #include "SimplifyBooleanExprCheck.h" #include "SimplifySubscriptExprCheck.h" @@ -143,6 +144,8 @@ class ReadabilityModule : public ClangTidyModule { "readability-redundant-parentheses"); CheckFactories.registerCheck<RedundantPreprocessorCheck>( "readability-redundant-preprocessor"); + CheckFactories.registerCheck<RedundantTypenameCheck>( + "readability-redundant-typename"); CheckFactories.registerCheck<ReferenceToConstructedTemporaryCheck>( "readability-reference-to-constructed-temporary"); CheckFactories.registerCheck<SimplifySubscriptExprCheck>( diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp new file mode 100644 index 0000000000000..e70fb39aab533 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RedundantTypenameCheck.h" +#include "clang/AST/TypeLoc.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/DeclSpec.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(typeLoc(unless(hasAncestor(decl(isInstantiated())))) + .bind("nonDependentTypeLoc"), + this); + + if (!getLangOpts().CPlusPlus20) + return; + + const auto InImplicitTypenameContext = anyOf( + hasParent(decl(anyOf( + typedefNameDecl(), templateTypeParmDecl(), nonTypeTemplateParmDecl(), + friendDecl(), fieldDecl(), + varDecl(hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())), + unless(parmVarDecl())), + parmVarDecl(hasParent(expr(requiresExpr()))), + parmVarDecl(hasParent(typeLoc(hasParent(decl( + anyOf(cxxMethodDecl(), hasParent(friendDecl()), + functionDecl(has(nestedNameSpecifier())), + cxxDeductionGuideDecl(hasDeclContext(recordDecl())))))))), + // Match return types. + functionDecl(unless(cxxConversionDecl()))))), + hasParent(expr(anyOf(cxxNamedCastExpr(), cxxNewExpr())))); + Finder->addMatcher( + typeLoc(InImplicitTypenameContext).bind("dependentTypeLoc"), this); +} + +void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) { + const SourceLocation ElaboratedKeywordLoc = [&] { + if (const auto *NonDependentTypeLoc = + Result.Nodes.getNodeAs<TypeLoc>("nonDependentTypeLoc")) { + if (const auto TL = NonDependentTypeLoc->getAs<TypedefTypeLoc>()) + return TL.getElaboratedKeywordLoc(); + + if (const auto TL = NonDependentTypeLoc->getAs<TagTypeLoc>()) + return TL.getElaboratedKeywordLoc(); + + if (const auto TL = NonDependentTypeLoc + ->getAs<DeducedTemplateSpecializationTypeLoc>()) + return TL.getElaboratedKeywordLoc(); + + if (const auto TL = + NonDependentTypeLoc->getAs<TemplateSpecializationTypeLoc>()) + if (!TL.getType()->isDependentType()) + return TL.getElaboratedKeywordLoc(); + } else { + TypeLoc InnermostTypeLoc = + *Result.Nodes.getNodeAs<TypeLoc>("dependentTypeLoc"); + while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc()) + InnermostTypeLoc = Next; + + if (const auto TL = InnermostTypeLoc.getAs<DependentNameTypeLoc>()) + return TL.getElaboratedKeywordLoc(); + + if (const auto TL = + InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>()) + return TL.getElaboratedKeywordLoc(); + } + + return SourceLocation(); + }(); + + if (ElaboratedKeywordLoc.isInvalid()) + return; + + if (Token ElaboratedKeyword; + Lexer::getRawToken(ElaboratedKeywordLoc, ElaboratedKeyword, + *Result.SourceManager, getLangOpts()) || + ElaboratedKeyword.getRawIdentifier() != "typename") + return; + + diag(ElaboratedKeywordLoc, "redundant 'typename'") + << FixItHint::CreateRemoval(ElaboratedKeywordLoc); +} + +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h new file mode 100644 index 0000000000000..8e86b0c765fd7 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::readability { + +/// Finds redundant uses of the `typename` keyword. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-typename.html +class RedundantTypenameCheck : public ClangTidyCheck { +public: + RedundantTypenameCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 8a0151f567c24..061fb114276dc 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -221,6 +221,11 @@ New checks Detect redundant parentheses. +- New :doc:`readability-redundant-typename + <clang-tidy/checks/readability/redundant-typename>` check. + + Finds redundant uses of the ``typename`` keyword. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index a324d18704c01..d3c89e469188d 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -410,6 +410,7 @@ Clang-Tidy Checks :doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes" :doc:`readability-redundant-string-cstr <readability/redundant-string-cstr>`, "Yes" :doc:`readability-redundant-string-init <readability/redundant-string-init>`, "Yes" + :doc:`readability-redundant-typename <readability/redundant-typename>`, "Yes" :doc:`readability-reference-to-constructed-temporary <readability/reference-to-constructed-temporary>`, :doc:`readability-simplify-boolean-expr <readability/simplify-boolean-expr>`, "Yes" :doc:`readability-simplify-subscript-expr <readability/simplify-subscript-expr>`, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst new file mode 100644 index 0000000000000..3f3e5de94d594 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst @@ -0,0 +1,31 @@ +.. title:: clang-tidy - readability-redundant-typename + +readability-redundant-typename +============================== + +Finds redundant uses of the ``typename`` keyword. + +``typename`` is redundant in two cases. First, before non-dependent names: + +.. code-block:: c++ + + /*typename*/ std::vector<int>::size_type size; + +And second, since C++20, before dependent names that appear in a context +where only a type is allowed (the following example shows just a few of them): + +.. code-block:: c++ + + template <typename T> + using trait = /*typename*/ T::type; + + template <typename T> + /*typename*/ T::underlying_type as_underlying(T n) { + return static_cast</*typename*/ T::underlying_type>(n); + } + + template <typename T> + struct S { + /*typename*/ T::type variable; + /*typename*/ T::type function(/*typename*/ T::type); + }; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp new file mode 100644 index 0000000000000..8329926888d49 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp @@ -0,0 +1,25 @@ +// RUN: %check_clang_tidy -std=c++98,c++03 %s readability-redundant-typename %t \ +// RUN: -- -- -fno-delayed-template-parsing + +struct NotDependent { + typedef int R; + template <typename = int> + struct T {}; +}; + +template <typename T> +typename T::R f() { + static_cast<typename T::R>(0); + + typename NotDependent::R NotDependentVar; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES: NotDependent::R NotDependentVar; + + typename NotDependent::T<int> V1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES: NotDependent::T<int> V1; + + void notDependentFunctionDeclaration(typename NotDependent::R); + // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES: void notDependentFunctionDeclaration(NotDependent::R); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp new file mode 100644 index 0000000000000..2efafd1a9a649 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp @@ -0,0 +1,269 @@ +// RUN: %check_clang_tidy -std=c++11,c++14 %s readability-redundant-typename %t \ +// RUN: -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy -std=c++17 -check-suffixes=,17 %s readability-redundant-typename %t \ +// RUN: -- -- -fno-delayed-template-parsing +// RUN: %check_clang_tidy -std=c++20-or-later -check-suffixes=,17,20 %s readability-redundant-typename %t \ +// RUN: -- -- -fno-delayed-template-parsing + +struct NotDependent { + using R = int; + struct S {}; + template <typename = int> + struct T {}; +}; + +auto f(typename NotDependent::S) + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES: auto f(NotDependent::S) + -> typename NotDependent::R + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES: -> NotDependent::R +{ + typename NotDependent::T<int> V1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES: NotDependent::T<int> V1; + +#if __cplusplus >= 201703L + typename NotDependent::T V2; + // CHECK-MESSAGES-17: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-17: NotDependent::T V2; +#endif + + return typename NotDependent::R(); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] + // return NotDependent::R(); +} + +template < + typename T, + typename T::R V, + // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: T::R V, + typename U = typename T::R + // CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: typename U = T::R +> +auto f() -> typename T::R +// CHECK-MESSAGES-20: :[[@LINE-1]]:13: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: auto f() -> T::R +{ + static_cast<typename T::R>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:15: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: static_cast<T::R>(0); + + dynamic_cast<typename T::R>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: dynamic_cast<T::R>(0); + + reinterpret_cast<typename T::R>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: reinterpret_cast<T::R>(0); + + const_cast<typename T::R>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: const_cast<T::R>(0); + + static_cast<typename T::R&>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:15: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: static_cast<T::R&>(0); + + dynamic_cast<typename T::R const volatile &&>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: dynamic_cast<T::R const volatile &&>(0); + + reinterpret_cast<const typename T::template M<42>::R *>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:26: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: reinterpret_cast<const T::template M<42>::R *>(0); + + const_cast<const typename T::R *const[100]>(0); + // CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: const_cast<const T::R *const[100]>(0); + + (typename T::R)(0); + + alignof(typename T::R); + + new typename T::R(); + // CHECK-MESSAGES-20: :[[@LINE-1]]:7: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: new T::R(); + + // CHECK-MESSAGES-20: :[[@LINE+2]]:15: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: static_cast<decltype([] { + static_cast<typename decltype([] { + return typename T::R(); // Inner typename must stay. + })::R>(0); + + auto localFunctionDeclaration() -> typename T::R; + // CHECK-MESSAGES-20: :[[@LINE-1]]:38: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: auto localFunctionDeclaration() -> T::R; + + void (*PointerToFunction)(typename T::R); + void anotherLocalFunctionDeclaration(typename T::R); + + auto Lambda = [](typename T::R = typename T::R()) {}; + // CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: auto Lambda = [](T::R = typename T::R()) {}; + + typename T::R DependentVar; + typename NotDependent::R NotDependentVar; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES: NotDependent::R NotDependentVar; + + return typename T::R(); +} + +template <typename T> +using trait = const typename T::R ****; +// CHECK-MESSAGES-20: :[[@LINE-1]]:21: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: using trait = const T::R ****; + +template <typename T> +using t = typename T::template R<T>; +// CHECK-MESSAGES-20: :[[@LINE-1]]:11: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: using t = T::template R<T>; + +template <typename T> +trait<typename T::R> m(); + +#if __cplusplus >= 202002L + +template <typename T> +concept c = requires(typename T::R) { +// CHECK-MESSAGES-20: :[[@LINE-1]]:22: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: concept c = requires(T::R) { + typename T::R; +}; + +template <typename T> +requires c<typename T::R> +void b(); + +auto GenericLambda = []<typename T>(typename T::R = typename T::R()) {}; +// CHECK-MESSAGES-20: :[[@LINE-1]]:37: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: auto GenericLambda = []<typename T>(T::R = typename T::R()) {}; + +#endif // __cplusplus >= 202002L + +template <typename T, typename> +struct PartiallySpecializedType {}; + +template <typename T> +struct PartiallySpecializedType<T, typename T::R> {}; + +#if __cplusplus >= 201402L + +template <typename T> +typename T::R v = typename T::R(); +// CHECK-MESSAGES-20: :[[@LINE-1]]:1: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: T::R v = typename T::R(); + +#endif // __cplusplus >= 201402L + +template <typename T> +typename T::R f(); +// CHECK-MESSAGES-20: :[[@LINE-1]]:1: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: T::R f(); + +template <typename T> +void n(typename T::R *) {} + +template void n<NotDependent>(NotDependent::R *); + +namespace ns { + +template <typename T> +void f(typename T::R1, typename T::R2); + +} // namespace ns + +template <typename T> +void ns::f( + typename T::R1, + // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: T::R1, + typename T::R2 + // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: T::R2 +); + +template <typename... Ts> +void p(typename Ts::R...); + +template <typename T, typename... Ts> +class A { +public: + friend typename T::R; + // CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: friend T::R; + + typedef typename T::R a; + // CHECK-MESSAGES-20: :[[@LINE-1]]:11: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: typedef T::R a; + + const typename T::R typedef b; + // CHECK-MESSAGES-20: :[[@LINE-1]]:9: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: const T::R typedef b; + + typename T::R v; + // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: T::R v; + + typename T::R + // CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: T::R + g(typename T::R) {} + // CHECK-MESSAGES-20: :[[@LINE-1]]:5: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: g(T::R) {} + + void h(typename T::R = typename T::R()) {} + // CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: void h(T::R = typename T::R()) {} + + void p(typename Ts::R...); + // CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: void p(Ts::R...); + + friend void k(typename T::R) {} + // CHECK-MESSAGES-20: :[[@LINE-1]]:17: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: friend void k(T::R) {} + + template <typename> + struct Nested {}; + +#if __cplusplus >= 201703L + template <typename U> + Nested(U, const typename U::R *, typename U::R = typename U::R()) -> Nested<typename U::R>; + // CHECK-MESSAGES-20: :[[@LINE-1]]:19: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-MESSAGES-20: :[[@LINE-2]]:36: warning: redundant 'typename' [readability-redundant-typename] + // CHECK-FIXES-20: Nested(U, const U::R *, U::R = typename U::R()) -> Nested<typename U::R>; +#endif + + friend struct T::R; + using typename T::R; + enum E1 : typename T::R {}; + enum class E2 : typename T::R {}; + operator typename T::R(); + void m() { this->operator typename T::R(); } +#if __cplusplus >= 202002L + T::R n; + T::R q(T::R) {} +#endif +}; + +#if __cplusplus >= 201703L + +template <typename T, typename U = typename T::R> +// CHECK-MESSAGES-20: :[[@LINE-1]]:36: warning: redundant 'typename' [readability-redundant-typename] +// CHECK-FIXES-20: template <typename T, typename U = T::R> +A(T, typename T::R) -> A<typename T::R>; + +#endif + +#define TYPENAME_KEYWORD_IN_MACRO typename +TYPENAME_KEYWORD_IN_MACRO NotDependent::R Macro1; + +#define WHOLE_TYPE_IN_MACRO typename NotDependent::R +WHOLE_TYPE_IN_MACRO Macro2; + +#define WHOLE_DECLARATION_IN_MACRO typename NotDependent::R Macro3 +WHOLE_DECLARATION_IN_MACRO; diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 492863ddfc4a1..98e62de2a9bfb 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2763,6 +2763,20 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDynamicCastExpr> extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr> cxxConstCastExpr; +/// Matches any named cast expression. +/// +/// Example: Matches all four of the casts in +/// \code +/// struct S { virtual void f(); }; +/// S* p = nullptr; +/// S* ptr1 = static_cast<S*>(p); +/// S* ptr2 = reinterpret_cast<S*>(p); +/// S* ptr3 = dynamic_cast<S*>(p); +/// S* ptr4 = const_cast<S*>(p); +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr> + cxxNamedCastExpr; + /// Matches a C-style cast expression. /// /// Example: Matches (int) 2.2f in diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 1f0e007dafc65..42f124ba852ed 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -1009,6 +1009,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDynamicCastExpr> cxxDynamicCastExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXConstCastExpr> cxxConstCastExpr; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr> + cxxNamedCastExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, CStyleCastExpr> cStyleCastExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, ExplicitCastExpr> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
