diff options
Diffstat (limited to 'compilerplugins/clang/refcounting.cxx')
-rw-r--r-- | compilerplugins/clang/refcounting.cxx | 539 |
1 files changed, 445 insertions, 94 deletions
diff --git a/compilerplugins/clang/refcounting.cxx b/compilerplugins/clang/refcounting.cxx index 31b1540d391e..801173ce6488 100644 --- a/compilerplugins/clang/refcounting.cxx +++ b/compilerplugins/clang/refcounting.cxx @@ -6,13 +6,13 @@ * 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/. */ -#ifndef LO_CLANG_SHARED_PLUGINS #include <string> #include <iostream> #include "check.hxx" #include "plugin.hxx" +#include "config_clang.h" #include "clang/AST/CXXInheritance.h" /** @@ -56,6 +56,10 @@ public: bool VisitFieldDecl(const FieldDecl *); bool VisitVarDecl(const VarDecl *); bool VisitFunctionDecl(const FunctionDecl *); + bool VisitTypeLoc(clang::TypeLoc typeLoc); + bool VisitCXXDeleteExpr(const CXXDeleteExpr *); + bool VisitBinaryOperator(const BinaryOperator *); + bool VisitReturnStmt(const ReturnStmt *); // Creation of temporaries with one argument are represented by // CXXFunctionalCastExpr, while any other number of arguments are @@ -70,6 +74,8 @@ private: const RecordDecl* parent, const std::string& rDeclName); bool visitTemporaryObjectExpr(Expr const * expr); + bool isCastingReference(const Expr* expr); + bool isCallingGetOnWeakRef(const Expr* expr); }; bool containsXInterfaceSubclass(const clang::Type* pType0); @@ -201,6 +207,65 @@ bool containsXInterfaceSubclass(const clang::Type* pType0) { } } +bool containsOWeakObjectSubclass(const clang::Type* pType0); + +bool containsOWeakObjectSubclass(const QualType& qType) { + return containsOWeakObjectSubclass(qType.getTypePtr()); +} + +bool containsOWeakObjectSubclass(const clang::Type* pType0) { + if (!pType0) + return false; + if (pType0->isDependentType()) { + return false; + } + const clang::Type* pType = pType0->getUnqualifiedDesugaredType(); + if (!pType) + return false; + const CXXRecordDecl* pRecordDecl = pType->getAsCXXRecordDecl(); + if (pRecordDecl) { + // because dbaccess just has to be special... + loplugin::DeclCheck dc(pRecordDecl); + if (dc.Class("DocumentEvents").Namespace("dbaccess") + .GlobalNamespace() || + dc.Class("OBookmarkContainer").Namespace("dbaccess") + .GlobalNamespace()) + return false; + // TODO not sure about these ones, just avoiding dbaccess in general for now + if (dc.Class("SbaXPropertiesChangeMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXSubmitMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXResetMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXPropertyChangeMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXSQLErrorMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXParameterMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXRowSetApproveMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXRowSetMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXLoadMultiplexer").Namespace("dbaui").GlobalNamespace() || + dc.Class("SbaXVetoableChangeMultiplexer").Namespace("dbaui").GlobalNamespace()) + return false; + // slideshow playing games here + if (dc.Class("SlideView").AnonymousNamespace().Namespace("internal").Namespace("slideshow").GlobalNamespace()) + return false; + // svx playing acquire/release games here in OWeakSubObject + if (dc.Class("FmXUpdateMultiplexer").GlobalNamespace() || + dc.Class("FmXContainerMultiplexer").GlobalNamespace() || + dc.Class("FmXSelectionMultiplexer").GlobalNamespace() || + dc.Class("FmXGridControlMultiplexer").GlobalNamespace() || + dc.Class("FmXModifyMultiplexer").GlobalNamespace()) + return false; + } + if (pType->isPointerType()) { + // ignore + return false; + } else if (pType->isArrayType()) { + const clang::ArrayType* pArrayType = dyn_cast<clang::ArrayType>(pType); + QualType elementType = pArrayType->getElementType(); + return containsOWeakObjectSubclass(elementType); + } else { + return loplugin::isDerivedFrom(pRecordDecl, [](Decl const * decl) -> bool { return bool(loplugin::DeclCheck(decl).Class("OWeakObject").Namespace("cppu").GlobalNamespace()); }); + } +} + bool containsSvRefBaseSubclass(const clang::Type* pType0) { if (!pType0) return false; @@ -313,24 +378,30 @@ static bool containsStaticTypeMethod(const CXXRecordDecl* x) void RefCounting::checkUnoReference(QualType qt, const Decl* decl, const RecordDecl* parent, const std::string& rDeclName) { - if (loplugin::TypeCheck(qt).Class("Reference").Namespace("uno").Namespace("star").Namespace("sun").Namespace("com").GlobalNamespace()) { - const CXXRecordDecl* pRecordDecl = qt->getAsCXXRecordDecl(); - const ClassTemplateSpecializationDecl* pTemplate = dyn_cast<ClassTemplateSpecializationDecl>(pRecordDecl); - const TemplateArgument& rArg = pTemplate->getTemplateArgs()[0]; - const CXXRecordDecl* templateParam = rArg.getAsType()->getAsCXXRecordDecl()->getDefinition(); - if (templateParam && !containsStaticTypeMethod(templateParam)) { - report( - DiagnosticsEngine::Warning, - ("uno::Reference %0 with template parameter that does not" - " contain ::static_type() %1%select{|, parent is %3,}2 should" - " probably be using rtl::Reference instead"), - decl->getLocation()) - << rDeclName << qt << (parent != nullptr) - << (parent != nullptr - ? parent->getQualifiedNameAsString() : std::string()) - << decl->getSourceRange(); - } - } + if (!loplugin::TypeCheck(qt).Class("Reference").Namespace("uno").Namespace("star").Namespace("sun").Namespace("com").GlobalNamespace()) + return; + const CXXRecordDecl* pRecordDecl = qt->getAsCXXRecordDecl(); + const ClassTemplateSpecializationDecl* pTemplate = dyn_cast<ClassTemplateSpecializationDecl>(pRecordDecl); + const TemplateArgument& rArg = pTemplate->getTemplateArgs()[0]; + const CXXRecordDecl* templateParam = rArg.getAsType()->getAsCXXRecordDecl()->getDefinition(); + if (!templateParam) + return; + // SwXText is a special case. It is a mixin class that does not inherit from OWeakObject, so + // we cannot use rtl::Reference. + if (loplugin::DeclCheck(templateParam).Class("SwXText")) + return; + if (containsStaticTypeMethod(templateParam)) + return; + report( + DiagnosticsEngine::Warning, + ("uno::Reference %0 with template parameter that does not" + " contain ::static_type() %1%select{|, parent is %3,}2 should" + " probably be using rtl::Reference instead"), + decl->getLocation()) + << rDeclName << qt << (parent != nullptr) + << (parent != nullptr + ? parent->getQualifiedNameAsString() : std::string()) + << decl->getSourceRange(); } bool RefCounting::visitTemporaryObjectExpr(Expr const * expr) { @@ -343,7 +414,7 @@ bool RefCounting::visitTemporaryObjectExpr(Expr const * expr) { DiagnosticsEngine::Warning, ("Temporary object of SvRefBase subclass %0 being directly stack" " managed, should be managed via tools::SvRef"), - compat::getBeginLoc(expr)) + expr->getBeginLoc()) << t.getUnqualifiedType() << expr->getSourceRange(); } else if (containsSalhelperReferenceObjectSubclass(t.getTypePtr())) { report( @@ -351,7 +422,7 @@ bool RefCounting::visitTemporaryObjectExpr(Expr const * expr) { ("Temporary object of salhelper::SimpleReferenceObject subclass %0" " being directly stack managed, should be managed via" " rtl::Reference"), - compat::getBeginLoc(expr)) + expr->getBeginLoc()) << t.getUnqualifiedType() << expr->getSourceRange(); } else if (containsXInterfaceSubclass(t)) { report( @@ -359,12 +430,111 @@ bool RefCounting::visitTemporaryObjectExpr(Expr const * expr) { ("Temporary object of css::uno::XInterface subclass %0 being" " directly stack managed, should be managed via" " css::uno::Reference"), - compat::getBeginLoc(expr)) + expr->getBeginLoc()) + << t.getUnqualifiedType() << expr->getSourceRange(); + } else if (containsOWeakObjectSubclass(t)) { + report( + DiagnosticsEngine::Warning, + ("Temporary object of cppu::OWeakObject subclass %0 being" + " directly stack managed, should be managed via" + " css::uno::Reference"), + expr->getBeginLoc()) << t.getUnqualifiedType() << expr->getSourceRange(); } return true; } +// check for dodgy code managing ref-counted stuff with shared_ptr or unique_ptr or similar stuff +bool RefCounting::VisitTypeLoc(clang::TypeLoc typeLoc) +{ + QualType firstTemplateParamType; + if (auto recordType = typeLoc.getType()->getUnqualifiedDesugaredType()->getAs<RecordType>()) { + auto const tc = loplugin::TypeCheck(recordType); + if (tc.ClassOrStruct("unique_ptr").StdNamespace() + || tc.ClassOrStruct("weak_ptr").StdNamespace() + || tc.ClassOrStruct("shared_ptr").StdNamespace() + || tc.ClassOrStruct("intrusive_ptr").Namespace("boost").GlobalNamespace()) + { + auto templateDecl = dyn_cast<ClassTemplateSpecializationDecl>(recordType->getDecl()); + if (templateDecl && templateDecl->getTemplateArgs().size() > 0) + firstTemplateParamType = templateDecl->getTemplateArgs()[0].getAsType(); + } + } + if (firstTemplateParamType.isNull()) + return true; + if (containsSvRefBaseSubclass(firstTemplateParamType.getTypePtr())) + { + report( + DiagnosticsEngine::Warning, + "SvRefBase subclass %0 being managed via smart pointer, should be managed via tools::SvRef", + typeLoc.getBeginLoc()) + << firstTemplateParamType + << typeLoc.getSourceRange(); + } + if (containsSalhelperReferenceObjectSubclass(firstTemplateParamType.getTypePtr())) + { + report( + DiagnosticsEngine::Warning, + "salhelper::SimpleReferenceObject subclass %0 being managed via smart pointer, should be managed via rtl::Reference", + typeLoc.getBeginLoc()) + << firstTemplateParamType + << typeLoc.getSourceRange(); + } +// Not in general (dbaccess::DocumentEvents, dbaccess/source/core/dataaccess/databasedocument.hxx): +#if 0 + if (containsXInterfaceSubclass(firstTemplateParamType)) + { + report( + DiagnosticsEngine::Warning, + "XInterface subclass %0 being managed via smart pointer, should be managed via uno::Reference", + typeLoc.getBeginLoc()) + << firstTemplateParamType + << typeLoc.getSourceRange(); + } +#endif + if (containsOWeakObjectSubclass(firstTemplateParamType.getTypePtr())) + { + report( + DiagnosticsEngine::Warning, + "cppu::OWeakObject subclass %0 being managed via smart pointer, should be managed via rtl::Reference", + typeLoc.getBeginLoc()) + << firstTemplateParamType + << typeLoc.getSourceRange(); + } + return true; +} + +bool RefCounting::VisitCXXDeleteExpr(const CXXDeleteExpr * cxxDeleteExpr) +{ + if (ignoreLocation(cxxDeleteExpr)) + return true; + StringRef aFileName = getFilenameOfLocation( + compiler.getSourceManager().getSpellingLoc(cxxDeleteExpr->getBeginLoc())); + if (loplugin::isSamePathname(aFileName, SRCDIR "/cppuhelper/source/weak.cxx")) + return true; + if (loplugin::isSamePathname(aFileName, SRCDIR "/include/svx/svdobj.hxx")) + return true; + if (loplugin::isSamePathname(aFileName, SRCDIR "/svx/source/svdraw/svdobj.cxx")) + return true; + + if (!cxxDeleteExpr->getArgument()) + return true; + auto argType = cxxDeleteExpr->getArgument()->getType(); + if (argType.isNull() || !argType->isPointerType()) + return true; + auto pointeeType = argType->getPointeeType(); + if (containsOWeakObjectSubclass(pointeeType)) + { + report( + DiagnosticsEngine::Warning, + "cppu::OWeakObject subclass %0 being deleted via delete, should be managed via rtl::Reference", + cxxDeleteExpr->getBeginLoc()) + << pointeeType + << cxxDeleteExpr->getSourceRange(); + } + return true; +} + bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) { if (ignoreLocation(fieldDecl)) { return true; @@ -380,20 +550,6 @@ bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) { return true; } - // check for dodgy code managing ref-counted stuff with shared_ptr or unique_ptr or similar stuff - QualType firstTemplateParamType; - if (auto recordType = fieldDecl->getType()->getUnqualifiedDesugaredType()->getAs<RecordType>()) { - auto const tc = loplugin::TypeCheck(fieldDecl->getType()); - if (tc.Class("unique_ptr").StdNamespace() - || tc.Class("shared_ptr").StdNamespace() - || tc.Class("intrusive_ptr").Namespace("boost").GlobalNamespace()) - { - auto templateDecl = dyn_cast<ClassTemplateSpecializationDecl>(recordType->getDecl()); - if (templateDecl && templateDecl->getTemplateArgs().size() > 0) - firstTemplateParamType = templateDecl->getTemplateArgs()[0].getAsType(); - } - } - if (containsSvRefBaseSubclass(fieldDecl->getType().getTypePtr())) { report( DiagnosticsEngine::Warning, @@ -405,18 +561,6 @@ bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) { << fieldDecl->getSourceRange(); } - if (!firstTemplateParamType.isNull() && containsSvRefBaseSubclass(firstTemplateParamType.getTypePtr())) - { - report( - DiagnosticsEngine::Warning, - "SvRefBase subclass %0 being managed via smart pointer, should be managed via tools::SvRef, " - "parent is %1", - fieldDecl->getLocation()) - << firstTemplateParamType - << fieldDecl->getParent() - << fieldDecl->getSourceRange(); - } - if (containsSalhelperReferenceObjectSubclass(fieldDecl->getType().getTypePtr())) { report( DiagnosticsEngine::Warning, @@ -428,21 +572,10 @@ bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) { << fieldDecl->getSourceRange(); } - if (!firstTemplateParamType.isNull() && containsSalhelperReferenceObjectSubclass(firstTemplateParamType.getTypePtr())) - { - report( - DiagnosticsEngine::Warning, - "salhelper::SimpleReferenceObject subclass %0 being managed via smart pointer, should be managed via rtl::Reference, " - "parent is %1", - fieldDecl->getLocation()) - << firstTemplateParamType - << fieldDecl->getParent() - << fieldDecl->getSourceRange(); - } - auto const dc = loplugin::DeclCheck(fieldDecl->getParent()); if ( (dc.Class("BaseReference").Namespace("uno").Namespace("star") .Namespace("sun").Namespace("com").GlobalNamespace()) + || (dc.Class("Reference").Namespace("rtl").GlobalNamespace()) || (dc.Union("element_alias").Namespace("detail").Namespace("cppu") .GlobalNamespace()) // this is playing some kind of game to avoid circular references @@ -463,20 +596,16 @@ bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) { << fieldDecl->getSourceRange(); } -// Not in general (dbaccess::DocumentEvents, dbaccess/source/core/dataaccess/databasedocument.hxx): -#if 0 - if (!firstTemplateParamType.isNull() && containsXInterfaceSubclass(firstTemplateParamType)) - { + if (containsOWeakObjectSubclass(fieldDecl->getType())) { report( DiagnosticsEngine::Warning, - "XInterface subclass %0 being managed via smart pointer, should be managed via uno::Reference, " + "cppu::OWeakObject subclass %0 being directly heap managed, should be managed via rtl::Reference, " "parent is %1", fieldDecl->getLocation()) - << firstTemplateParamType + << fieldDecl->getType() << fieldDecl->getParent() << fieldDecl->getSourceRange(); } -#endif checkUnoReference( fieldDecl->getType(), fieldDecl, @@ -485,43 +614,267 @@ bool RefCounting::VisitFieldDecl(const FieldDecl * fieldDecl) { return true; } +bool RefCounting::VisitReturnStmt(const ReturnStmt * returnStmt) { + if (ignoreLocation(returnStmt)) { + return true; + } + + if (!returnStmt->getRetValue()) + return true; + auto cxxNewExpr = dyn_cast<CXXNewExpr>(returnStmt->getRetValue()->IgnoreImplicit()); + if (!cxxNewExpr) + return true; + + auto qt = returnStmt->getRetValue()->getType(); + if (!qt->isPointerType()) + return false; + qt = qt->getPointeeType(); + + if (containsOWeakObjectSubclass(qt)) { + report( + DiagnosticsEngine::Warning, + "new object of cppu::OWeakObject subclass %0 being returned via raw pointer, should be returned by via rtl::Reference", + returnStmt->getBeginLoc()) + << qt + << returnStmt->getSourceRange(); + } + + return true; +} bool RefCounting::VisitVarDecl(const VarDecl * varDecl) { - if (ignoreLocation(varDecl)) { + if (ignoreLocation(varDecl)) + return true; + + checkUnoReference(varDecl->getType(), varDecl, nullptr, "var"); + + if (isa<ParmVarDecl>(varDecl)) return true; + + if (containsSvRefBaseSubclass(varDecl->getType().getTypePtr())) { + report( + DiagnosticsEngine::Warning, + "SvRefBase subclass being directly stack managed, should be managed via tools::SvRef, " + + varDecl->getType().getAsString(), + varDecl->getLocation()) + << varDecl->getSourceRange(); } - if (!isa<ParmVarDecl>(varDecl)) { - if (containsSvRefBaseSubclass(varDecl->getType().getTypePtr())) { - report( - DiagnosticsEngine::Warning, - "SvRefBase subclass being directly stack managed, should be managed via tools::SvRef, " - + varDecl->getType().getAsString(), - varDecl->getLocation()) - << varDecl->getSourceRange(); + if (containsSalhelperReferenceObjectSubclass(varDecl->getType().getTypePtr())) { + StringRef name { getFilenameOfLocation( + compiler.getSourceManager().getSpellingLoc(varDecl->getLocation())) }; + // this is playing games that it believes is safe + if (loplugin::isSamePathname(name, SRCDIR "/stoc/source/security/permissions.cxx")) + return true; + report( + DiagnosticsEngine::Warning, + "salhelper::SimpleReferenceObject subclass being directly stack managed, should be managed via rtl::Reference, " + + varDecl->getType().getAsString(), + varDecl->getLocation()) + << varDecl->getSourceRange(); + } + if (containsXInterfaceSubclass(varDecl->getType())) { + report( + DiagnosticsEngine::Warning, + "XInterface subclass being directly stack managed, should be managed via uno::Reference, " + + varDecl->getType().getAsString(), + varDecl->getLocation()) + << varDecl->getSourceRange(); + } + if (containsOWeakObjectSubclass(varDecl->getType())) { + report( + DiagnosticsEngine::Warning, + "cppu::OWeakObject subclass being directly stack managed, should be managed via uno::Reference, " + + varDecl->getType().getAsString(), + varDecl->getLocation()) + << varDecl->getSourceRange(); + } + + if (varDecl->getType()->isPointerType() && varDecl->getInit()) + { + auto newExpr = dyn_cast<CXXNewExpr>(varDecl->getInit()->IgnoreImplicit()); + if (newExpr) + { + StringRef fileName = getFilenameOfLocation(compiler.getSourceManager().getSpellingLoc(varDecl->getBeginLoc())); + if (loplugin::isSamePathname(fileName, SRCDIR "/cppuhelper/source/component_context.cxx")) + return true; + auto pointeeType = varDecl->getType()->getPointeeType(); + if (containsOWeakObjectSubclass(pointeeType)) + report( + DiagnosticsEngine::Warning, + "cppu::OWeakObject subclass %0 being managed via raw pointer, should be managed via rtl::Reference", + varDecl->getLocation()) + << pointeeType + << varDecl->getSourceRange(); + } + if (isCastingReference(varDecl->getInit())) + { + // TODO false+ code + StringRef fileName = getFilenameOfLocation(compiler.getSourceManager().getSpellingLoc(varDecl->getBeginLoc())); + if (loplugin::isSamePathname(fileName, SRCDIR "/sw/source/core/unocore/unotbl.cxx")) + return true; + auto pointeeType = varDecl->getType()->getPointeeType(); + if (containsOWeakObjectSubclass(pointeeType)) + report( + DiagnosticsEngine::Warning, + "cppu::OWeakObject subclass %0 being managed via raw pointer, should be managed via rtl::Reference", + varDecl->getLocation()) + << pointeeType + << varDecl->getSourceRange(); + } + if (isCallingGetOnWeakRef(varDecl->getInit())) + { + auto pointeeType = varDecl->getType()->getPointeeType(); + if (containsOWeakObjectSubclass(pointeeType)) + report( + DiagnosticsEngine::Warning, + "weak object being converted to strong, and then the reference dropped, and managed via raw pointer, should be managed via rtl::Reference", + varDecl->getLocation()) + << pointeeType + << varDecl->getSourceRange(); } - if (containsSalhelperReferenceObjectSubclass(varDecl->getType().getTypePtr())) { - StringRef name { getFilenameOfLocation( - compiler.getSourceManager().getSpellingLoc(varDecl->getLocation())) }; - // this is playing games that it believes is safe - if (loplugin::isSamePathname(name, SRCDIR "/stoc/source/security/permissions.cxx")) + } + return true; +} + +/** + Look for code like + static_cast<FooChild*>(makeFoo().get()); + where makeFoo() returns a Reference<Foo> +*/ +bool RefCounting::isCastingReference(const Expr* expr) +{ + expr = expr->IgnoreImplicit(); + auto castExpr = dyn_cast<CastExpr>(expr); + if (!castExpr) + return false; + auto memberCallExpr = dyn_cast<CXXMemberCallExpr>(castExpr->getSubExpr()); + if (!memberCallExpr) + return false; + if (!memberCallExpr->getMethodDecl()->getIdentifier() || memberCallExpr->getMethodDecl()->getName() != "get") + return false; + QualType objectType = memberCallExpr->getImplicitObjectArgument()->getType(); + if (!loplugin::TypeCheck(objectType).Class("Reference")) + return false; + // ignore "x.get()" where x is a var + auto obj = memberCallExpr->getImplicitObjectArgument()->IgnoreImplicit(); + if (isa<DeclRefExpr>(obj) || isa<MemberExpr>(obj)) + return false; + // if the foo in foo().get() returns "rtl::Reference<T>&" then the variable + // we are assigning to does not __have__ to be Reference, since the method called + // must already be holding a reference. + if (auto callExpr = dyn_cast<CallExpr>(obj)) + { + if (auto callMethod = callExpr->getDirectCallee()) + if (callMethod->getReturnType()->isReferenceType()) + return false; + } + // Ignore + // WeakReference x; + // if (x.get.get()) + // and similar stuff + if (auto memberCall2 = dyn_cast<CXXMemberCallExpr>(obj)) + { + if (loplugin::TypeCheck(memberCall2->getImplicitObjectArgument()->getType()).Class("WeakReference")) + return false; + } + return true; +} + +/** + Look for code like + makeFoo().get(); + or + cast<T*>(makeFoo().get().get()); + or + foo.get(); + where makeFoo() returns a unotools::WeakReference<Foo> + and foo is a unotools::WeakReference<Foo> var. +*/ +bool RefCounting::isCallingGetOnWeakRef(const Expr* expr) +{ + expr = expr->IgnoreImplicit(); + // unwrap the cast (if any) + if (auto castExpr = dyn_cast<CastExpr>(expr)) + expr = castExpr->getSubExpr()->IgnoreImplicit(); + // unwrap outer get (if any) + if (auto memberCallExpr = dyn_cast<CXXMemberCallExpr>(expr)) + { + auto methodDecl = memberCallExpr->getMethodDecl(); + if (methodDecl && methodDecl->getIdentifier() && methodDecl->getName() == "get") + { + QualType objectType = memberCallExpr->getImplicitObjectArgument()->getType(); + if (loplugin::TypeCheck(objectType).Class("Reference").Namespace("rtl")) + expr = memberCallExpr->getImplicitObjectArgument()->IgnoreImplicit(); + } + } + // check for converting a WeakReference to a strong reference via get() + if (auto memberCallExpr = dyn_cast<CXXMemberCallExpr>(expr)) + { + auto methodDecl = memberCallExpr->getMethodDecl(); + if (methodDecl && methodDecl->getIdentifier() && methodDecl->getName() == "get") + { + QualType objectType = memberCallExpr->getImplicitObjectArgument()->getType(); + if (loplugin::TypeCheck(objectType).Class("WeakReference").Namespace("unotools")) return true; + } + } + return false; +} + +bool RefCounting::VisitBinaryOperator(const BinaryOperator * binaryOperator) +{ + if (ignoreLocation(binaryOperator)) + return true; + if (binaryOperator->getOpcode() != BO_Assign) + return true; + if (!binaryOperator->getLHS()->getType()->isPointerType()) + return true; + + auto newExpr = dyn_cast<CXXNewExpr>(binaryOperator->getRHS()->IgnoreImplicit()); + if (newExpr) + { + // deliberately does not want to keep track at the allocation site + StringRef fileName = getFilenameOfLocation(compiler.getSourceManager().getSpellingLoc(binaryOperator->getBeginLoc())); + if (loplugin::isSamePathname(fileName, SRCDIR "/vcl/unx/generic/dtrans/X11_selection.cxx")) + return true; + + auto pointeeType = binaryOperator->getLHS()->getType()->getPointeeType(); + if (containsOWeakObjectSubclass(pointeeType)) + { report( DiagnosticsEngine::Warning, - "salhelper::SimpleReferenceObject subclass being directly stack managed, should be managed via rtl::Reference, " - + varDecl->getType().getAsString(), - varDecl->getLocation()) - << varDecl->getSourceRange(); + "cppu::OWeakObject subclass %0 being managed via raw pointer, should be managed via rtl::Reference", + binaryOperator->getBeginLoc()) + << pointeeType + << binaryOperator->getSourceRange(); } - if (containsXInterfaceSubclass(varDecl->getType())) { + } + if (isCastingReference(binaryOperator->getRHS())) + { + auto pointeeType = binaryOperator->getLHS()->getType()->getPointeeType(); + if (containsOWeakObjectSubclass(pointeeType)) report( DiagnosticsEngine::Warning, - "XInterface subclass being directly stack managed, should be managed via uno::Reference, " - + varDecl->getType().getAsString(), - varDecl->getLocation()) - << varDecl->getSourceRange(); - } + "cppu::OWeakObject subclass %0 being managed via raw pointer, should be managed via rtl::Reference", + binaryOperator->getBeginLoc()) + << pointeeType + << binaryOperator->getSourceRange(); + } + if (isCallingGetOnWeakRef(binaryOperator->getRHS())) + { + // TODO Very dodgy code, but I see no simple way of fixing it + StringRef fileName = getFilenameOfLocation(compiler.getSourceManager().getSpellingLoc(binaryOperator->getBeginLoc())); + if (loplugin::isSamePathname(fileName, SRCDIR "/sd/source/ui/view/Outliner.cxx")) + return true; + auto pointeeType = binaryOperator->getLHS()->getType()->getPointeeType(); + if (containsOWeakObjectSubclass(pointeeType)) + report( + DiagnosticsEngine::Warning, + "weak object being converted to strong, and then the reference dropped, and managed via raw pointer, should be managed via rtl::Reference", + binaryOperator->getBeginLoc()) + << pointeeType + << binaryOperator->getSourceRange(); } - checkUnoReference(varDecl->getType(), varDecl, nullptr, "var"); return true; } @@ -543,6 +896,4 @@ loplugin::Plugin::Registration< RefCounting > refcounting("refcounting"); } -#endif // LO_CLANG_SHARED_PLUGINS - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |