/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/** Look for virtual methods where all of the overrides either (a) do nothing (b) all return the same value
The process goes something like this: $ make check $ make FORCE_COMPILE=all COMPILER_PLUGIN_TOOL='VirtualDead' check $ ./compilerplugins/clang/VirtualDead.py $ for dir in *; do make FORCE_COMPILE=all UPDATE_FILES=$dir COMPILER_PLUGIN_TOOL='removevirtuals' $dir; done
Note that the actual process may involve a fair amount of undoing, hand editing, and general messing around to get it to work :-)
*/
std::string niceName(const CXXMethodDecl* cxxMethodDecl)
{ while (cxxMethodDecl->getTemplateInstantiationPattern())
cxxMethodDecl = dyn_cast<CXXMethodDecl>(cxxMethodDecl->getTemplateInstantiationPattern()); while (cxxMethodDecl->getInstantiatedFromMemberFunction())
cxxMethodDecl = dyn_cast<CXXMethodDecl>(cxxMethodDecl->getInstantiatedFromMemberFunction());
std::string s = cxxMethodDecl->getReturnType().getCanonicalType().getAsString() + " "
+ cxxMethodDecl->getQualifiedNameAsString() + "("; for (const ParmVarDecl* pParmVarDecl : cxxMethodDecl->parameters())
{
s += pParmVarDecl->getType().getCanonicalType().getAsString();
s += ",";
}
s += ")"; if (cxxMethodDecl->isConst())
{
s += "const";
} return s;
}
bool VirtualDead::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
{ if (!methodDecl->isVirtual() || methodDecl->isDeleted()) returntrue; if (isa<CXXDestructorDecl>(methodDecl)) returntrue; // ignore stuff that forms part of the stable URE interface if (isInUnoIncludeFile(methodDecl->getCanonicalDecl())) returntrue;
if (!methodDecl->isThisDeclarationADefinition()) returntrue;
std::string returnValue;
auto body = methodDecl->getBody(); if (body)
{ auto compoundStmt = dyn_cast<CompoundStmt>(body); if (!compoundStmt)
returnValue = "empty"; elseif (compoundStmt->size() == 0)
returnValue = "empty"; else
{ if (auto returnStmt = dyn_cast<ReturnStmt>(*compoundStmt->body_begin()))
{ if (!returnStmt->getRetValue())
returnValue = "empty"; else
returnValue = getCallValue(returnStmt->getRetValue());
} else
returnValue = "unknown-stmt";
}
} else
returnValue = "empty";
std::string paramBitfield; for (auto it = methodDecl->param_begin(); it != methodDecl->param_end(); ++it)
{ auto param = *it;
paramBitfield += param->getName().empty() ? "0" : "1";
}
for (auto iter = methodDecl->begin_overridden_methods();
iter != methodDecl->end_overridden_methods(); ++iter)
{ const CXXMethodDecl* overriddenMethod = *iter;
markSuperclassMethods(overriddenMethod, returnValue, paramBitField);
}
}
std::string VirtualDead::getCallValue(const Expr* arg)
{
arg = arg->IgnoreParenCasts(); if (isa<CXXDefaultArgExpr>(arg))
{
arg = dyn_cast<CXXDefaultArgExpr>(arg)->getExpr();
}
arg = arg->IgnoreParenCasts(); // ignore this, it seems to trigger an infinite recursion if (isa<UnaryExprOrTypeTraitExpr>(arg)) return"unknown1"; if (arg->isValueDependent()) return"unknown2";
APSInt x1; if (compat::EvaluateAsInt(arg, x1, compiler.getASTContext()))
{ return compat::toString(x1, 10);
} if (isa<CXXNullPtrLiteralExpr>(arg))
{ return"0";
} if (isa<MaterializeTemporaryExpr>(arg))
{ const CXXBindTemporaryExpr* strippedArg
= dyn_cast_or_null<CXXBindTemporaryExpr>(arg->IgnoreParenCasts()); if (strippedArg)
{ auto temp = dyn_cast<CXXTemporaryObjectExpr>(strippedArg->getSubExpr()); if (temp->getNumArgs() == 0)
{ if (loplugin::TypeCheck(temp->getType())
.Class("OUString")
.Namespace("rtl")
.GlobalNamespace())
{ return"\"\"";
} if (loplugin::TypeCheck(temp->getType())
.Class("OString")
.Namespace("rtl")
.GlobalNamespace())
{ return"\"\"";
} return"defaultConstruct";
}
}
}
// Get the expression contents. // This helps us find params which are always initialised with something like "OUString()".
SourceManager& SM = compiler.getSourceManager();
SourceLocation startLoc = arg->getBeginLoc();
SourceLocation endLoc = arg->getEndLoc(); constchar* p1 = SM.getCharacterData(startLoc); constchar* p2 = SM.getCharacterData(endLoc); if (!p1 || !p2 || (p2 - p1) < 0 || (p2 - p1) > 40)
{ return"unknown3";
} unsigned n = Lexer::MeasureTokenLength(endLoc, SM, compiler.getLangOpts());
std::string s(p1, p2 - p1 + n); // strip linefeed and tab characters so they don't interfere with the parsing of the log file
std::replace(s.begin(), s.end(), '\r', ' ');
std::replace(s.begin(), s.end(), '\n', ' ');
std::replace(s.begin(), s.end(), '\t', ' ');
// now normalize the value. For some params, like OUString, we can pass it as OUString() or "" and they are the same thing if (s == "OUString()")
s = "\"\""; elseif (s == "OString()")
s = "\"\"";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.