Skip to content

Commit 82c842a

Browse files
committed
[clang-tidy] Add new check: readability-redundant-typename
1 parent 82acc31 commit 82c842a

File tree

8 files changed

+335
-0
lines changed

8 files changed

+335
-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
@@ -48,6 +48,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
4848
RedundantSmartptrGetCheck.cpp
4949
RedundantStringCStrCheck.cpp
5050
RedundantStringInitCheck.cpp
51+
RedundantTypenameCheck.cpp
5152
ReferenceToConstructedTemporaryCheck.cpp
5253
SimplifyBooleanExprCheck.cpp
5354
SimplifySubscriptExprCheck.cpp

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "RedundantSmartptrGetCheck.h"
5252
#include "RedundantStringCStrCheck.h"
5353
#include "RedundantStringInitCheck.h"
54+
#include "RedundantTypenameCheck.h"
5455
#include "ReferenceToConstructedTemporaryCheck.h"
5556
#include "SimplifyBooleanExprCheck.h"
5657
#include "SimplifySubscriptExprCheck.h"
@@ -140,6 +141,8 @@ class ReadabilityModule : public ClangTidyModule {
140141
"readability-redundant-member-init");
141142
CheckFactories.registerCheck<RedundantPreprocessorCheck>(
142143
"readability-redundant-preprocessor");
144+
CheckFactories.registerCheck<RedundantTypenameCheck>(
145+
"readability-redundant-typename");
143146
CheckFactories.registerCheck<ReferenceToConstructedTemporaryCheck>(
144147
"readability-reference-to-constructed-temporary");
145148
CheckFactories.registerCheck<SimplifySubscriptExprCheck>(
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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/Sema/DeclSpec.h"
15+
16+
using namespace clang::ast_matchers;
17+
using namespace clang::ast_matchers::internal;
18+
19+
namespace clang::tidy::readability {
20+
21+
void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {
22+
// NOLINTNEXTLINE(readability-identifier-naming)
23+
const VariadicDynCastAllOfMatcher<TypeLoc, TypedefTypeLoc> typedefTypeLoc;
24+
Finder->addMatcher(typedefTypeLoc().bind("typeloc"), this);
25+
26+
if (!getLangOpts().CPlusPlus20)
27+
return;
28+
29+
// NOLINTBEGIN(readability-identifier-naming)
30+
const VariadicDynCastAllOfMatcher<Stmt, CXXNamedCastExpr> cxxNamedCastExpr;
31+
const auto inImplicitTypenameContext = [&] {
32+
return anyOf(hasParent(typedefNameDecl()),
33+
hasParent(templateTypeParmDecl()),
34+
hasParent(nonTypeTemplateParmDecl()),
35+
hasParent(cxxNamedCastExpr()), hasParent(cxxNewExpr()),
36+
hasParent(friendDecl()), hasParent(fieldDecl()),
37+
hasParent(parmVarDecl(hasParent(expr(requiresExpr())))),
38+
hasParent(parmVarDecl(hasParent(typeLoc(hasParent(namedDecl(
39+
anyOf(cxxMethodDecl(), hasParent(friendDecl()),
40+
functionDecl(has(nestedNameSpecifier()))))))))),
41+
// Match return types.
42+
hasParent(functionDecl(unless(cxxConversionDecl()))));
43+
};
44+
// NOLINTEND(readability-identifier-naming)
45+
Finder->addMatcher(typeLoc(inImplicitTypenameContext()).bind("typeloc"),
46+
this);
47+
}
48+
49+
void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
50+
const SourceLocation TypenameKeywordLoc = [&] {
51+
if (const auto *TTL = Result.Nodes.getNodeAs<TypedefTypeLoc>("typeloc"))
52+
return TTL->getElaboratedKeywordLoc();
53+
54+
TypeLoc InnermostTypeLoc = *Result.Nodes.getNodeAs<TypeLoc>("typeloc");
55+
while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc())
56+
InnermostTypeLoc = Next;
57+
58+
if (const auto DNTL = InnermostTypeLoc.getAs<DependentNameTypeLoc>())
59+
return DNTL.getElaboratedKeywordLoc();
60+
61+
return SourceLocation();
62+
}();
63+
64+
if (!TypenameKeywordLoc.isValid())
65+
return;
66+
67+
diag(TypenameKeywordLoc, "redundant 'typename'")
68+
<< FixItHint::CreateRemoval(TypenameKeywordLoc);
69+
}
70+
71+
} // namespace clang::tidy::readability
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H
11+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTYPENAMECHECK_H
12+
13+
#include "../ClangTidyCheck.h"
14+
15+
namespace clang::tidy::readability {
16+
17+
/// Finds unnecessary uses of the `typename` keyword.
18+
///
19+
/// For the user-facing documentation see:
20+
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-typename.html
21+
class RedundantTypenameCheck : public ClangTidyCheck {
22+
public:
23+
RedundantTypenameCheck(StringRef Name, ClangTidyContext *Context)
24+
: ClangTidyCheck(Name, Context) {}
25+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
26+
return LangOpts.CPlusPlus;
27+
}
28+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
29+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
30+
std::optional<TraversalKind> getCheckTraversalKind() const override {
31+
return TK_IgnoreUnlessSpelledInSource;
32+
}
33+
};
34+
35+
} // namespace clang::tidy::readability
36+
37+
#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
@@ -199,6 +199,11 @@ New checks
199199
Finds virtual function overrides with different visibility than the function
200200
in the base class.
201201

