summaryrefslogtreecommitdiff
path: root/compilerplugins/clang/refcounting.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/refcounting.cxx')
-rw-r--r--compilerplugins/clang/refcounting.cxx539
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: */