chart2/source/controller/dialogs/dlg_Theme.cxx | 1 chart2/source/controller/sidebar/ChartThemeControl.cxx | 1 chart2/source/controller/sidebar/ChartThemePanel.cxx | 1 compilerplugins/clang/scopedvclptr.cxx | 282 ++++++++++++++ compilerplugins/clang/test/scopedvclptr.cxx | 92 ++++ drawinglayer/source/processor2d/vclhelperbufferdevice.cxx | 1 sc/source/ui/inc/checklistmenu.hxx | 1 solenv/CompilerTest_compilerplugins_clang.mk | 1 svx/source/tbxctrls/StylesPreviewWindow.cxx | 2 svx/source/tbxctrls/SvxColorIconView.cxx | 1 svx/source/tbxctrls/fontworkgallery.cxx | 1 svx/source/tbxctrls/tbxcolorupdate.cxx | 2 svx/source/unodraw/UnoGraphicExporter.cxx | 1 sw/source/core/doc/DocumentDeviceManager.cxx | 2 vcl/inc/salvtables.hxx | 1 vcl/source/app/salvtables.cxx | 3 vcl/source/window/syswin.cxx | 1 vcl/unx/generic/gdi/cairo_xlib_cairo.cxx | 1 vcl/unx/gtk3/gtkcairo.cxx | 1 vcl/unx/gtk3/gtkinst.cxx | 5 20 files changed, 400 insertions(+), 1 deletion(-)
New commits: commit 3a3251eee5afcef78f1851d069d8e5824782fb12 Author: Andras Timar <[email protected]> AuthorDate: Sat Feb 21 16:17:57 2026 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Tue Feb 24 11:47:55 2026 +0100 new loplugin:scopedvclptr to detect VclPtr<VirtualDevice> leaks Two checks to prevent GDI handle leaks on Windows: 1. Local VclPtr<VirtualDevice> created via VclPtr::Create() but never disposed - should use ScopedVclPtr<VirtualDevice> instead. Suppressed when the variable is returned (factory), explicitly disposeAndClear()'d, or not initialized via VclPtr::Create(). 2. Functions returning VclPtr<VirtualDevice> - should return ScopedVclPtr<VirtualDevice> so callers get automatic cleanup. Both checks support // [-loplugin:scopedvclptr] suppression comments for cases where the code is correct but the plugin cannot prove it (e.g. ownership transfer to a container/member, virtual overrides whose base class dictates the return type). 17 existing false-positive sites suppressed across vcl, svx, sw, chart2, sc, drawinglayer, and editeng. Added additional 7 suppression comments to GTK-only code that doesn't affect Windows. Change-Id: I6556f2d4e27ab34d135c3fbc5a6c18e04a3e3e0e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199957 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/chart2/source/controller/dialogs/dlg_Theme.cxx b/chart2/source/controller/dialogs/dlg_Theme.cxx index a60b6e96a2a9..f75b2d977f68 100644 --- a/chart2/source/controller/dialogs/dlg_Theme.cxx +++ b/chart2/source/controller/dialogs/dlg_Theme.cxx @@ -77,6 +77,7 @@ SchThemeDlg::SchThemeDlg(weld::Window* pWindow, ChartController* pController, bo mxThemeIconView->select(0); } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> SchThemeDlg::makeImage(int nIndex) { // clone the chart diff --git a/chart2/source/controller/sidebar/ChartThemeControl.cxx b/chart2/source/controller/sidebar/ChartThemeControl.cxx index 531fe569f631..de356c1ea24d 100644 --- a/chart2/source/controller/sidebar/ChartThemeControl.cxx +++ b/chart2/source/controller/sidebar/ChartThemeControl.cxx @@ -194,6 +194,7 @@ ChartThemePopup::~ChartThemePopup() mxManageChartStylesButton.reset(); } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> ChartThemePopup::makeImage(int nIndex) { VclPtr<VirtualDevice> device1 = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA); diff --git a/chart2/source/controller/sidebar/ChartThemePanel.cxx b/chart2/source/controller/sidebar/ChartThemePanel.cxx index 9e9038d625f0..c9c11b0bee92 100644 --- a/chart2/source/controller/sidebar/ChartThemePanel.cxx +++ b/chart2/source/controller/sidebar/ChartThemePanel.cxx @@ -96,6 +96,7 @@ void ThemeWrapper::updateData() const void ThemeWrapper::select(const sal_uInt32 nIndex) { mpController->setTheme(nIndex); } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> ThemeWrapper::makePictureFromThemedChart(sal_uInt32 nIndex) { if (mpController) diff --git a/compilerplugins/clang/scopedvclptr.cxx b/compilerplugins/clang/scopedvclptr.cxx new file mode 100644 index 000000000000..9689a8cfec14 --- /dev/null +++ b/compilerplugins/clang/scopedvclptr.cxx @@ -0,0 +1,282 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. + */ + +#include <string> + +#include "check.hxx" +#include "plugin.hxx" +#include "config_clang.h" + +/** + * Two checks to prevent GDI handle leaks on Windows: + * + * 1. Local VclPtr<VirtualDevice> created via VclPtr::Create() but never + * disposed — should use ScopedVclPtr<VirtualDevice> instead. + * Suppressed when the variable is: + * - returned from the function (factory pattern) + * - explicitly disposeAndClear()'d / clear()'d + * - not initialized via VclPtr::Create() (borrowing a shared reference) + * + * 2. Functions returning VclPtr<VirtualDevice> — should return + * ScopedVclPtr<VirtualDevice> so callers get automatic cleanup. + * + * VclPtr does NOT call dispose() in its destructor. ScopedVclPtr does. + */ + +namespace +{ +// --------------------------------------------------------------------------- +// helpers +// --------------------------------------------------------------------------- + +/// Strip implicit conversions, copy/move constructors, and temporary +/// materializations to find the underlying DeclRefExpr (if any). +static const DeclRefExpr* getUnderlyingDeclRef(const Expr* pExpr) +{ + if (!pExpr) + return nullptr; + pExpr = pExpr->IgnoreImplicit(); + if (auto* pDeclRef = dyn_cast<DeclRefExpr>(pExpr)) + return pDeclRef; + if (auto* pConstruct = dyn_cast<CXXConstructExpr>(pExpr)) + { + if (pConstruct->getNumArgs() == 1) + return getUnderlyingDeclRef(pConstruct->getArg(0)); + } + if (auto* pMaterialize = dyn_cast<MaterializeTemporaryExpr>(pExpr)) + return getUnderlyingDeclRef(pMaterialize->getSubExpr()); + if (auto* pBind = dyn_cast<CXXBindTemporaryExpr>(pExpr)) + return getUnderlyingDeclRef(pBind->getSubExpr()); + return nullptr; +} + +/// Is the VarDecl directly returned from any ReturnStmt in the function body? +/// Only matches when the variable itself is the return value (possibly through +/// implicit conversions), NOT when it is merely referenced inside the return +/// expression (e.g. pVar->GetSomething()). +static bool isReturnedFromStmt(const Stmt* pStmt, const VarDecl* pVarDecl) +{ + if (!pStmt) + return false; + if (auto* pReturn = dyn_cast<ReturnStmt>(pStmt)) + { + auto* pDeclRef = getUnderlyingDeclRef(pReturn->getRetValue()); + if (pDeclRef && pDeclRef->getDecl() == pVarDecl) + return true; + } + for (auto* child : pStmt->children()) + { + if (isReturnedFromStmt(child, pVarDecl)) + return true; + } + return false; +} + +/// Is disposeAndClear() or clear() called on the VarDecl somewhere in the body? +static bool isDisposedInStmt(const Stmt* pStmt, const VarDecl* pVarDecl) +{ + if (!pStmt) + return false; + if (auto* pCallExpr = dyn_cast<CXXMemberCallExpr>(pStmt)) + { + if (auto* pCallee = pCallExpr->getDirectCallee()) + { + auto check = loplugin::DeclCheck(pCallee); + if (check.Function("disposeAndClear") || check.Function("clear")) + { + // Check that the object being called is our VarDecl + if (auto* pMemberExpr = dyn_cast<MemberExpr>(pCallExpr->getCallee())) + { + auto* pBase = pMemberExpr->getBase()->IgnoreImplicit(); + if (auto* pDeclRef = dyn_cast<DeclRefExpr>(pBase)) + { + if (pDeclRef->getDecl() == pVarDecl) + return true; + } + } + } + } + } + for (auto* child : pStmt->children()) + { + if (isDisposedInStmt(child, pVarDecl)) + return true; + } + return false; +} + +/// Does the expression tree contain a call to VclPtr<...>::Create()? +static bool containsVclPtrCreate(const Stmt* pStmt) +{ + if (!pStmt) + return false; + if (auto* pCallExpr = dyn_cast<CallExpr>(pStmt)) + { + if (auto* pCallee = pCallExpr->getDirectCallee()) + { + if (pCallee->getNameAsString() == "Create") + { + if (auto* pMethodDecl = dyn_cast<CXXMethodDecl>(pCallee)) + { + if (loplugin::DeclCheck(pMethodDecl) + .MemberFunction() + .Class("VclPtr") + .GlobalNamespace()) + return true; + } + } + } + } + for (auto* child : pStmt->children()) + { + if (containsVclPtrCreate(child)) + return true; + } + return false; +} + +// --------------------------------------------------------------------------- +// plugin +// --------------------------------------------------------------------------- + +class ScopedVclPtrCheck : public loplugin::FilteringPlugin<ScopedVclPtrCheck> +{ +public: + explicit ScopedVclPtrCheck(loplugin::InstantiationData const& data) + : FilteringPlugin(data) + { + } + + virtual bool preRun() override + { + StringRef fn(handler.getMainFileName()); + if (loplugin::isSamePathname(fn, SRCDIR "/include/vcl/vclptr.hxx")) + return false; + return true; + } + + virtual void run() override + { + if (preRun()) + TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); + } + + bool VisitVarDecl(const VarDecl*); + bool VisitFunctionDecl(const FunctionDecl*); + +private: + bool isVclPtrToVirtualDevice(QualType qType); +}; + +bool ScopedVclPtrCheck::isVclPtrToVirtualDevice(QualType qType) +{ + auto check = loplugin::TypeCheck(qType); + if (!check.Class("VclPtr").GlobalNamespace()) + return false; + + const clang::Type* pType = qType.getTypePtr(); + if (!pType) + return false; + + const CXXRecordDecl* pRecordDecl = pType->getAsCXXRecordDecl(); + if (!pRecordDecl) + return false; + + const auto* pTemplate = dyn_cast<ClassTemplateSpecializationDecl>(pRecordDecl); + if (!pTemplate) + return false; + + if (pTemplate->getTemplateArgs().size() < 1) + return false; + + const TemplateArgument& rArg = pTemplate->getTemplateArgs()[0]; + if (rArg.getKind() != TemplateArgument::ArgKind::Type) + return false; + + return bool(loplugin::TypeCheck(rArg.getAsType()).Class("VirtualDevice").GlobalNamespace()); +} + +bool ScopedVclPtrCheck::VisitVarDecl(const VarDecl* pVarDecl) +{ + if (ignoreLocation(pVarDecl)) + return true; + + if (isa<ParmVarDecl>(pVarDecl)) + return true; + if (isa<FieldDecl>(pVarDecl)) + return true; + if (pVarDecl->hasGlobalStorage()) + return true; + + if (!isVclPtrToVirtualDevice(pVarDecl->getType())) + return true; + + // Only warn when the variable is initialized via VclPtr::Create(). + // Variables initialized from other function calls are typically borrowing + // a shared/cached/member-owned device, not creating a new one. + auto* pInit = pVarDecl->getInit(); + if (!pInit || !containsVclPtrCreate(pInit)) + return true; + + auto* pFuncDecl = dyn_cast<FunctionDecl>(pVarDecl->getDeclContext()); + if (pFuncDecl && pFuncDecl->hasBody()) + { + const Stmt* pBody = pFuncDecl->getBody(); + + // Factory pattern: the local is returned to the caller. + if (isReturnedFromStmt(pBody, pVarDecl)) + return true; + + // Manual lifecycle: disposeAndClear() or clear() is called explicitly. + if (isDisposedInStmt(pBody, pVarDecl)) + return true; + } + + if (suppressWarningAt(pVarDecl->getLocation())) + return true; + + report(DiagnosticsEngine::Warning, + "use ScopedVclPtr<VirtualDevice> instead of VclPtr<VirtualDevice>" + " for local variables to prevent GDI handle leaks" + " [loplugin:scopedvclptr]", + pVarDecl->getLocation()) + << pVarDecl->getSourceRange(); + + return true; +} + +bool ScopedVclPtrCheck::VisitFunctionDecl(const FunctionDecl* pFuncDecl) +{ + if (ignoreLocation(pFuncDecl)) + return true; + + if (!pFuncDecl->isThisDeclarationADefinition()) + return true; + + if (!isVclPtrToVirtualDevice(pFuncDecl->getReturnType())) + return true; + + if (suppressWarningAt(pFuncDecl->getLocation())) + return true; + + report(DiagnosticsEngine::Warning, + "use ScopedVclPtr<VirtualDevice> as return type instead of" + " VclPtr<VirtualDevice> to prevent GDI handle leaks" + " [loplugin:scopedvclptr]", + pFuncDecl->getLocation()) + << pFuncDecl->getSourceRange(); + + return true; +} + +loplugin::Plugin::Registration<ScopedVclPtrCheck> scopedvclptr("scopedvclptr"); + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/compilerplugins/clang/test/scopedvclptr.cxx b/compilerplugins/clang/test/scopedvclptr.cxx new file mode 100644 index 000000000000..1f5a02432110 --- /dev/null +++ b/compilerplugins/clang/test/scopedvclptr.cxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. + */ + +#include <sal/config.h> + +#include <vcl/vclptr.hxx> +#include <vcl/vclreferencebase.hxx> + +// Minimal VirtualDevice stub — the plugin checks for Class("VirtualDevice").GlobalNamespace() +class VirtualDevice : public VclReferenceBase +{ +public: + void dispose() override { VclReferenceBase::dispose(); } + ~VirtualDevice() override { disposeOnce(); } +}; + +// --- Cases that SHOULD warn (local variable) --- + +// Local VclPtr<VirtualDevice> created via ::Create(), not disposed, not returned +void bad_local() +{ + VclPtr<VirtualDevice> + pVDev // expected-error {{use ScopedVclPtr<VirtualDevice> instead of VclPtr<VirtualDevice> for local variables to prevent GDI handle leaks [loplugin:scopedvclptr]}} + = VclPtr<VirtualDevice>::Create(); + (void)pVDev; +} + +// --- Cases that SHOULD warn (return type) --- + +// Function returning VclPtr<VirtualDevice> should return ScopedVclPtr +VclPtr<VirtualDevice> +bad_return_type() // expected-error {{use ScopedVclPtr<VirtualDevice> as return type instead of VclPtr<VirtualDevice> to prevent GDI handle leaks [loplugin:scopedvclptr]}} +{ + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + return pVDev; +} + +// --- Cases that should NOT warn --- + +// ScopedVclPtr local is fine +void good_scoped() +{ + ScopedVclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + (void)pVDev; +} + +// Factory returning ScopedVclPtr: no warnings at all +ScopedVclPtr<VirtualDevice> good_factory_scoped() +{ + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + return pVDev; +} + +// Using VclPtr in return expression is NOT the same as returning it +VirtualDevice* bad_use_in_return() +{ + VclPtr<VirtualDevice> + pVDev // expected-error {{use ScopedVclPtr<VirtualDevice> instead of VclPtr<VirtualDevice> for local variables to prevent GDI handle leaks [loplugin:scopedvclptr]}} + = VclPtr<VirtualDevice>::Create(); + return pVDev.get(); +} + +// Explicit disposeAndClear: developer manages lifecycle manually +void good_explicit_dispose() +{ + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + (void)pVDev; + pVDev.disposeAndClear(); +} + +// Borrowing: initialized from a function call, not VclPtr::Create() +VclPtr<VirtualDevice> GetSharedDevice(); +void good_borrow() +{ + VclPtr<VirtualDevice> pVDev = GetSharedDevice(); + (void)pVDev; +} + +// No initializer: variable declared but not created via ::Create() +void good_no_init() +{ + VclPtr<VirtualDevice> pVDev; + (void)pVDev; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx index 6b6499a8b539..8362e8387122 100644 --- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx +++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx @@ -137,6 +137,7 @@ bool VDevBuffer::isSizeSuitable(const VclPtr<VirtualDevice>& device, const Size& return false; } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel) { std::unique_lock aGuard(m_aMutex); diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx index d0d055627668..b6f3384bd76c 100644 --- a/sc/source/ui/inc/checklistmenu.hxx +++ b/sc/source/ui/inc/checklistmenu.hxx @@ -385,6 +385,7 @@ public: ScViewData& GetViewData() const { return mrParentControl.GetViewData(); } ScCheckListMenuControl::ExtendedData* getExtendedData() { return mrParentControl.getExtendedData(); } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> create_virtual_device() const { return mxMenu->create_virtual_device(); } /** diff --git a/solenv/CompilerTest_compilerplugins_clang.mk b/solenv/CompilerTest_compilerplugins_clang.mk index eb74020d5ca6..0ca6721f288b 100644 --- a/solenv/CompilerTest_compilerplugins_clang.mk +++ b/solenv/CompilerTest_compilerplugins_clang.mk @@ -77,6 +77,7 @@ $(eval $(call gb_CompilerTest_add_exception_objects,compilerplugins_clang, \ compilerplugins/clang/test/salcall \ compilerplugins/clang/test/sallogareas \ compilerplugins/clang/test/salunicodeliteral \ + compilerplugins/clang/test/scopedvclptr \ compilerplugins/clang/test/selfinit \ compilerplugins/clang/test/simplifyconstruct \ compilerplugins/clang/test/simplifydynamiccast \ diff --git a/svx/source/tbxctrls/StylesPreviewWindow.cxx b/svx/source/tbxctrls/StylesPreviewWindow.cxx index a9a786fe4b65..56324cd9aa7f 100644 --- a/svx/source/tbxctrls/StylesPreviewWindow.cxx +++ b/svx/source/tbxctrls/StylesPreviewWindow.cxx @@ -587,7 +587,7 @@ IMPL_LINK(StylesPreviewWindow_Base, GetPreviewImage, const weld::encoded_image_q return true; } -VclPtr<VirtualDevice> +VclPtr<VirtualDevice> // [-loplugin:scopedvclptr] StylesPreviewWindow_Base::GetCachedPreview(const StylePreviewDescriptor& rStyle) { auto aFound = StylePreviewCache::Get().find(rStyle.translatedName); diff --git a/svx/source/tbxctrls/SvxColorIconView.cxx b/svx/source/tbxctrls/SvxColorIconView.cxx index 43018ff9b084..bde726dd6488 100644 --- a/svx/source/tbxctrls/SvxColorIconView.cxx +++ b/svx/source/tbxctrls/SvxColorIconView.cxx @@ -92,6 +92,7 @@ void SvxColorIconView::addEntriesForColorSet(weld::IconView& pIconView, } } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> SvxColorIconView::createColorDevice() { const sal_uInt32 nEdgeLength = getEntryEdgeLength() - 2; diff --git a/svx/source/tbxctrls/fontworkgallery.cxx b/svx/source/tbxctrls/fontworkgallery.cxx index 3b8af2b8c65c..975a87add992 100644 --- a/svx/source/tbxctrls/fontworkgallery.cxx +++ b/svx/source/tbxctrls/fontworkgallery.cxx @@ -103,6 +103,7 @@ void FontWorkGalleryDialog::initFavorites(sal_uInt16 nThemeId) if (GalleryExplorer::GetSdrObj(nThemeId, nModelPos, pModel, &aThumb) && !aThumb.IsEmpty()) { + // [-loplugin:scopedvclptr] VclPtr< VirtualDevice > pVDev = VclPtr<VirtualDevice>::Create(); const Point aNull(0, 0); diff --git a/svx/source/tbxctrls/tbxcolorupdate.cxx b/svx/source/tbxctrls/tbxcolorupdate.cxx index 9c36ee157019..aa5681f4a9d3 100644 --- a/svx/source/tbxctrls/tbxcolorupdate.cxx +++ b/svx/source/tbxctrls/tbxcolorupdate.cxx @@ -193,6 +193,7 @@ namespace svx mpTbx->SetItemImage(mnBtnId, Image(aGraphic.GetXGraphic())); } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> VclToolboxButtonColorUpdater::CreateVirtualDevice() const { return VclPtr<VirtualDevice>::Create(*mpTbx->GetOutDev()); @@ -347,6 +348,7 @@ namespace svx mpTbx->set_item_image(msBtnId, pVirDev); } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> ToolboxButtonColorUpdater::CreateVirtualDevice() const { return mpTbx->create_virtual_device(); diff --git a/svx/source/unodraw/UnoGraphicExporter.cxx b/svx/source/unodraw/UnoGraphicExporter.cxx index 57c176edec47..90285a974d3d 100644 --- a/svx/source/unodraw/UnoGraphicExporter.cxx +++ b/svx/source/unodraw/UnoGraphicExporter.cxx @@ -300,6 +300,7 @@ IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo, void) @return the returned VirtualDevice is owned by the caller */ +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> GraphicExporter::CreatePageVDev( SdrPage* pPage, tools::Long nWidthPixel, tools::Long nHeightPixel ) const { VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); diff --git a/sw/source/core/doc/DocumentDeviceManager.cxx b/sw/source/core/doc/DocumentDeviceManager.cxx index 690a183e1fdc..f55d60042c49 100644 --- a/sw/source/core/doc/DocumentDeviceManager.cxx +++ b/sw/source/core/doc/DocumentDeviceManager.cxx @@ -259,8 +259,10 @@ DocumentDeviceManager::~DocumentDeviceManager() VirtualDevice& DocumentDeviceManager::CreateVirtualDevice_() const { #ifdef IOS + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> pNewVir = VclPtr<VirtualDevice>::Create(DeviceFormat::GRAYSCALE); #else + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> pNewVir = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA); #endif diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index 850c3f85fdcb..5e3e02f4dbdc 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -899,6 +899,7 @@ public: } } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> create_render_virtual_device() const override { auto xRet = VclPtr<VirtualDevice>::Create(); diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 78adf725cc76..0b68dfc142b3 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -683,6 +683,7 @@ OUString SalInstanceWidget::escape_ui_str(const OUString& rLabel) const return rLabel.replaceAll("~", "~~"); } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> SalInstanceWidget::create_virtual_device() const { // create with (annoying) separate alpha layer that LibreOffice itself uses @@ -1703,6 +1704,7 @@ OUString SalInstanceWindow::get_window_state(vcl::WindowDataMask nMask) const SystemEnvData SalInstanceWindow::get_system_data() const { return *m_xWindow->GetSystemData(); } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> SalInstanceWindow::screenshot() { SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(m_xWindow.get()); @@ -7024,6 +7026,7 @@ public: return 0; } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> create_render_virtual_device() const override { return VclPtr<VirtualDevice>::Create(); diff --git a/vcl/source/window/syswin.cxx b/vcl/source/window/syswin.cxx index 4414b135f4a2..d022ae41dc3a 100644 --- a/vcl/source/window/syswin.cxx +++ b/vcl/source/window/syswin.cxx @@ -1120,6 +1120,7 @@ void SystemWindow::ImplDeferredInit(vcl::Window* /*pParent*/, WinBits /*nBits*/) SAL_WARN("vcl.layout", "SystemWindow in layout without doDeferredInit impl"); } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> SystemWindow::createScreenshot() { // same prerequisites as in Execute() diff --git a/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx b/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx index 87758f24d98e..42530e1c818a 100644 --- a/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx +++ b/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx @@ -235,6 +235,7 @@ namespace cairo &cairo_surface_destroy ))); } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> X11Surface::createVirtualDevice() const { SystemGraphicsData aSystemGraphicsData; diff --git a/vcl/unx/gtk3/gtkcairo.cxx b/vcl/unx/gtk3/gtkcairo.cxx index f389f4d087c1..2b2087be610c 100644 --- a/vcl/unx/gtk3/gtkcairo.cxx +++ b/vcl/unx/gtk3/gtkcairo.cxx @@ -113,6 +113,7 @@ namespace cairo mpGraphics->WidgetQueueDraw(); } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> Gtk3Surface::createVirtualDevice() const { SystemGraphicsData aSystemGraphicsData; diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index da42a85659d6..da7f4c6b8bcc 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -4487,6 +4487,7 @@ public: return rLabel.replaceAll("_", "__"); } + // [-loplugin:scopedvclptr] virtual VclPtr<VirtualDevice> create_virtual_device() const override { // create with no separate alpha layer like everything sane does @@ -4553,6 +4554,7 @@ public: gtk_container_resize_children(GTK_CONTAINER(m_pWidget)); #endif + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> xOutput(VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA)); xOutput->SetOutputSizePixel(aSize); @@ -6680,6 +6682,7 @@ public: g_signal_handler_unblock(m_pWidget, m_nToplevelFocusChangedSignalId); } + // [-loplugin:scopedvclptr] virtual VclPtr<VirtualDevice> screenshot() override { // detect if we have to manually setup its size @@ -23158,6 +23161,7 @@ public: return signal_custom_get_size(rOutput); } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> create_render_virtual_device() const override { return create_virtual_device(); @@ -23613,6 +23617,7 @@ public: assert(false && "not implemented"); } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> create_render_virtual_device() const override { return create_virtual_device();
