Skip to content

Commit 81de861

Browse files
authored
[clang-tidy] Add new check: readability-redundant-typename (#161574)
Closes #158374.
1 parent 3b8f63d commit 81de861

File tree

11 files changed

+482
-0
lines changed

11 files changed

+482
-0
lines changed

clang-tools-extra/clang-tidy/readability/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
4949
RedundantSmartptrGetCheck.cpp
5050
RedundantStringCStrCheck.cpp
5151
RedundantStringInitCheck.cpp
52+
RedundantTypenameCheck.cpp
5253
ReferenceToConstructedTemporaryCheck.cpp
5354
SimplifyBooleanExprCheck.cpp
5455
SimplifySubscriptExprCheck.cpp

clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "RedundantSmartptrGetCheck.h"
5353
#include "RedundantStringCStrCheck.h"
5454
#include "RedundantStringInitCheck.h"
55+
#include "RedundantTypenameCheck.h"
5556
#include "ReferenceToConstructedTemporaryCheck.h"
5657
#include "SimplifyBooleanExprCheck.h"
5758
#include "SimplifySubscriptExprCheck.h"
@@ -143,6 +144,8 @@ class ReadabilityModule : public ClangTidyModule {
143144
"readability-redundant-parentheses");
144145
CheckFactories.registerCheck<RedundantPreprocessorCheck>(
145146
"readability-redundant-preprocessor");
147+
CheckFactories.registerCheck<RedundantTypenameCheck>(
148+
"readability-redundant-typename");
146149
CheckFactories.registerCheck<ReferenceToConstructedTemporaryCheck>(
147150
"readability-reference-to-constructed-temporary");
148151
CheckFactories.registerCheck<SimplifySubscriptExprCheck>(
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "RedundantTypenameCheck.h"
10+
#include "clang/AST/TypeLoc.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
#include "clang/ASTMatchers/ASTMatchers.h"
13+
#include "clang/Basic/Diagnostic.h"
14+
#include "clang/Lex/Lexer.h"
15+
#include "clang/Sema/DeclSpec.h"
16+
17+
using namespace clang::ast_matchers;
18+
19+
namespace clang::tidy::readability {
20+
21+
void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
22+
Finder->addMatcher(typeLoc(unless(hasAncestor(decl(isInstantiated()))))
23+
.bind("nonDependentTypeLoc"),
24+
this);
25+
26+
if (!getLangOpts().CPlusPlus20)
27+
return;
28+
29+
const auto InImplicitTypenameContext = anyOf(
30+
hasParent(decl(anyOf(
31+
typedefNameDecl(), templateTypeParmDecl(), nonTypeTemplateParmDecl(),
32+
friendDecl(), fieldDecl(),
33+
varDecl(hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())),
34+
unless(parmVarDecl())),
35+
parmVarDecl(hasParent(expr(requiresExpr()))),
36+
parmVarDecl(hasParent(typeLoc(hasParent(decl(
37+
anyOf(cxxMethodDecl(), hasParent(friendDecl()),
38+
functionDecl(has(nestedNameSpecifier())),
39+
cxxDeductionGuideDecl(hasDeclContext(recordDecl())))))))),
40+
// Match return types.
41+
functionDecl(unless(cxxConversionDecl()))))),
42+
hasParent(expr(anyOf(cxxNamedCastExpr(), cxxNewExpr()))));
43+
Finder->addMatcher(
44+
typeLoc(InImplicitTypenameContext).bind("dependentTypeLoc"), this);
45+
}
46+
47+
void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
48+
const SourceLocation ElaboratedKeywordLoc = [&] {
49+
if (const auto *NonDependentTypeLoc =
50+
Result.Nodes.getNodeAs<TypeLoc>("nonDependentTypeLoc")) {
51+
if (const auto TL = NonDependentTypeLoc->getAs<TypedefTypeLoc>())
52+
return TL.getElaboratedKeywordLoc();
53+
54+
if (const auto TL = NonDependentTypeLoc->getAs<TagTypeLoc>())
55+
return TL.getElaboratedKeywordLoc();
56+
57+
if (const auto TL = NonDependentTypeLoc
58+
->getAs<DeducedTemplateSpecializationTypeLoc>())
59+
return TL.getElaboratedKeywordLoc();
60+
61+
if (const auto TL =
62+
NonDependentTypeLoc->getAs<TemplateSpecializationTypeLoc>())
63+
if (!TL.getType()->isDependentType())
64+
return TL.getElaboratedKeywordLoc();
65+
} else {
66+
TypeLoc InnermostTypeLoc =
67+
*Result.Nodes.getNodeAs<TypeLoc>("dependentTypeLoc");
68+
while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc())
69+
InnermostTypeLoc = Next;
70+
71+
if (const auto TL = InnermostTypeLoc.getAs<DependentNameTypeLoc>())
72+
return TL.getElaboratedKeywordLoc();
73+
74+
if (const auto TL =
75+
InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>())
76+
return TL.getElaboratedKeywordLoc();
77+
}
78+
79+
return SourceLocation();
80+
}();
81+
82+
if (ElaboratedKeywordLoc.isInvalid())
83+
return;
84+
85+
if (Token ElaboratedKeyword;
86+
Lexer::getRawToken(ElaboratedKeywordLoc, ElaboratedKeyword,
87+
*Result.SourceManager, getLangOpts()) ||
88+
ElaboratedKeyword.getRawIdentifier() != "typename")
89+
return;
90+
91+
diag(ElaboratedKeywordLoc, "redundant 'typename'")
92+
<< FixItHint::CreateRemoval(ElaboratedKeywordLoc);
93+
}
94+
95+
} // namespace clang::tidy::readability
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang::tidy::readability {
15+
16+
/// Finds redundant uses of the `typename` keyword.
17+
///
18+
/// For the user-facing documentation see:
19+
/// https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-typename.html
20+
class RedundantTypenameCheck : public ClangTidyCheck {
21+
public:
22+
RedundantTypenameCheck(StringRef Name, ClangTidyContext *Context)
23+
: ClangTidyCheck(Name, Context) {}
24+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
25+
return LangOpts.CPlusPlus;
26+
}
27+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
28+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
29+
std::optional<TraversalKind> getCheckTraversalKind() const override {
30+
return TK_IgnoreUnlessSpelledInSource;
31+
}
32+
};
33+
34+
} // namespace clang::tidy::readability
35+
36+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ New checks
221221

