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