aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra')
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidyCheck.cpp10
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp12
-rw-r--r--clang-tools-extra/clang-tidy/readability/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp94
-rw-r--r--clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h36
-rw-r--r--clang-tools-extra/docs/ReleaseNotes.rst5
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/list.rst1
-rw-r--r--clang-tools-extra/docs/clang-tidy/checks/readability/redundant-typename.rst31
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename-cxx98.cpp25
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/redundant-typename.cpp269
11 files changed, 475 insertions, 12 deletions
diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
index d36cc3e..6e0c252 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
@@ -90,12 +90,10 @@ ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName) const {
return std::nullopt;
}
-static std::optional<bool> getAsBool(StringRef Value,
- const llvm::Twine &LookupName) {
-
+static std::optional<bool> getAsBool(StringRef Value) {
if (std::optional<bool> Parsed = llvm::yaml::parseBool(Value))
return Parsed;
- // To maintain backwards compatability, we support parsing numbers as
+ // To maintain backwards compatibility, we support parsing numbers as
// booleans, even though its not supported in YAML.
long long Number = 0;
if (!Value.getAsInteger(10, Number))
@@ -107,7 +105,7 @@ template <>
std::optional<bool>
ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const {
if (std::optional<StringRef> ValueOr = get(LocalName)) {
- if (auto Result = getAsBool(*ValueOr, NamePrefix + LocalName))
+ if (auto Result = getAsBool(*ValueOr))
return Result;
diagnoseBadBooleanOption(NamePrefix + LocalName, *ValueOr);
}
@@ -119,7 +117,7 @@ std::optional<bool>
ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const {
auto Iter = findPriorityOption(CheckOptions, NamePrefix, LocalName, Context);
if (Iter != CheckOptions.end()) {
- if (auto Result = getAsBool(Iter->getValue().Value, Iter->getKey()))
+ if (auto Result = getAsBool(Iter->getValue().Value))
return Result;
diagnoseBadBooleanOption(Iter->getKey(), Iter->getValue().Value);
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
index 0399af2..61ccd26 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
@@ -49,7 +49,7 @@ static StringRef getReplacementFor(StringRef FunctionName,
// Try to find a better replacement from Annex K first.
StringRef AnnexKReplacementFunction =
StringSwitch<StringRef>(FunctionName)
- .Cases("asctime", "asctime_r", "asctime_s")
+ .Cases({"asctime", "asctime_r"}, "asctime_s")
.Case("gets", "gets_s")
.Default({});
if (!AnnexKReplacementFunction.empty())
@@ -59,7 +59,7 @@ static StringRef getReplacementFor(StringRef FunctionName,
// FIXME: Some of these functions are available in C++ under "std::", and
// should be matched and suggested.
return StringSwitch<StringRef>(FunctionName)
- .Cases("asctime", "asctime_r", "strftime")
+ .Cases({"asctime", "asctime_r"}, "strftime")
.Case("gets", "fgets")
.Case("rewind", "fseek")
.Case("setbuf", "setvbuf");
@@ -90,13 +90,13 @@ static StringRef getReplacementForAdditional(StringRef FunctionName,
/// safer alternative.
static StringRef getRationaleFor(StringRef FunctionName) {
return StringSwitch<StringRef>(FunctionName)
- .Cases("asctime", "asctime_r", "ctime",
+ .Cases({"asctime", "asctime_r", "ctime"},
"is not bounds-checking and non-reentrant")
- .Cases("bcmp", "bcopy", "bzero", "is deprecated")
- .Cases("fopen", "freopen", "has no exclusive access to the opened file")
+ .Cases({"bcmp", "bcopy", "bzero"}, "is deprecated")
+ .Cases({"fopen", "freopen"}, "has no exclusive access to the opened file")
.Case("gets", "is insecure, was deprecated and removed in C11 and C++14")
.Case("getpw", "is dangerous as it may overflow the provided buffer")
- .Cases("rewind", "setbuf", "has no error detection")
+ .Cases({"rewind", "setbuf"}, "has no error detection")
.Case("vfork", "is insecure as it can lead to denial of service "
"situations in the parent process")
.Default("is not bounds-checking");
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 0d0641c..91e9354 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 fcfac05..569302e 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 @@ public:
"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 0000000..a4edd2b
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.cpp
@@ -0,0 +1,94 @@
+//===----------------------------------------------------------------------===//
+//
+// 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"
+
+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 0000000..8e86b0c
--- /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 8a0151f..061fb114 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 a324d18..d3c89e4 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 0000000..3f3e5de
--- /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 0000000..8329926
--- /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 0000000..2efafd1
--- /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;