clang-tools 22.0.0git
RedundantTypenameCheck.cpp
Go to the documentation of this file.
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
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
16using namespace clang::ast_matchers;
17
19
21 Finder->addMatcher(
22 typeLoc(unless(hasAncestor(decl(isInstantiated())))).bind("typeLoc"),
23 this);
24
25 if (!getLangOpts().CPlusPlus20)
26 return;
27
28 const auto InImplicitTypenameContext = anyOf(
29 hasParent(decl(anyOf(
30 typedefNameDecl(), templateTypeParmDecl(), nonTypeTemplateParmDecl(),
31 friendDecl(), fieldDecl(),
32 varDecl(hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())),
33 unless(parmVarDecl())),
34 parmVarDecl(hasParent(expr(requiresExpr()))),
35 parmVarDecl(hasParent(typeLoc(hasParent(decl(
36 anyOf(cxxMethodDecl(), hasParent(friendDecl()),
37 functionDecl(has(nestedNameSpecifier())),
38 cxxDeductionGuideDecl(hasDeclContext(recordDecl())))))))),
39 // Match return types.
40 functionDecl(unless(cxxConversionDecl()))))),
41 hasParent(expr(anyOf(cxxNamedCastExpr(), cxxNewExpr()))));
42 Finder->addMatcher(
43 typeLoc(InImplicitTypenameContext).bind("dependentTypeLoc"), this);
44}
45
46void RedundantTypenameCheck::check(const MatchFinder::MatchResult &Result) {
47 const TypeLoc TL = [&] {
48 if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("typeLoc"))
49 return TL->getType()->isDependentType() ? TypeLoc() : *TL;
50
51 auto TL = *Result.Nodes.getNodeAs<TypeLoc>("dependentTypeLoc");
52 while (const TypeLoc Next = TL.getNextTypeLoc())
53 TL = Next;
54 return TL;
55 }();
56
57 if (TL.isNull())
58 return;
59
60 const SourceLocation ElaboratedKeywordLoc = [&] {
61 if (const auto CastTL = TL.getAs<TypedefTypeLoc>())
62 return CastTL.getElaboratedKeywordLoc();
63
64 if (const auto CastTL = TL.getAs<TagTypeLoc>())
65 return CastTL.getElaboratedKeywordLoc();
66
67 if (const auto CastTL = TL.getAs<DeducedTemplateSpecializationTypeLoc>())
68 return CastTL.getElaboratedKeywordLoc();
69
70 if (const auto CastTL = TL.getAs<TemplateSpecializationTypeLoc>())
71 return CastTL.getElaboratedKeywordLoc();
72
73 if (const auto CastTL = TL.getAs<DependentNameTypeLoc>())
74 return CastTL.getElaboratedKeywordLoc();
75
76 return SourceLocation();
77 }();
78
79 if (ElaboratedKeywordLoc.isInvalid())
80 return;
81
82 if (Token ElaboratedKeyword;
83 Lexer::getRawToken(ElaboratedKeywordLoc, ElaboratedKeyword,
84 *Result.SourceManager, getLangOpts()) ||
85 ElaboratedKeyword.getRawIdentifier() != "typename")
86 return;
87
88 diag(ElaboratedKeywordLoc, "redundant 'typename'")
89 << FixItHint::CreateRemoval(ElaboratedKeywordLoc);
90}
91
92} // namespace clang::tidy::readability
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override