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/SvxColorIconView.cxx | 1 svx/source/tbxctrls/tbxcolorupdate.cxx | 2 svx/source/unodraw/UnoGraphicExporter.cxx | 1 sw/source/core/doc/DocumentDeviceManager.cxx | 2 vcl/source/app/salvtables.cxx | 2 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 | 4 17 files changed, 395 insertions(+)
New commits: commit 2c518fbc6c4e70bdbaa26c602f498305c9770a4c Author: Andras Timar <[email protected]> AuthorDate: Sat Feb 21 16:17:57 2026 +0100 Commit: Caolán McNamara <[email protected]> CommitDate: Fri Feb 27 15:34:59 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]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200608 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/chart2/source/controller/dialogs/dlg_Theme.cxx b/chart2/source/controller/dialogs/dlg_Theme.cxx index ea81a48b2218..af1985e4697e 100644 --- a/chart2/source/controller/dialogs/dlg_Theme.cxx +++ b/chart2/source/controller/dialogs/dlg_Theme.cxx @@ -78,6 +78,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 bebf679357bc..2d4af14feaa4 100644 --- a/chart2/source/controller/sidebar/ChartThemeControl.cxx +++ b/chart2/source/controller/sidebar/ChartThemeControl.cxx @@ -195,6 +195,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 71600c1e8c71..c8a1148067bf 100644 --- a/chart2/source/controller/sidebar/ChartThemePanel.cxx +++ b/chart2/source/controller/sidebar/ChartThemePanel.cxx @@ -95,6 +95,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 3546bb2a9308..6914c97d2af3 100644 --- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx +++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx @@ -139,6 +139,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 ad8eed0a6878..03dc2cf498a0 100644 --- a/sc/source/ui/inc/checklistmenu.hxx +++ b/sc/source/ui/inc/checklistmenu.hxx @@ -382,6 +382,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 9a1dacbc5789..8f4616b454f5 100644 --- a/solenv/CompilerTest_compilerplugins_clang.mk +++ b/solenv/CompilerTest_compilerplugins_clang.mk @@ -79,6 +79,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/SvxColorIconView.cxx b/svx/source/tbxctrls/SvxColorIconView.cxx index 96e102a14fd9..c26d24b08432 100644 --- a/svx/source/tbxctrls/SvxColorIconView.cxx +++ b/svx/source/tbxctrls/SvxColorIconView.cxx @@ -96,6 +96,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/tbxcolorupdate.cxx b/svx/source/tbxctrls/tbxcolorupdate.cxx index 14879214a8e2..44dfca847e6f 100644 --- a/svx/source/tbxctrls/tbxcolorupdate.cxx +++ b/svx/source/tbxctrls/tbxcolorupdate.cxx @@ -193,6 +193,7 @@ void VclToolboxButtonColorUpdater::SetImage(VirtualDevice* pVirDev) mpTbx->SetItemImage(mnBtnId, Image(aGraphic.GetXGraphic())); } +// [-loplugin:scopedvclptr] VclPtr<VirtualDevice> VclToolboxButtonColorUpdater::CreateVirtualDevice() const { auto xVD = VclPtr<VirtualDevice>::Create(*mpTbx->GetOutDev()); @@ -350,6 +351,7 @@ void ToolboxButtonColorUpdater::SetImage(VirtualDevice* pVirDev) 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 799fe3af9bb3..398ced591d60 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 1d49f23e7182..d5cd71a38391 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/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 26b3771eef00..0f76bc2173f7 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -665,6 +665,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 @@ -1678,6 +1679,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()); diff --git a/vcl/source/window/syswin.cxx b/vcl/source/window/syswin.cxx index 0334935e89cb..fc5616c3f8b6 100644 --- a/vcl/source/window/syswin.cxx +++ b/vcl/source/window/syswin.cxx @@ -1137,6 +1137,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 95e3bf834bed..300ab96536e1 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -4296,6 +4296,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 @@ -4362,6 +4363,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); @@ -6571,6 +6573,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 @@ -6598,6 +6601,7 @@ public: #endif } + // [-loplugin:scopedvclptr] VclPtr<VirtualDevice> xOutput(VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA)); xOutput->SetOutputSizePixel(get_size()); cairo_surface_t* pSurface = get_underlying_cairo_surface(*xOutput);
