improve passstuffbyref return analysis

Change-Id: I4258bcc97273d8bb7a8c4879fac02a427f76e18c
Reviewed-on: https://gerrit.libreoffice.org/27317
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
This commit is contained in:
Noel Grandin
2016-07-18 09:22:27 +02:00
committed by Noel Grandin
parent 9f4af777a8
commit 508c95f1b6
366 changed files with 693 additions and 620 deletions

View File

@@ -36,7 +36,7 @@ public:
virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
// When warning about function params of primitive type that could be passed
// by value instead of by reference, make sure not to warn if the paremeter
// by value instead of by reference, make sure not to warn if the parameter
// is ever bound to a reference; on the one hand, this needs scaffolding in
// all Traverse*Decl functions (indirectly) derived from FunctionDecl; and
// on the other hand, use a hack of ignoring just the DeclRefExprs nested in
@@ -51,9 +51,8 @@ public:
bool TraverseImplicitCastExpr(ImplicitCastExpr * expr);
bool VisitDeclRefExpr(const DeclRefExpr * expr);
bool VisitCallExpr(const CallExpr * ) { if (mbInsideFunctionDecl) mbFoundDisqualifier = true; return true; }
bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr * ) { if (mbInsideFunctionDecl) mbFoundDisqualifier = true; return true; }
bool VisitDeclStmt(const DeclStmt * ) { if (mbInsideFunctionDecl) mbFoundDisqualifier = true; return true; }
bool VisitReturnStmt(const ReturnStmt * );
bool VisitVarDecl(const VarDecl * );
private:
template<typename T> bool traverseAnyFunctionDecl(
@@ -62,6 +61,8 @@ private:
void checkReturnValue(const FunctionDecl * functionDecl, const CXXMethodDecl * methodDecl);
bool isFat(QualType type);
bool isPrimitiveConstRef(QualType type);
bool isReturnExprDisqualified(const Expr* expr);
bool mbInsideFunctionDecl;
bool mbFoundDisqualifier;
@@ -228,10 +229,10 @@ void PassStuffByRef::checkParams(const FunctionDecl * functionDecl) {
void PassStuffByRef::checkReturnValue(const FunctionDecl * functionDecl, const CXXMethodDecl * methodDecl) {
if (methodDecl && methodDecl->isVirtual()) {
if (methodDecl && (methodDecl->isVirtual() || methodDecl->hasAttr<OverrideAttr>())) {
return;
}
if( !functionDecl->hasBody()) {
if( !functionDecl->doesThisDeclarationHaveABody()) {
return;
}
@@ -258,7 +259,8 @@ void PassStuffByRef::checkReturnValue(const FunctionDecl * functionDecl, const C
|| (dc.MemberFunction().Class("Model").Namespace("xforms")
.GlobalNamespace())
|| (dc.MemberFunction().Class("Submission").Namespace("xforms")
.GlobalNamespace()))
.GlobalNamespace())
|| (dc.Function("TopLeft").Class("SwRect").GlobalNamespace()))
{
return;
}
@@ -274,8 +276,7 @@ void PassStuffByRef::checkReturnValue(const FunctionDecl * functionDecl, const C
return;
// depends on a define
if (dc.Function("GetSharedFileURL").Class("SfxObjectShell")
.GlobalNamespace())
{
.GlobalNamespace()) {
return;
}
mbInsideFunctionDecl = true;
@@ -297,12 +298,85 @@ void PassStuffByRef::checkReturnValue(const FunctionDecl * functionDecl, const C
{
report(
DiagnosticsEngine::Note,
"rather return by const& than by value",
"decl here",
functionDecl->getCanonicalDecl()->getSourceRange().getBegin())
<< functionDecl->getCanonicalDecl()->getSourceRange();
}
}
bool PassStuffByRef::VisitReturnStmt(const ReturnStmt * returnStmt)
{
if (!mbInsideFunctionDecl)
return true;
const Expr* expr = dyn_cast<Expr>(*returnStmt->child_begin())->IgnoreParenCasts();
if (isReturnExprDisqualified(expr)) {
mbFoundDisqualifier = true;
return true;
}
return true;
}
bool PassStuffByRef::isReturnExprDisqualified(const Expr* expr)
{
if (isa<ExprWithCleanups>(expr)) {
return true;
}
if (const CXXConstructExpr* constructExpr = dyn_cast<CXXConstructExpr>(expr)) {
if (constructExpr->getNumArgs()==1) {
expr = constructExpr->getArg(0)->IgnoreParenCasts();
}
}
if (isa<CXXConstructExpr>(expr)) {
return true;
}
if (const ArraySubscriptExpr* childExpr = dyn_cast<ArraySubscriptExpr>(expr)) {
expr = childExpr->getLHS();
}
if (const MemberExpr* memberExpr = dyn_cast<MemberExpr>(expr)) {
expr = memberExpr->getBase();
}
if (const DeclRefExpr* declRef = dyn_cast<DeclRefExpr>(expr)) {
const VarDecl* varDecl = dyn_cast<VarDecl>(declRef->getDecl());
if (varDecl) {
if (varDecl->getStorageDuration() == SD_Automatic
|| varDecl->getStorageDuration() == SD_FullExpression ) {
return true;
}
return false;
}
}
if (const ConditionalOperator* condOper = dyn_cast<ConditionalOperator>(expr)) {
return isReturnExprDisqualified(condOper->getTrueExpr())
|| isReturnExprDisqualified(condOper->getFalseExpr());
}
if (const CallExpr* callExpr = dyn_cast<CallExpr>(expr)) {
return !loplugin::TypeCheck(callExpr->getType()).Const().LvalueReference();
}
return true;
}
bool PassStuffByRef::VisitVarDecl(const VarDecl * varDecl)
{
if (!mbInsideFunctionDecl)
return true;
// things guarded by locking are probably best left alone
loplugin::TypeCheck dc(varDecl->getType());
if (dc.Class("Guard").Namespace("osl").GlobalNamespace())
mbFoundDisqualifier = true;
if (dc.Class("ClearableGuard").Namespace("osl").GlobalNamespace())
mbFoundDisqualifier = true;
if (dc.Class("ResettableGuard").Namespace("osl").GlobalNamespace())
mbFoundDisqualifier = true;
else if (dc.Class("SolarMutexGuard").GlobalNamespace())
mbFoundDisqualifier = true;
else if (dc.Class("SfxModelGuard").GlobalNamespace())
mbFoundDisqualifier = true;
else if (dc.Class("ReadWriteGuard").Namespace("utl").GlobalNamespace())
mbFoundDisqualifier = true;
return true;
}
// Would produce a wrong recommendation for
//
// PresenterFrameworkObserver::RunOnUpdateEnd(