10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
22 AST_POLYMORPHIC_MATCHER_P(
23 forEachTemplateArgument,
24 AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
25 TemplateSpecializationType, FunctionDecl),
26 clang::ast_matchers::internal::Matcher<TemplateArgument>, InnerMatcher) {
27 ArrayRef<TemplateArgument> TemplateArgs =
28 clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
29 clang::ast_matchers::internal::BoundNodesTreeBuilder Result;
31 for (
const auto &Arg : TemplateArgs) {
32 clang::ast_matchers::internal::BoundNodesTreeBuilder ArgBuilder(*
Builder);
33 if (InnerMatcher.matches(Arg, Finder, &ArgBuilder)) {
35 Result.addMatch(ArgBuilder);
42 AST_MATCHER_P(DeducedTemplateSpecializationType, refsToTemplatedDecl,
43 clang::ast_matchers::internal::Matcher<NamedDecl>, DeclMatcher) {
44 if (
const auto *TD = Node.getTemplateName().getAsTemplateDecl())
45 return DeclMatcher.matches(*TD, Finder,
Builder);
54 return isa<RecordDecl>(TargetDecl) || isa<ClassTemplateDecl>(TargetDecl) ||
55 isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl) ||
56 isa<FunctionTemplateDecl>(TargetDecl) || isa<EnumDecl>(TargetDecl) ||
57 isa<EnumConstantDecl>(TargetDecl);
60 void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) {
61 Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind(
"using"),
this);
62 auto DeclMatcher = hasDeclaration(namedDecl().bind(
"used"));
63 Finder->addMatcher(loc(enumType(DeclMatcher)),
this);
64 Finder->addMatcher(loc(recordType(DeclMatcher)),
this);
65 Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)),
this);
66 Finder->addMatcher(loc(deducedTemplateSpecializationType(
67 refsToTemplatedDecl(namedDecl().bind(
"used")))),
69 Finder->addMatcher(declRefExpr().bind(
"used"),
this);
70 Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind(
"used"))),
73 callExpr(hasDeclaration(functionDecl(
74 forEachTemplateArgument(templateArgument().bind(
"used"))))),
76 Finder->addMatcher(loc(templateSpecializationType(forEachTemplateArgument(
77 templateArgument().bind(
"used")))),
81 void UnusedUsingDeclsCheck::check(
const MatchFinder::MatchResult &Result) {
82 if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
85 if (
const auto *Using = Result.Nodes.getNodeAs<UsingDecl>(
"using")) {
87 if (Using->getLocation().isMacroID())
91 if (isa<CXXRecordDecl>(Using->getDeclContext()))
97 if (isa<FunctionDecl>(Using->getDeclContext()))
100 UsingDeclContext Context(Using);
101 Context.UsingDeclRange = CharSourceRange::getCharRange(
102 Using->getBeginLoc(),
103 Lexer::findLocationAfterToken(
104 Using->getEndLoc(), tok::semi, *Result.SourceManager, getLangOpts(),
106 for (
const auto *UsingShadow : Using->shadows()) {
107 const auto *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl();
109 Context.UsingTargetDecls.insert(TargetDecl);
111 if (!Context.UsingTargetDecls.empty())
112 Contexts.push_back(Context);
117 auto RemoveNamedDecl = [&](
const NamedDecl *Used) {
118 removeFromFoundDecls(Used);
120 if (
const auto *FD = dyn_cast<FunctionDecl>(Used)) {
121 removeFromFoundDecls(FD->getPrimaryTemplate());
122 }
else if (
const auto *Specialization =
123 dyn_cast<ClassTemplateSpecializationDecl>(Used)) {
124 removeFromFoundDecls(Specialization->getSpecializedTemplate());
125 }
else if (
const auto *FD = dyn_cast<FunctionDecl>(Used)) {
126 if (
const auto *FDT = FD->getPrimaryTemplate())
127 removeFromFoundDecls(FDT);
128 }
else if (
const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
129 if (
const auto *ET = ECD->getType()->getAs<EnumType>())
130 removeFromFoundDecls(ET->getDecl());
135 if (
const auto *Used = Result.Nodes.getNodeAs<NamedDecl>(
"used")) {
136 RemoveNamedDecl(Used);
140 if (
const auto *Used = Result.Nodes.getNodeAs<TemplateArgument>(
"used")) {
141 if (Used->getKind() == TemplateArgument::Template) {
142 if (
const auto *TD = Used->getAsTemplate().getAsTemplateDecl())
143 removeFromFoundDecls(TD);
145 if (
auto *RD = Used->getAsType()->getAsCXXRecordDecl())
146 removeFromFoundDecls(RD);
147 }
else if (Used->getKind() == TemplateArgument::Declaration) {
148 RemoveNamedDecl(Used->getAsDecl());
153 if (
const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>(
"used")) {
154 RemoveNamedDecl(DRE->getDecl());
158 if (
const auto *ULE = Result.Nodes.getNodeAs<UnresolvedLookupExpr>(
"used")) {
159 for (
const NamedDecl *ND : ULE->decls()) {
160 if (
const auto *USD = dyn_cast<UsingShadowDecl>(ND))
161 removeFromFoundDecls(USD->getTargetDecl()->getCanonicalDecl());
166 void UnusedUsingDeclsCheck::removeFromFoundDecls(
const Decl *D) {
174 for (
auto &Context : Contexts) {
175 if (Context.UsingTargetDecls.count(D->getCanonicalDecl()) > 0)
176 Context.IsUsed =
true;
180 void UnusedUsingDeclsCheck::onEndOfTranslationUnit() {
181 for (
const auto &Context : Contexts) {
182 if (!Context.IsUsed) {
183 diag(Context.FoundUsingDecl->getLocation(),
"using decl %0 is unused")
184 << Context.FoundUsingDecl;
186 diag(Context.FoundUsingDecl->getLocation(),
187 "remove the using", DiagnosticIDs::Note)
188 << FixItHint::CreateRemoval(Context.UsingDeclRange);