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(typeLoc(unless(hasAncestor(decl(isInstantiated()))))
22 .bind("nonDependentTypeLoc"),
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 SourceLocation ElaboratedKeywordLoc = [&] {
48 if (const auto *NonDependentTypeLoc =
49 Result.Nodes.getNodeAs<TypeLoc>("nonDependentTypeLoc")) {
50 if (const auto TL = NonDependentTypeLoc->getAs<TypedefTypeLoc>())
51 return TL.getElaboratedKeywordLoc();
52
53 if (const auto TL = NonDependentTypeLoc->getAs<TagTypeLoc>())
54 return TL.getElaboratedKeywordLoc();
55
56 if (const auto TL = NonDependentTypeLoc
57 ->getAs<DeducedTemplateSpecializationTypeLoc>())
58 return TL.getElaboratedKeywordLoc();
59
60 if (const auto TL =
61 NonDependentTypeLoc->getAs<TemplateSpecializationTypeLoc>())
62 if (!TL.getType()->isDependentType())
63 return TL.getElaboratedKeywordLoc();
64 } else {
65 TypeLoc InnermostTypeLoc =
66 *Result.Nodes.getNodeAs<TypeLoc>("dependentTypeLoc");
67 while (const TypeLoc Next = InnermostTypeLoc.getNextTypeLoc())
68 InnermostTypeLoc = Next;
69
70 if (const auto TL = InnermostTypeLoc.getAs<DependentNameTypeLoc>())
71 return TL.getElaboratedKeywordLoc();
72
73 if (const auto TL =
74 InnermostTypeLoc.getAs<TemplateSpecializationTypeLoc>())
75 return TL.getElaboratedKeywordLoc();
76 }
77
78 return SourceLocation();
79 }();
80
81 if (ElaboratedKeywordLoc.isInvalid())
82 return;
83
84 if (Token ElaboratedKeyword;
85 Lexer::getRawToken(ElaboratedKeywordLoc, ElaboratedKeyword,
86 *Result.SourceManager, getLangOpts()) ||
87 ElaboratedKeyword.getRawIdentifier() != "typename")
88 return;
89
90 diag(ElaboratedKeywordLoc, "redundant 'typename'")
91 << FixItHint::CreateRemoval(ElaboratedKeywordLoc);
92}
93
94} // namespace clang::tidy::readability
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override