222222
Detect redundant parentheses.
223223

224+
- New :doc:`readability-redundant-typename
225+
<clang-tidy/checks/readability/redundant-typename>` check.
226+
227+
Finds redundant uses of the ``typename`` keyword.
228+
224229
New check aliases
225230
^^^^^^^^^^^^^^^^^
226231

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ Clang-Tidy Checks
410410
:doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes"
411411
:doc:`readability-redundant-string-cstr <readability/redundant-string-cstr>`, "Yes"
412412
:doc:`readability-redundant-string-init <readability/redundant-string-init>`, "Yes"
413+
:doc:`readability-redundant-typename <readability/redundant-typename>`, "Yes"
413414
:doc:`readability-reference-to-constructed-temporary <readability/reference-to-constructed-temporary>`,
414415
:doc:`readability-simplify-boolean-expr <readability/simplify-boolean-expr>`, "Yes"
415416
:doc:`readability-simplify-subscript-expr <readability/simplify-subscript-expr>`, "Yes"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.. title:: clang-tidy - readability-redundant-typename
2+
3+
readability-redundant-typename
4+
==============================
5+
6+
Finds redundant uses of the ``typename`` keyword.
7+
8+
``typename`` is redundant in two cases. First, before non-dependent names:
9+
10+
.. code-block:: c++
11+
12+
/*typename*/ std::vector<int>::size_type size;
13+
14+
And second, since C++20, before dependent names that appear in a context
15+
where only a type is allowed (the following example shows just a few of them):
16+
17+
.. code-block:: c++
18+
19+
template <typename T>
20+
using trait = /*typename*/ T::type;
21+
22+
template <typename T>
23+
/*typename*/ T::underlying_type as_underlying(T n) {
24+
return static_cast</*typename*/ T::underlying_type>(n);
25+
}
26+
27+
template <typename T>
28+
struct S {
29+
/*typename*/ T::type variable;
30+
/*typename*/ T::type function(/*typename*/ T::type);
31+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %check_clang_tidy -std=c++98,c++03 %s readability-redundant-typename %t \
2+
// RUN: -- -- -fno-delayed-template-parsing
3+
4+
struct NotDependent {
5+
typedef int R;
6+
template <typename = int>
7+
struct T {};
8+
};
9+
10+
template <typename T>
11+
typename T::R f() {
12+
static_cast<typename T::R>(0);
13+
14+
typename NotDependent::R NotDependentVar;
15+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
16+
// CHECK-FIXES: NotDependent::R NotDependentVar;
17+
18+
typename NotDependent::T<int> V1;
19+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
20+
// CHECK-FIXES: NotDependent::T<int> V1;
21+
22+
void notDependentFunctionDeclaration(typename NotDependent::R);
23+
// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: redundant 'typename' [readability-redundant-typename]
24+
// CHECK-FIXES: void notDependentFunctionDeclaration(NotDependent::R);
25+
}

0 commit comments

Comments
 (0)