Index: clang-tidy/misc/UnusedUsingDeclsCheck.h =================================================================== --- clang-tidy/misc/UnusedUsingDeclsCheck.h +++ clang-tidy/misc/UnusedUsingDeclsCheck.h @@ -30,6 +30,8 @@ void onEndOfTranslationUnit() override; private: + void removeFromFoundDecls(const Decl *D); + llvm::DenseMap FoundDecls; llvm::DenseMap FoundRanges; }; Index: clang-tidy/misc/UnusedUsingDeclsCheck.cpp =================================================================== --- clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -23,6 +23,7 @@ auto DeclMatcher = hasDeclaration(namedDecl().bind("used")); Finder->addMatcher(loc(recordType(DeclMatcher)), this); Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)), this); + Finder->addMatcher(declRefExpr().bind("used"), this); } void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { @@ -34,8 +35,13 @@ const auto *TargetDecl = Using->shadow_begin()->getTargetDecl()->getCanonicalDecl(); - // FIXME: Handle other target types. - if (!isa(TargetDecl) && !isa(TargetDecl)) + // Ignores using-declarations defined in class definition. + if (isa(TargetDecl->getDeclContext())) + return; + + if (!isa(TargetDecl) && !isa(TargetDecl) && + !isa(TargetDecl) && !isa(TargetDecl) && + !isa(TargetDecl)) return; FoundDecls[TargetDecl] = Using; @@ -57,10 +63,26 @@ if (const auto *Specialization = dyn_cast(Used)) Used = Specialization->getSpecializedTemplate(); - auto I = FoundDecls.find(Used->getCanonicalDecl()); - if (I != FoundDecls.end()) - I->second = nullptr; + removeFromFoundDecls(Used->getCanonicalDecl()); + return; } + + if (const auto *DRE = Result.Nodes.getNodeAs("used")) { + if (const auto *FD = dyn_cast(DRE->getDecl())) { + if (const auto *FDT = FD->getPrimaryTemplate()) + removeFromFoundDecls(FDT->getCanonicalDecl()); + else + removeFromFoundDecls(FD->getCanonicalDecl()); + } else if (const auto *VD = dyn_cast(DRE->getDecl())) { + removeFromFoundDecls(VD->getCanonicalDecl()); + } + } +} + +void UnusedUsingDeclsCheck::removeFromFoundDecls(const Decl *D) { + auto I = FoundDecls.find(D); + if (I != FoundDecls.end()) + I->second = nullptr; } void UnusedUsingDeclsCheck::onEndOfTranslationUnit() { Index: test/clang-tidy/misc-unused-using-decls.cpp =================================================================== --- test/clang-tidy/misc-unused-using-decls.cpp +++ test/clang-tidy/misc-unused-using-decls.cpp @@ -10,6 +10,32 @@ class D { public: static int i; }; template class E {}; template class F {}; +class G { public: static void func() {} }; +class H { public: static int i; }; +class I { + public: + static int ii; +}; + +class Base { + public: + void f(); +}; + +D UsedInstance; +D UnusedInstance; + +int UsedFunc() { return 1; } +int UnusedFunc() { return 1; } +template int UsedTemplateFunc() { return 1; } +template int UnusedTemplateFunc() { return 1; } + +class ostream { +public: + ostream &operator<<(ostream &(*PF)(ostream &)); +}; +extern ostream cout; +ostream &endl(ostream &os); } // ----- Using declarations ----- @@ -24,6 +50,25 @@ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'E' is unused // CHECK-FIXES: {{^}}// E using n::F; +using n::G; +using n::H; +using n::I; +int I::ii = 1; +class Derived : public Base { + public: + using Base::f; +}; +using n::UsedInstance; +using n::UsedFunc; +using n::UsedTemplateFunc; +using n::UnusedInstance; // UnusedInstance +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedInstance' is unused +// CHECK-FIXES: {{^}}// UnusedInstance +using n::UnusedFunc; // UnusedFunc +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: using decl 'UnusedFunc' is unused +// CHECK-FIXES: {{^}}// UnusedFunc +using n::cout; +using n::endl; // ----- Usages ----- void f(B b); @@ -31,5 +76,11 @@ vector data; D::i = 1; F f; + void (*func)() = &G::func; + int *i = &H::i; + UsedInstance.i; + UsedFunc(); + UsedTemplateFunc(); + cout << endl; }