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