1 //===--- UnusedUsingDeclsCheck.cpp - clang-tidy----------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "UnusedUsingDeclsCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Lex/Lexer.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace tidy { 19 namespace misc { 20 21 // A function that helps to tell whether a TargetDecl will be checked. 22 // We only check a TargetDecl if : 23 // * The corresponding UsingDecl is not defined in macros or in class 24 // definitions. 25 // * Only variable, function and class types are considered. 26 static bool ShouldCheckDecl(const Decl *TargetDecl) { 27 // Ignores using-declarations defined in macros. 28 if (TargetDecl->getLocation().isMacroID()) 29 return false; 30 31 // Ignores using-declarations defined in class definition. 32 if (isa<CXXRecordDecl>(TargetDecl->getDeclContext())) 33 return false; 34 35 return isa<RecordDecl>(TargetDecl) || isa<ClassTemplateDecl>(TargetDecl) || 36 isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl) || 37 isa<FunctionTemplateDecl>(TargetDecl); 38 } 39 40 void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) { 41 Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind("using"), this); 42 auto DeclMatcher = hasDeclaration(namedDecl().bind("used")); 43 Finder->addMatcher(loc(recordType(DeclMatcher)), this); 44 Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)), this); 45 Finder->addMatcher(declRefExpr().bind("used"), this); 46 Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind("used"))), 47 this); 48 } 49 50 void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { 51 if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) { 52 UsingDeclContext Context(Using); 53 Context.UsingDeclRange = CharSourceRange::getCharRange( 54 Using->getLocStart(), 55 Lexer::findLocationAfterToken( 56 Using->getLocEnd(), tok::semi, *Result.SourceManager, 57 Result.Context->getLangOpts(), 58 /*SkipTrailingWhitespaceAndNewLine=*/true)); 59 for (const auto *UsingShadow : Using->shadows()) { 60 const auto *TargetDecl = UsingShadow->getTargetDecl()->getCanonicalDecl(); 61 if (ShouldCheckDecl(TargetDecl)) 62 Context.UsingTargetDecls.insert(TargetDecl); 63 } 64 if (!Context.UsingTargetDecls.empty()) 65 Contexts.push_back(Context); 66 return; 67 } 68 69 // Mark using declarations as used by setting FoundDecls' value to zero. As 70 // the AST is walked in order, usages are only marked after a the 71 // corresponding using declaration has been found. 72 // FIXME: This currently doesn't look at whether the type reference is 73 // actually found with the help of the using declaration. 74 if (const auto *Used = Result.Nodes.getNodeAs<NamedDecl>("used")) { 75 if (const auto *Specialization = 76 dyn_cast<ClassTemplateSpecializationDecl>(Used)) 77 Used = Specialization->getSpecializedTemplate(); 78 removeFromFoundDecls(Used); 79 return; 80 } 81 82 if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>("used")) { 83 if (const auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) { 84 if (const auto *FDT = FD->getPrimaryTemplate()) 85 removeFromFoundDecls(FDT); 86 else 87 removeFromFoundDecls(FD); 88 } else if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { 89 removeFromFoundDecls(VD); 90 } 91 } 92 // Check the uninstantiated template function usage. 93 if (const auto *ULE = Result.Nodes.getNodeAs<UnresolvedLookupExpr>("used")) { 94 for (const NamedDecl* ND : ULE->decls()) { 95 if (const auto *USD = dyn_cast<UsingShadowDecl>(ND)) 96 removeFromFoundDecls(USD->getTargetDecl()->getCanonicalDecl()); 97 } 98 } 99 } 100 101 void UnusedUsingDeclsCheck::removeFromFoundDecls(const Decl *D) { 102 for (auto &Context : Contexts) { 103 if (Context.UsingTargetDecls.count(D->getCanonicalDecl()) > 0) { 104 Context.IsUsed = true; 105 break; 106 } 107 } 108 } 109 110 void UnusedUsingDeclsCheck::onEndOfTranslationUnit() { 111 for (const auto &Context : Contexts) { 112 if (!Context.IsUsed) { 113 diag(Context.FoundUsingDecl->getLocation(), "using decl %0 is unused") 114 << Context.FoundUsingDecl 115 << FixItHint::CreateRemoval(Context.UsingDeclRange); 116 } 117 } 118 Contexts.clear(); 119 } 120 121 } // namespace misc 122 } // namespace tidy 123 } // namespace clang 124