202+
- New :doc:`readability-redundant-typename
203+
<clang-tidy/checks/readability/redundant-typename>` check.
204+
205+
Finds unnecessary uses of the ``typename`` keyword.
206+
202207
New check aliases
203208
^^^^^^^^^^^^^^^^^
204209

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ Clang-Tidy Checks
408408
:doc:`readability-redundant-smartptr-get <readability/redundant-smartptr-get>`, "Yes"
409409
:doc:`readability-redundant-string-cstr <readability/redundant-string-cstr>`, "Yes"
410410
:doc:`readability-redundant-string-init <readability/redundant-string-init>`, "Yes"
411+
:doc:`readability-redundant-typename <readability/redundant-typename>`, "Yes"
411412
:doc:`readability-reference-to-constructed-temporary <readability/reference-to-constructed-temporary>`,
412413
:doc:`readability-simplify-boolean-expr <readability/simplify-boolean-expr>`, "Yes"
413414
:doc:`readability-simplify-subscript-expr <readability/simplify-subscript-expr>`, "Yes"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.. title:: clang-tidy - readability-redundant-typename
2+
3+
readability-redundant-typename
4+
==============================
5+
6+
Finds unnecessary uses of the ``typename`` keyword.
7+
8+
``typename`` is unnecessary 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+
struct S {
24+
/* typename */ T::type variable;
25+
/* typename */ T::type function(/* typename */ T::type);
26+
};
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// RUN: %check_clang_tidy -std=c++11,c++14,c++17 %s readability-redundant-typename %t \
2+
// RUN: -- -- -fno-delayed-template-parsing
3+
// RUN: %check_clang_tidy -std=c++20-or-later -check-suffixes=,20 %s readability-redundant-typename %t \
4+
// RUN: -- -- -fno-delayed-template-parsing
5+
6+
struct NotDependent {
7+
using R = int;
8+
};
9+
10+
auto f(typename NotDependent::R)
11+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant 'typename' [readability-redundant-typename]
12+
// CHECK-FIXES: auto f(NotDependent::R)
13+
-> typename NotDependent::R
14+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: redundant 'typename' [readability-redundant-typename]
15+
// CHECK-FIXES: -> NotDependent::R
16+
{
17+
return typename NotDependent::R();
18+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename]
19+
// return NotDependent::R();
20+
}
21+
22+
template <
23+
typename T,
24+
typename T::R V,
25+
// CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
26+
// CHECK-FIXES-20: T::R V,
27+
typename U = typename T::R
28+
// CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename]
29+
// CHECK-FIXES-20: typename U = T::R
30+
>
31+
auto f() -> typename T::R
32+
// CHECK-MESSAGES-20: :[[@LINE-1]]:13: warning: redundant 'typename' [readability-redundant-typename]
33+
// CHECK-FIXES-20: auto f() -> T::R
34+
{
35+
static_cast<typename T::R>(0);
36+
// CHECK-MESSAGES-20: :[[@LINE-1]]:15: warning: redundant 'typename' [readability-redundant-typename]
37+
// CHECK-FIXES-20: static_cast<T::R>(0);
38+
39+
dynamic_cast<typename T::R>(0);
40+
// CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename]
41+
// CHECK-FIXES-20: dynamic_cast<T::R>(0);
42+
43+
reinterpret_cast<typename T::R>(0);
44+
// CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename]
45+
// CHECK-FIXES-20: reinterpret_cast<T::R>(0);
46+
47+
const_cast<typename T::R>(0);
48+
// CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: redundant 'typename' [readability-redundant-typename]
49+
// CHECK-FIXES-20: const_cast<T::R>(0);
50+
51+
static_cast<typename T::R&>(0);
52+
// CHECK-MESSAGES-20: :[[@LINE-1]]:15: warning: redundant 'typename' [readability-redundant-typename]
53+
// CHECK-FIXES-20: static_cast<T::R&>(0);
54+
55+
dynamic_cast<typename T::R const volatile &&>(0);
56+
// CHECK-MESSAGES-20: :[[@LINE-1]]:16: warning: redundant 'typename' [readability-redundant-typename]
57+
// CHECK-FIXES-20: dynamic_cast<T::R const volatile &&>(0);
58+
59+
reinterpret_cast<const typename T::template M<42>::R *>(0);
60+
// CHECK-MESSAGES-20: :[[@LINE-1]]:26: warning: redundant 'typename' [readability-redundant-typename]
61+
// CHECK-FIXES-20: reinterpret_cast<const T::template M<42>::R *>(0);
62+
63+
const_cast<const typename T::R *const[100]>(0);
64+
// CHECK-MESSAGES-20: :[[@LINE-1]]:20: warning: redundant 'typename' [readability-redundant-typename]
65+
// CHECK-FIXES-20: const_cast<const T::R *const[100]>(0);
66+
67+
(typename T::R)(0);
68+
69+
alignof(typename T::R);
70+
71+
new typename T::R();
72+
// CHECK-MESSAGES-20: :[[@LINE-1]]:7: warning: redundant 'typename' [readability-redundant-typename]
73+
// CHECK-FIXES-20: new T::R();
74+
75+
// CHECK-MESSAGES-20: :[[@LINE+2]]:15: warning: redundant 'typename' [readability-redundant-typename]
76+
// CHECK-FIXES-20: static_cast<decltype([] {
77+
static_cast<typename decltype([] {
78+
return typename T::R(); // Inner typename must stay.
79+
})::R>(0);
80+
81+
auto localFunctionDeclaration() -> typename T::R;
82+
// CHECK-MESSAGES-20: :[[@LINE-1]]:38: warning: redundant 'typename' [readability-redundant-typename]
83+
// CHECK-FIXES-20: auto localFunctionDeclaration() -> T::R;
84+
85+
void (*PointerToFunction)(typename T::R);
86+
void anotherLocalFunctionDeclaration(typename T::R);
87+
88+
typename T::R DependentVar;
89+
typename NotDependent::R NotDependentVar;
90+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
91+
// CHECK-FIXES: NotDependent::R NotDependentVar;
92+
93+
return typename T::R();
94+
}
95+
96+
template <typename T>
97+
using trait = const typename T::R ****;
98+
// CHECK-MESSAGES-20: :[[@LINE-1]]:21: warning: redundant 'typename' [readability-redundant-typename]
99+
// CHECK-FIXES-20: using trait = const T::R ****;
100+
101+
template <typename T>
102+
trait<typename T::R> m();
103+
104+
#if __cplusplus >= 202002L
105+
106+
template <typename T>
107+
concept c = requires(typename T::R) {
108+
// CHECK-MESSAGES-20: :[[@LINE-1]]:22: warning: redundant 'typename' [readability-redundant-typename]
109+
// CHECK-FIXES-20: concept c = requires(T::R) {
110+
typename T::R;
111+
};
112+
113+
template <typename T>
114+
requires c<typename T::R>
115+
void b();
116+
117+
#endif // __cplusplus >= 202002L
118+
119+
template <typename T, typename>
120+
struct PartiallySpecializedType {};
121+
122+
template <typename T>
123+
struct PartiallySpecializedType<T, typename T::R> {};
124+
125+
template <typename T>
126+
auto v = typename T::type();
127+
128+
template <typename T>
129+
typename T::R f();
130+
// CHECK-MESSAGES-20: :[[@LINE-1]]:1: warning: redundant 'typename' [readability-redundant-typename]
131+
// CHECK-FIXES-20: T::R f();
132+
133+
template <typename T>
134+
void n(typename T::R);
135+
136+
namespace ns {
137+
138+
template <typename T>
139+
void f(typename T::R1, typename T::R2);
140+
141+
} // namespace ns
142+
143+
template <typename T>
144+
void ns::f(
145+
typename T::R1,
146+
// CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
147+
// CHECK-FIXES-20: T::R1,
148+
typename T::R2
149+
// CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
150+
// CHECK-FIXES-20: T::R2
151+
);
152+
153+
template <typename T>
154+
class A {
155+
public:
156+
friend typename T::R;
157+
// CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename]
158+
// CHECK-FIXES-20: friend T::R;
159+
160+
typedef typename T::R a;
161+
// CHECK-MESSAGES-20: :[[@LINE-1]]:11: warning: redundant 'typename' [readability-redundant-typename]
162+
// CHECK-FIXES-20: typedef T::R a;
163+
164+
const typename T::R typedef b;
165+
// CHECK-MESSAGES-20: :[[@LINE-1]]:9: warning: redundant 'typename' [readability-redundant-typename]
166+
// CHECK-FIXES-20: const T::R typedef b;
167+
168+
typename T::R v;
169+
// CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
170+
// CHECK-FIXES-20: T::R v;
171+
172+
typename T::R
173+
// CHECK-MESSAGES-20: :[[@LINE-1]]:3: warning: redundant 'typename' [readability-redundant-typename]
174+
// CHECK-FIXES-20: T::R
175+
g(typename T::R) {}
176+
// CHECK-MESSAGES-20: :[[@LINE-1]]:5: warning: redundant 'typename' [readability-redundant-typename]
177+
// CHECK-FIXES-20: g(T::R) {}
178+
179+
void h(typename T::R = typename T::R()) {}
180+
// CHECK-MESSAGES-20: :[[@LINE-1]]:10: warning: redundant 'typename' [readability-redundant-typename]
181+
// CHECK-FIXES-20: void h(T::R = typename T::R()) {}
182+
183+
friend void k(typename T::R) {}
184+
// CHECK-MESSAGES-20: :[[@LINE-1]]:17: warning: redundant 'typename' [readability-redundant-typename]
185+
// CHECK-FIXES-20: friend void k(T::R) {}
186+
187+
enum E1 : typename T::R {};
188+
enum class E2 : typename T::R {};
189+
operator typename T::R();
190+
void m() { this->operator typename T::R(); }
191+
};

0 commit comments

Comments
 (0)