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);
47 return isa<RecordDecl>(TargetDecl) || isa<ClassTemplateDecl>(TargetDecl) ||
48 isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl) ||
49 isa<FunctionTemplateDecl>(TargetDecl) || isa<EnumDecl>(TargetDecl) ||
50 isa<EnumConstantDecl>(TargetDecl);
53 void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) {
54 Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind(
"using"),
this);
55 auto DeclMatcher = hasDeclaration(namedDecl().bind(
"used"));
56 Finder->addMatcher(loc(enumType(DeclMatcher)),
this);
57 Finder->addMatcher(loc(recordType(DeclMatcher)),
this);
58 Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)),
this);
59 Finder->addMatcher(declRefExpr().bind(
"used"),
this);
60 Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind(
"used"))),
63 callExpr(hasDeclaration(functionDecl(
64 forEachTemplateArgument(templateArgument().bind(
"used"))))),
66 Finder->addMatcher(loc(templateSpecializationType(forEachTemplateArgument(
67 templateArgument().bind(
"used")))),
71 void UnusedUsingDeclsCheck::check(
const MatchFinder::MatchResult &Result) {
72 if (Result.Context->getDiagnostics().hasUncompilableErrorOccurred())
75 if (
const auto *Using = Result.Nodes.getNodeAs<UsingDecl>(
"using")) {
77 if (Using->getLocation().isMacroID())
81 if (isa<CXXRecordDecl>(Using->getDeclContext()))
87 if (isa<FunctionDecl>(Using->getDeclContext()))
90 UsingDeclContext Context(Using);
91 Context.UsingDeclRange = CharSourceRange::getCharRange(
93 Lexer::findLocationAfterToken(
94 Using->getEndLoc(), tok::semi, *Result.SourceManager, getLangOpts(),
96 for (
const auto *UsingShadow : Using->shadows()) {
97 const auto *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl();
99 Context.UsingTargetDecls.insert(TargetDecl);
101 if (!Context.UsingTargetDecls.empty())
102 Contexts.push_back(Context);
107 auto RemoveNamedDecl = [&](
const NamedDecl *Used) {
108 removeFromFoundDecls(Used);
110 if (
const auto *FD = dyn_cast<FunctionDecl>(Used)) {
111 removeFromFoundDecls(FD->getPrimaryTemplate());
112 }
else if (
const auto *Specialization =
113 dyn_cast<ClassTemplateSpecializationDecl>(Used)) {
114 removeFromFoundDecls(Specialization->getSpecializedTemplate());
115 }
else if (
const auto *FD = dyn_cast<FunctionDecl>(Used)) {
116 if (
const auto *FDT = FD->getPrimaryTemplate())
117 removeFromFoundDecls(FDT);
118 }
else if (
const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
119 if (
const auto *ET = ECD->getType()->getAs<EnumType>())
120 removeFromFoundDecls(ET->getDecl());
125 if (
const auto *Used = Result.Nodes.getNodeAs<NamedDecl>(
"used")) {
126 RemoveNamedDecl(Used);
130 if (
const auto *Used = Result.Nodes.getNodeAs<TemplateArgument>(
"used")) {
131 if (Used->getKind() == TemplateArgument::Template) {
132 if (
const auto *TD = Used->getAsTemplate().getAsTemplateDecl())
133 removeFromFoundDecls(TD);
135 if (
auto *RD = Used->getAsType()->getAsCXXRecordDecl())
136 removeFromFoundDecls(RD);
137 }
else if (Used->getKind() == TemplateArgument::Declaration) {
138 RemoveNamedDecl(Used->getAsDecl());
143 if (
const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>(
"used")) {
144 RemoveNamedDecl(DRE->getDecl());
148 if (
const auto *ULE = Result.Nodes.getNodeAs<UnresolvedLookupExpr>(
"used")) {
149 for (
const NamedDecl *ND : ULE->decls()) {
150 if (
const auto *USD = dyn_cast<UsingShadowDecl>(ND))
151 removeFromFoundDecls(USD->getTargetDecl()->getCanonicalDecl());
156 void UnusedUsingDeclsCheck::removeFromFoundDecls(
const Decl *D) {
164 for (
auto &Context : Contexts) {
165 if (Context.UsingTargetDecls.count(D->getCanonicalDecl()) > 0)
166 Context.IsUsed =
true;
170 void UnusedUsingDeclsCheck::onEndOfTranslationUnit() {
171 for (
const auto &Context : Contexts) {
172 if (!Context.IsUsed) {
173 diag(Context.FoundUsingDecl->getLocation(),
"using decl %0 is unused")
174 << Context.FoundUsingDecl;
176 diag(Context.FoundUsingDecl->getLocation(),
177 "remove the using", DiagnosticIDs::Note)
178 << FixItHint::CreateRemoval(Context.UsingDeclRange);
const FunctionDecl * Decl
static bool ShouldCheckDecl(const Decl *TargetDecl)
CodeCompletionBuilder Builder
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//