Skip to content
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
82c842a
[clang-tidy] Add new check: `readability-redundant-typename`
localspook Oct 1, 2025
7353f87
Merge branch 'main' into readability-redundant-typename
localspook Oct 1, 2025
4bae981
Move matcher out of lambda
localspook Oct 1, 2025
8f0118a
Use different names for bound nodes
localspook Oct 1, 2025
21d3d44
Use `isInvalid`
localspook Oct 1, 2025
7e100c3
Update clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
localspook Oct 1, 2025
3e362cd
Add C++98 tests, guard variable template behind C++14
localspook Oct 1, 2025
b7a23d9
fix false negative with variable templates
localspook Oct 1, 2025
fb68c3c
fix false negative with variable templates: take two
localspook Oct 1, 2025
8f33b21
test fixes, move simple matchers into `ASTMatchers.h`
localspook Oct 2, 2025
99a7c14
reduce duplication in matchers
localspook Oct 2, 2025
2309f33
Remove stray newline
localspook Oct 2, 2025
41b823c
Add tests with pack expansions
localspook Oct 2, 2025
893b3ae
Fix false negative and false positive
localspook Oct 3, 2025
e6944fa
Add test case
localspook Oct 3, 2025
e897eb7
Test C++03
localspook Oct 3, 2025
efb594a
Adjust matcher usage examples
localspook Oct 3, 2025
809c8a4
unnecessary -> redundant
localspook Oct 3, 2025
beb67d4
Fix typo
localspook Oct 3, 2025
2f3eee7
Fix false positive and negative
localspook Oct 8, 2025
994d620
Make release note a bit more detailed
localspook Oct 8, 2025
93e27b3
adjust test
localspook Oct 8, 2025
de7e96c
Revert "Make release note a bit more detailed"
localspook Oct 8, 2025
3638089
Fix more FNs with nondependent types, add more GOOD tests, bit more docs
localspook Oct 23, 2025
bfd0643
Make docs a bit more consistent
localspook Oct 23, 2025
df4c35e
add deduction guide tests
localspook Oct 23, 2025
1e2194e
add lambda tests
localspook Oct 23, 2025
28856f1
remove unused `using namespace`
localspook Oct 23, 2025
a1dda04
fix FN for deduction guides in class scopes
localspook Oct 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/readability/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
RedundantSmartptrGetCheck.cpp
RedundantStringCStrCheck.cpp
RedundantStringInitCheck.cpp
RedundantTypenameCheck.cpp
ReferenceToConstructedTemporaryCheck.cpp
SimplifyBooleanExprCheck.cpp
SimplifySubscriptExprCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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>(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//===----------------------------------------------------------------------===//
//
// 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;
using namespace clang::ast_matchers::internal;

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())))))))),
// 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 TTL = NonDependentTypeLoc->getAs<TypedefTypeLoc>())
return TTL.getElaboratedKeywordLoc();

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 TSTL =
InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>())
return TSTL.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
36 changes: 36 additions & 0 deletions clang-tools-extra/clang-tidy/readability/RedundantTypenameCheck.h
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ New checks

Detect redundant parentheses.

- 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.

New check aliases
^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,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"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.. 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>
struct S {
/* typename */ T::type variable;
/* typename */ T::type function(/* typename */ T::type);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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 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);
}
Loading
Loading