95 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "RedundantTypenameCheck.h"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 18namespace clang::tidy::readability {19 20void RedundantTypenameCheck::registerMatchers(MatchFinder *Finder) {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 = NonDependentTypeLoc57 ->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::readability95