summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/passstuffbyref.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/passstuffbyref.cxx')
-rw-r--r--compilerplugins/clang/passstuffbyref.cxx94
1 files changed, 84 insertions, 10 deletions
diff --git a/compilerplugins/clang/passstuffbyref.cxx b/compilerplugins/clang/passstuffbyref.cxx
index 3cf7a352e89f..b1b3169f94c9 100644
--- a/compilerplugins/clang/passstuffbyref.cxx
+++ b/compilerplugins/clang/passstuffbyref.cxx
@@ -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(