11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
15 using namespace clang::ast_matchers;
25 return isa<RecordDecl>(TargetDecl) || isa<ClassTemplateDecl>(TargetDecl) ||
26 isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl) ||
27 isa<FunctionTemplateDecl>(TargetDecl) || isa<EnumDecl>(TargetDecl) ||
28 isa<EnumConstantDecl>(TargetDecl);
31 void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *
Finder) {
32 Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind(
"using"),
this);
33 auto DeclMatcher = hasDeclaration(namedDecl().bind(
"used"));
34 Finder->addMatcher(loc(enumType(DeclMatcher)),
this);
35 Finder->addMatcher(loc(recordType(DeclMatcher)),
this);
36 Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)),
this);
37 Finder->addMatcher(declRefExpr().bind(
"used"),
this);
38 Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind(
"used"))),
42 void UnusedUsingDeclsCheck::check(
const MatchFinder::MatchResult &
Result) {
43 if (
const auto *Using = Result.Nodes.getNodeAs<UsingDecl>(
"using")) {
45 if (Using->getLocation().isMacroID())
49 if (isa<CXXRecordDecl>(Using->getDeclContext()))
55 if (isa<FunctionDecl>(Using->getDeclContext()))
58 UsingDeclContext
Context(Using);
59 Context.UsingDeclRange = CharSourceRange::getCharRange(
61 Lexer::findLocationAfterToken(
62 Using->getLocEnd(), tok::semi, *Result.SourceManager,
63 Result.Context->getLangOpts(),
65 for (
const auto *UsingShadow : Using->shadows()) {
66 const auto *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl();
68 Context.UsingTargetDecls.insert(TargetDecl);
70 if (!Context.UsingTargetDecls.empty())
71 Contexts.push_back(Context);
80 if (
const auto *Used = Result.Nodes.getNodeAs<NamedDecl>(
"used")) {
81 if (
const auto *Specialization =
82 dyn_cast<ClassTemplateSpecializationDecl>(Used))
83 Used = Specialization->getSpecializedTemplate();
84 removeFromFoundDecls(Used);
88 if (
const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>(
"used")) {
89 if (
const auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
90 if (
const auto *FDT = FD->getPrimaryTemplate())
91 removeFromFoundDecls(FDT);
93 removeFromFoundDecls(FD);
94 }
else if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
95 removeFromFoundDecls(VD);
96 }
else if (
const auto *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
97 removeFromFoundDecls(ECD);
98 if (
const auto *ET = ECD->getType()->getAs<EnumType>())
99 removeFromFoundDecls(ET->getDecl());
103 if (
const auto *ULE = Result.Nodes.getNodeAs<UnresolvedLookupExpr>(
"used")) {
104 for (
const NamedDecl* ND : ULE->decls()) {
105 if (
const auto *USD = dyn_cast<UsingShadowDecl>(ND))
106 removeFromFoundDecls(USD->getTargetDecl()->getCanonicalDecl());
111 void UnusedUsingDeclsCheck::removeFromFoundDecls(
const Decl *D) {
117 for (
auto &
Context : Contexts) {
118 if (
Context.UsingTargetDecls.count(D->getCanonicalDecl()) > 0)
123 void UnusedUsingDeclsCheck::onEndOfTranslationUnit() {
124 for (
const auto &
Context : Contexts) {
126 diag(
Context.FoundUsingDecl->getLocation(),
"using decl %0 is unused")
128 << FixItHint::CreateRemoval(
Context.UsingDeclRange);
std::unique_ptr< ast_matchers::MatchFinder > Finder
static bool ShouldCheckDecl(const Decl *TargetDecl)
ClangTidyContext & Context