diff options
author | Noel Grandin <noel@peralex.com> | 2016-05-05 09:46:12 +0200 |
---|---|---|
committer | Noel Grandin <noelgrandin@gmail.com> | 2016-05-06 06:48:38 +0000 |
commit | f3d9aab8410c00298f29ca0194c5d33d53c63ff2 (patch) | |
tree | 370d24d49547d8eb2cdbcb293992d9b9a4a670ed /compilerplugins | |
parent | 654c98064d3fd2bd1e13ae2bda5f84e8d51d0071 (diff) |
teach passstuffbyref plugin to check for..
unnecessarily passing primitives by const ref.
Suggested by Tor Lillqvist
Change-Id: I445e220542969ca3e252581e5953fb01cb2b2be6
Reviewed-on: https://gerrit.libreoffice.org/24672
Reviewed-by: Tor Lillqvist <tml@collabora.com>
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/passstuffbyref.cxx | 103 |
1 files changed, 79 insertions, 24 deletions
diff --git a/compilerplugins/clang/passstuffbyref.cxx b/compilerplugins/clang/passstuffbyref.cxx index c30b6fb6d9ca..a14d01f6a5a4 100644 --- a/compilerplugins/clang/passstuffbyref.cxx +++ b/compilerplugins/clang/passstuffbyref.cxx @@ -42,11 +42,18 @@ public: bool VisitLambdaExpr(const LambdaExpr * expr); private: + void checkParams(const FunctionDecl * functionDecl); + void checkReturnValue(const FunctionDecl * functionDecl, const CXXMethodDecl * methodDecl); bool isFat(QualType type); + bool isPrimitiveConstRef(QualType type); bool mbInsideFunctionDecl; bool mbFoundDisqualifier; }; +bool startswith(const std::string& rStr, const char* pSubStr) { + return rStr.compare(0, strlen(pSubStr), pSubStr) == 0; +} + bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) { if (ignoreLocation(functionDecl)) { return true; @@ -59,31 +66,60 @@ bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) { if (methodDecl && methodDecl->size_overridden_methods() > 0) { return true; } + + checkParams(functionDecl); + checkReturnValue(functionDecl, methodDecl); + return true; +} + +void PassStuffByRef::checkParams(const FunctionDecl * functionDecl) { // only warn on the definition/prototype of the function, // not on the function implementation - if (!functionDecl->isThisDeclarationADefinition()) - { - unsigned n = functionDecl->getNumParams(); - for (unsigned i = 0; i != n; ++i) { - const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i); - auto const t = pvDecl->getType(); - if (isFat(t)) { - report( - DiagnosticsEngine::Warning, - ("passing %0 by value, rather pass by const lvalue reference"), - pvDecl->getLocation()) - << t << pvDecl->getSourceRange(); - } + if (functionDecl->isThisDeclarationADefinition()) { + return; + } + unsigned n = functionDecl->getNumParams(); + for (unsigned i = 0; i != n; ++i) { + const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i); + auto const t = pvDecl->getType(); + if (isFat(t)) { + report( + DiagnosticsEngine::Warning, + ("passing %0 by value, rather pass by const lvalue reference"), + pvDecl->getLocation()) + << t << pvDecl->getSourceRange(); } - return true; } + // ignore stuff that forms part of the stable URE interface + if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc( + functionDecl->getCanonicalDecl()->getNameInfo().getLoc()))) { + return; + } + // these functions are passed as parameters to another function + std::string aFunctionName = functionDecl->getQualifiedNameAsString(); + if (startswith(aFunctionName, "slideshow::internal::ShapeAttributeLayer")) { + return; + } + for (unsigned i = 0; i != n; ++i) { + const ParmVarDecl * pvDecl = functionDecl->getParamDecl(i); + auto const t = pvDecl->getType(); + if (isPrimitiveConstRef(t)) { + report( + DiagnosticsEngine::Warning, + ("passing primitive type param %0 by const &, rather pass by value"), + pvDecl->getLocation()) + << t << pvDecl->getSourceRange(); + } + } +} +void PassStuffByRef::checkReturnValue(const FunctionDecl * functionDecl, const CXXMethodDecl * methodDecl) { if (methodDecl && methodDecl->isVirtual()) { - return true; + return; } if( !functionDecl->hasBody()) { - return true; + return; } const QualType type = functionDecl->getReturnType().getDesugaredType(compiler.getASTContext()); @@ -91,37 +127,37 @@ bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) { || type->isTemplateTypeParmType() || type->isDependentType() || type->isBuiltinType() || type->isScalarType()) { - return true; + return; } // ignore stuff that forms part of the stable URE interface if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc( functionDecl->getCanonicalDecl()->getNameInfo().getLoc()))) { - return true; + return; } std::string aFunctionName = functionDecl->getQualifiedNameAsString(); // function is passed as parameter to another function if (aFunctionName == "GDIMetaFile::ImplColMonoFnc" || aFunctionName == "editeng::SvxBorderLine::darkColor" || aFunctionName.compare(0, 8, "xforms::") == 0) - return true; + return; // not sure how to exclude this yet, returns copy of one of it's params if (aFunctionName == "sameDistColor" || aFunctionName == "sameColor" || aFunctionName == "pcr::(anonymous namespace)::StringIdentity::operator()" || aFunctionName == "matop::COp<type-parameter-0-0, svl::SharedString>::operator()" || aFunctionName == "slideshow::internal::accumulate" || aFunctionName == "slideshow::internal::lerp") - return true; + return; // depends on a define if (aFunctionName == "SfxObjectShell::GetSharedFileURL") - return true; + return; mbInsideFunctionDecl = true; mbFoundDisqualifier = false; TraverseStmt(functionDecl->getBody()); mbInsideFunctionDecl = false; if (mbFoundDisqualifier) - return true; + return; report( DiagnosticsEngine::Warning, @@ -138,8 +174,6 @@ bool PassStuffByRef::VisitFunctionDecl(const FunctionDecl * functionDecl) { functionDecl->getCanonicalDecl()->getSourceRange().getBegin()) << functionDecl->getCanonicalDecl()->getSourceRange(); } - //functionDecl->dump(); - return true; } bool PassStuffByRef::VisitLambdaExpr(const LambdaExpr * expr) { @@ -185,6 +219,27 @@ bool PassStuffByRef::isFat(QualType type) { && compiler.getASTContext().getTypeSizeInChars(t2).getQuantity() > 64; } +bool PassStuffByRef::isPrimitiveConstRef(QualType type) { + if (type->isIncompleteType()) { + return false; + } + if (!type->isReferenceType()) { + return false; + } + const clang::ReferenceType* referenceType = dyn_cast<ReferenceType>(type); + QualType pointeeQT = referenceType->getPointeeType(); + if (!pointeeQT.isConstQualified()) { + return false; + } + if (!pointeeQT->isFundamentalType()) { + return false; + } + // ignore double for now, some of our code seems to believe it is cheaper to pass by ref + const BuiltinType* builtinType = dyn_cast<BuiltinType>(pointeeQT); + return builtinType->getKind() != BuiltinType::Kind::Double; +} + + loplugin::Plugin::Registration< PassStuffByRef > X("passstuffbyref"); } |