Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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,77 @@
//===----------------------------------------------------------------------===//
//
// 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(typedefTypeLoc().bind("typedefTypeLoc"), 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("typeloc"), this);
}

void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
const SourceLocation ElaboratedKeywordLoc = [&] {
if (const auto *TTL =
Result.Nodes.getNodeAs<TypedefTypeLoc>("typedefTypeLoc"))
return TTL->getElaboratedKeywordLoc();

TypeLoc InnermostTypeLoc = *Result.Nodes.getNodeAs<TypeLoc>("typeloc");
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
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,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
^^^^^^^^^^^^^^^^^

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