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>
This commit is contained in:
Noel Grandin
2015-07-16 14:45:53 +02:00
committed by Noel Grandin
parent 9b9e75a078
commit 5a7bf1b32c
20 changed files with 60 additions and 214 deletions

View File

@@ -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) {
return true;
}
logCallToRootMethods(calleeMethodDecl);
logCallToRootMethods(calleeFunctionDecl);
return true;
}
bool UnusedMethods::VisitCXXMethodDecl( const CXXMethodDecl* functionDecl )
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;
}
// 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::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;
}