diff options
author | Noel Grandin <noel@peralex.com> | 2015-07-16 14:45:53 +0200 |
---|---|---|
committer | Noel Grandin <noelgrandin@gmail.com> | 2015-07-17 06:49:23 +0000 |
commit | 5a7bf1b32c3699c9ca40d60e61403a3b587f35ff (patch) | |
tree | 0b9cf1aa793c09e8bf761e8b284f980be8ee473b /compilerplugins/clang/unusedmethods.cxx | |
parent | 9b9e75a078306180a59011cc116cf179d24518ff (diff) |
loplugin:unusedmethods slideshow
Change-Id: I66b6cddb638a9fc1228d3ea9df5d112300a00eb3
Reviewed-on: https://gerrit.libreoffice.org/17128
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
Diffstat (limited to 'compilerplugins/clang/unusedmethods.cxx')
-rw-r--r-- | compilerplugins/clang/unusedmethods.cxx | 92 |
1 files changed, 58 insertions, 34 deletions
diff --git a/compilerplugins/clang/unusedmethods.cxx b/compilerplugins/clang/unusedmethods.cxx index 6d0303dbf56f..a137a216cfc6 100644 --- a/compilerplugins/clang/unusedmethods.cxx +++ b/compilerplugins/clang/unusedmethods.cxx @@ -35,9 +35,6 @@ to get it to work :-) TODO deal with calls to superclass/member constructors from other constructors, so we can find unused constructors -TODO deal with free functions and static methods -TODO track instantiations of template class constructor methods -TODO track instantiation of overridden methods when a template class is instantiated */ namespace { @@ -71,18 +68,20 @@ public: } bool VisitCallExpr(CallExpr* ); - bool VisitCXXMethodDecl( const CXXMethodDecl* decl ); + bool VisitFunctionDecl( const FunctionDecl* decl ); bool VisitDeclRefExpr( const DeclRefExpr* ); - bool TraverseCXXMethodDecl(CXXMethodDecl * decl) { return RecursiveASTVisitor::TraverseCXXMethodDecl(decl); } + bool VisitCXXConstructExpr( const CXXConstructExpr* ); }; -static std::string niceName(const CXXMethodDecl* functionDecl) +static std::string niceName(const FunctionDecl* functionDecl) { std::string s = compat::getReturnType(*functionDecl).getCanonicalType().getAsString() - + " " + functionDecl->getParent()->getQualifiedNameAsString() - + "::" + functionDecl->getNameAsString() - + "("; + + " "; + if (isa<CXXMethodDecl>(functionDecl)) { + s += dyn_cast<CXXMethodDecl>(functionDecl)->getParent()->getQualifiedNameAsString() + "::"; + } + s += functionDecl->getNameAsString() + "("; bool bFirst = true; for (const ParmVarDecl *pParmVarDecl : functionDecl->params()) { if (bFirst) @@ -92,27 +91,30 @@ static std::string niceName(const CXXMethodDecl* functionDecl) s += pParmVarDecl->getType().getCanonicalType().getAsString(); } s += ")"; - if (functionDecl->isConst()) { + if (isa<CXXMethodDecl>(functionDecl) && dyn_cast<CXXMethodDecl>(functionDecl)->isConst()) { s += " const"; } return s; } -static void logCallToRootMethods(const CXXMethodDecl* decl) +static void logCallToRootMethods(const FunctionDecl* functionDecl) { - // For virtual/overriding methods, we need to pretend we called the root method(s), - // so that they get marked as used. - decl = decl->getCanonicalDecl(); + functionDecl = functionDecl->getCanonicalDecl(); bool bPrinted = false; - for(CXXMethodDecl::method_iterator it = decl->begin_overridden_methods(); - it != decl->end_overridden_methods(); ++it) - { - logCallToRootMethods(*it); - bPrinted = true; + if (isa<CXXMethodDecl>(functionDecl)) { + // For virtual/overriding methods, we need to pretend we called the root method(s), + // so that they get marked as used. + const CXXMethodDecl* methodDecl = dyn_cast<CXXMethodDecl>(functionDecl); + for(CXXMethodDecl::method_iterator it = methodDecl->begin_overridden_methods(); + it != methodDecl->end_overridden_methods(); ++it) + { + logCallToRootMethods(*it); + bPrinted = true; + } } if (!bPrinted) { - std::string s = niceName(decl); + std::string s = niceName(functionDecl); callSet.insert(s); } } @@ -154,18 +156,42 @@ bool UnusedMethods::VisitCallExpr(CallExpr* expr) // if the function is templated. However, if we are inside a template function, // calling another function on the same template, the same problem occurs. // Rather than tracking all of that, just traverse anything we have not already traversed. - if (traversedFunctionSet.insert(calleeFunctionDecl->getQualifiedNameAsString()).second) + if (traversedFunctionSet.insert(niceName(calleeFunctionDecl)).second) TraverseFunctionDecl(calleeFunctionDecl); - CXXMethodDecl* calleeMethodDecl = dyn_cast_or_null<CXXMethodDecl>(calleeFunctionDecl); - if (calleeMethodDecl == nullptr) { + logCallToRootMethods(calleeFunctionDecl); + return true; +} + +bool UnusedMethods::VisitCXXConstructExpr(const CXXConstructExpr* expr) +{ + // I don't use the normal ignoreLocation() here, because I __want__ to include files that are + // compiled in the $WORKDIR since they may refer to normal code + SourceLocation expansionLoc = compiler.getSourceManager().getExpansionLoc( expr->getLocStart() ); + if( compiler.getSourceManager().isInSystemHeader( expansionLoc )) + return true; + + const CXXConstructorDecl *consDecl = expr->getConstructor(); + consDecl = consDecl->getCanonicalDecl(); + if (consDecl->getTemplatedKind() == FunctionDecl::TemplatedKind::TK_NonTemplate + && !consDecl->isFunctionTemplateSpecialization()) { return true; } - logCallToRootMethods(calleeMethodDecl); + // if we see a call to a constructor, it may effectively create a whole new class, + // if the constructor's class is templated. + if (!traversedFunctionSet.insert(niceName(consDecl)).second) + return true; + + const CXXRecordDecl* parent = consDecl->getParent(); + for( CXXRecordDecl::ctor_iterator it = parent->ctor_begin(); it != parent->ctor_end(); ++it) + TraverseCXXConstructorDecl(*it); + for( CXXRecordDecl::method_iterator it = parent->method_begin(); it != parent->method_end(); ++it) + TraverseCXXMethodDecl(*it); + return true; } -bool UnusedMethods::VisitCXXMethodDecl( const CXXMethodDecl* functionDecl ) +bool UnusedMethods::VisitFunctionDecl( const FunctionDecl* functionDecl ) { // I don't use the normal ignoreLocation() here, because I __want__ to include files that are // compiled in the $WORKDIR since they may refer to normal code @@ -174,12 +200,10 @@ bool UnusedMethods::VisitCXXMethodDecl( const CXXMethodDecl* functionDecl ) return true; functionDecl = functionDecl->getCanonicalDecl(); + const CXXMethodDecl* methodDecl = dyn_cast_or_null<CXXMethodDecl>(functionDecl); + // ignore method overrides, since the call will show up as being directed to the root method - if (functionDecl->size_overridden_methods() != 0 || functionDecl->hasAttr<OverrideAttr>()) { - return true; - } - // ignore static's for now. Would require generalising this plugin a little - if (functionDecl->isStatic()) { + if (methodDecl && (methodDecl->size_overridden_methods() != 0 || methodDecl->hasAttr<OverrideAttr>())) { return true; } // ignore stuff that forms part of the stable URE interface @@ -187,7 +211,7 @@ bool UnusedMethods::VisitCXXMethodDecl( const CXXMethodDecl* functionDecl ) functionDecl->getNameInfo().getLoc()))) { return true; } - if (isStandardStuff(functionDecl->getParent()->getQualifiedNameAsString())) { + if (methodDecl && isStandardStuff(methodDecl->getParent()->getQualifiedNameAsString())) { return true; } if (isa<CXXDestructorDecl>(functionDecl)) { @@ -196,7 +220,7 @@ bool UnusedMethods::VisitCXXMethodDecl( const CXXMethodDecl* functionDecl ) if (isa<CXXConstructorDecl>(functionDecl)) { return true; } - if (functionDecl->isDeleted()) { + if (methodDecl && methodDecl->isDeleted()) { return true; } @@ -214,10 +238,10 @@ bool UnusedMethods::VisitDeclRefExpr( const DeclRefExpr* declRefExpr ) return true; const Decl* functionDecl = declRefExpr->getDecl(); - if (!isa<CXXMethodDecl>(functionDecl)) { + if (!isa<FunctionDecl>(functionDecl)) { return true; } - logCallToRootMethods(dyn_cast<CXXMethodDecl>(functionDecl)->getCanonicalDecl()); + logCallToRootMethods(dyn_cast<FunctionDecl>(functionDecl)->getCanonicalDecl()); return true; } |