bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / useuniqueptr.cxx
blobcdf7b07e475191387674b8a4344f56ef35e3cfb9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <memory>
11 #include <cassert>
12 #include <string>
13 #include <iostream>
14 #include <fstream>
15 #include <set>
16 #include "plugin.hxx"
17 #include "check.hxx"
19 /**
20 Find destructors that only contain a single call to delete of a field. In which
21 case that field should really be managed by unique_ptr.
24 namespace {
26 class UseUniquePtr:
27 public loplugin::FilteringPlugin<UseUniquePtr>
29 public:
30 explicit UseUniquePtr(loplugin::InstantiationData const & data):
31 FilteringPlugin(data) {}
33 virtual void run() override
35 fn = handler.getMainFileName();
36 loplugin::normalizeDotDotInFilePath(fn);
37 // can't change these because we pass them down to the SfxItemPool stuff
38 if (fn == SRCDIR "/sc/source/core/data/docpool.cxx")
39 return;
40 // this just too clever for me
41 if (fn == SRCDIR "/sc/source/core/tool/chgtrack.cxx")
42 return;
43 // too clever
44 if (fn == SRCDIR "/pyuno/source/module/pyuno_runtime.cxx")
45 return;
46 // m_pExampleSet here is very badly managed. sometimes it is owning, sometimes not,
47 // and the logic depends on overriding methods.
48 if (fn == SRCDIR "/sfx2/source/dialog/tabdlg.cxx")
49 return;
50 // pLongArr is being deleted here because we temporarily overwrite a pointer to someone else's buffer, with a pointer
51 // to our own buffer
52 if (fn == SRCDIR "/editeng/source/misc/txtrange.cxx")
53 return;
54 // can't use std::set<std::unique_ptr<>> until C++14
55 if (fn == SRCDIR "/editeng/source/misc/svxacorr.cxx")
56 return;
57 // horrible horrible spawn of evil ownership and deletion here
58 if (fn == SRCDIR "/sfx2/source/view/ipclient.cxx")
59 return;
60 // sometimes it owns, sometimes it doesn't
61 if (fn == SRCDIR "/editeng/source/misc/svxacorr.cxx")
62 return;
63 // SwDoc::m_PageDescs has weird handling
64 if (fn == SRCDIR "/sw/source/core/doc/docnew.cxx")
65 return;
66 // SwRedlineData::pNext and pExtraData have complex handling
67 if (fn == SRCDIR "/sw/source/core/doc/docredln.cxx")
68 return;
69 // ScTempDocSource::pTempDoc
70 if (fn == SRCDIR "/sc/source/ui/unoobj/funcuno.cxx")
71 return;
72 // SwAttrIter::m_pFont
73 if (fn == SRCDIR "/sw/source/core/text/itratr.cxx"
74 || fn == SRCDIR "/sw/source/core/text/redlnitr.cxx")
75 return;
76 // SwWrongList
77 if (fn == SRCDIR "/sw/source/core/text/wrong.cxx")
78 return;
79 // SwLineLayout::m_pNext
80 if (fn == SRCDIR "/sw/source/core/text/porlay.cxx")
81 return;
82 // ODatabaseExport::m_aDestColumns
83 if (fn == SRCDIR "/dbaccess/source/ui/misc/DExport.cxx")
84 return;
85 // ScTabView::pDrawActual and pDrawOld
86 if (fn == SRCDIR "/sc/source/ui/view/tabview5.cxx")
87 return;
88 // SwHTMLParser::m_pPendStack
89 if (fn == SRCDIR "/sw/source/filter/html/htmlcss1.cxx")
90 return;
91 // Visual Studio 2017 has trouble with these
92 if (fn == SRCDIR "/comphelper/source/property/MasterPropertySet.cxx"
93 || fn == SRCDIR "/comphelper/source/property/MasterPropertySetInfo.cxx")
94 return;
95 // SwTableLine::m_aBoxes
96 if (fn == SRCDIR "/sw/source/core/table/swtable.cxx")
97 return;
98 // SwHTMLParser::m_pFormImpl
99 if (fn == SRCDIR "/sw/source/filter/html/htmlform.cxx")
100 return;
101 // SwHTMLParser::m_pPendStack, pNext
102 if (fn == SRCDIR "/sw/source/filter/html/htmltab.cxx")
103 return;
104 // SaveLine::pBox, pNext
105 if (fn == SRCDIR "/sw/source/core/undo/untbl.cxx")
106 return;
107 // RedlineInfo::pNextRedline
108 if (fn == SRCDIR "/sw/source/filter/xml/XMLRedlineImportHelper.cxx")
109 return;
110 // SfxObjectShell::pMedium
111 if (fn == SRCDIR "/sfx2/source/doc/objxtor.cxx")
112 return;
113 // various
114 if (fn == SRCDIR "/sw/source/filter/ww8/wrtww8.cxx")
115 return;
116 // WW8TabBandDesc
117 if (fn == SRCDIR "/sw/source/filter/ww8/ww8par2.cxx")
118 return;
119 // ZipOutputStream, ownership of ZipEntry is horribly complicated here
120 if (fn == SRCDIR "/package/source/zipapi/ZipOutputStream.cxx")
121 return;
122 // custom deleter
123 if (fn == SRCDIR "/sal/rtl/locale.cxx")
124 return;
125 // std::vector<ScLookupCacheMap*> is tricky, changing it would require moving lots of class definitions around
126 if (fn == SRCDIR "/sc/source/core/data/documen2.cxx"
127 || fn == SRCDIR "/sc/source/core/tool/interpretercontext.cxx")
128 return;
130 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
133 bool VisitFunctionDecl(const FunctionDecl* );
134 bool VisitCXXDeleteExpr(const CXXDeleteExpr* );
135 bool TraverseFunctionDecl(FunctionDecl* );
136 bool TraverseCXXDeductionGuideDecl(CXXDeductionGuideDecl* );
137 bool TraverseCXXMethodDecl(CXXMethodDecl* );
138 bool TraverseCXXConstructorDecl(CXXConstructorDecl* );
139 bool TraverseCXXConversionDecl(CXXConversionDecl* );
140 bool TraverseCXXDestructorDecl(CXXDestructorDecl* );
141 bool TraverseConstructorInitializer(CXXCtorInitializer*);
143 private:
144 void CheckCompoundStmt(const FunctionDecl*, const CompoundStmt* );
145 void CheckIfStmt(const FunctionDecl*, const IfStmt* );
146 void CheckCXXForRangeStmt(const FunctionDecl*, const CXXForRangeStmt* );
147 void CheckLoopDelete(const FunctionDecl*, const Stmt* );
148 void CheckLoopDelete(const FunctionDecl*, const CXXDeleteExpr* );
149 void CheckDeleteExpr(const FunctionDecl*, const CXXDeleteExpr*);
150 void CheckDeleteLocalVar(const FunctionDecl*, const CXXDeleteExpr*, const VarDecl*);
151 void CheckDeleteParmVar(const CXXDeleteExpr*, const ParmVarDecl*);
152 void CheckParenExpr(const FunctionDecl*, const ParenExpr*);
153 void CheckMemberDeleteExpr(const FunctionDecl*, const CXXDeleteExpr*,
154 const MemberExpr*, StringRef message);
155 FunctionDecl const * mpCurrentFunctionDecl = nullptr;
156 std::string fn;
159 bool UseUniquePtr::VisitFunctionDecl(const FunctionDecl* functionDecl)
161 if (ignoreLocation(functionDecl))
162 return true;
163 if (isInUnoIncludeFile(functionDecl))
164 return true;
166 const CompoundStmt* compoundStmt = dyn_cast_or_null< CompoundStmt >( functionDecl->getBody() );
167 if (!compoundStmt || compoundStmt->size() == 0)
168 return true;
170 CheckCompoundStmt(functionDecl, compoundStmt);
172 return true;
176 * check for simple call to delete i.e. direct unconditional call, or if-guarded call
178 void UseUniquePtr::CheckCompoundStmt(const FunctionDecl* functionDecl, const CompoundStmt* compoundStmt)
180 for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
182 if (auto cxxForRangeStmt = dyn_cast<CXXForRangeStmt>(*i))
183 CheckCXXForRangeStmt(functionDecl, cxxForRangeStmt);
184 else if (auto forStmt = dyn_cast<ForStmt>(*i))
185 CheckLoopDelete(functionDecl, forStmt->getBody());
186 else if (auto whileStmt = dyn_cast<WhileStmt>(*i))
187 CheckLoopDelete(functionDecl, whileStmt->getBody());
188 // check for unconditional inner compound statements
189 else if (auto innerCompoundStmt = dyn_cast<CompoundStmt>(*i))
190 CheckCompoundStmt(functionDecl, innerCompoundStmt);
191 else if (auto deleteExpr = dyn_cast<CXXDeleteExpr>(*i))
192 CheckDeleteExpr(functionDecl, deleteExpr);
193 else if (auto parenExpr = dyn_cast<ParenExpr>(*i))
194 CheckParenExpr(functionDecl, parenExpr);
195 else if (auto ifStmt = dyn_cast<IfStmt>(*i))
196 CheckIfStmt(functionDecl, ifStmt);
200 // Check for conditional deletes like:
201 // if (m_pField != nullptr) delete m_pField;
202 void UseUniquePtr::CheckIfStmt(const FunctionDecl* functionDecl, const IfStmt* ifStmt)
204 auto cond = ifStmt->getCond()->IgnoreImplicit();
205 if (auto ifCondMemberExpr = dyn_cast<MemberExpr>(cond))
207 // ignore "if (bMine)"
208 if (!loplugin::TypeCheck(ifCondMemberExpr->getType()).Pointer())
209 return;
210 // good
212 else if (auto binaryOp = dyn_cast<BinaryOperator>(cond))
214 if (!isa<MemberExpr>(binaryOp->getLHS()->IgnoreImplicit()))
215 return;
216 if (!isa<CXXNullPtrLiteralExpr>(binaryOp->getRHS()->IgnoreImplicit()))
217 return;
218 // good
220 else // ignore anything more complicated
221 return;
223 auto deleteExpr = dyn_cast<CXXDeleteExpr>(ifStmt->getThen());
224 if (deleteExpr)
226 CheckDeleteExpr(functionDecl, deleteExpr);
227 return;
230 auto parenExpr = dyn_cast<ParenExpr>(ifStmt->getThen());
231 if (parenExpr)
233 CheckParenExpr(functionDecl, parenExpr);
234 return;
237 auto ifThenCompoundStmt = dyn_cast<CompoundStmt>(ifStmt->getThen());
238 if (!ifThenCompoundStmt)
239 return;
240 for (auto j = ifThenCompoundStmt->body_begin(); j != ifThenCompoundStmt->body_end(); ++j)
242 auto ifDeleteExpr = dyn_cast<CXXDeleteExpr>(*j);
243 if (ifDeleteExpr)
244 CheckDeleteExpr(functionDecl, ifDeleteExpr);
245 ParenExpr const * parenExpr = dyn_cast<ParenExpr>(*j);
246 if (parenExpr)
247 CheckParenExpr(functionDecl, parenExpr);
251 void UseUniquePtr::CheckDeleteExpr(const FunctionDecl* functionDecl, const CXXDeleteExpr* deleteExpr)
253 auto deleteExprArg = deleteExpr->getArgument()->IgnoreParens()->IgnoreImplicit();
256 if (const MemberExpr* memberExpr = dyn_cast<MemberExpr>(deleteExprArg))
258 // ignore delete static_cast<T>(p)->other;
259 if (!isa<CXXThisExpr>(memberExpr->getBase()->IgnoreCasts()))
260 return;
261 // don't always own this
262 if (fn == SRCDIR "/editeng/source/editeng/impedit2.cxx")
263 return;
264 // this member needs to get passed via an extern "C" API
265 if (fn == SRCDIR "/sd/source/filter/sdpptwrp.cxx")
266 return;
267 // ownership complicated between this and the group
268 if (fn == SRCDIR "/sc/source/core/data/formulacell.cxx")
269 return;
270 // linked list
271 if (fn == SRCDIR "/sw/source/filter/html/parcss1.cxx")
272 return;
273 // linked list
274 if (fn == SRCDIR "/sw/source/filter/writer/writer.cxx")
275 return;
276 // complicated
277 if (fn == SRCDIR "/sc/source/filter/html/htmlpars.cxx")
278 return;
279 // complicated pimpl stuff in SalLayoutGlyphs
280 if (fn == SRCDIR "/vcl/source/gdi/impglyphitem.cxx")
281 return;
283 CheckMemberDeleteExpr(functionDecl, deleteExpr, memberExpr,
284 "unconditional call to delete on a member, should be using std::unique_ptr");
285 return;
288 const ArraySubscriptExpr* arrayExpr = dyn_cast<ArraySubscriptExpr>(deleteExprArg);
289 if (arrayExpr)
291 auto baseMemberExpr = dyn_cast<MemberExpr>(arrayExpr->getBase()->IgnoreParens()->IgnoreImplicit());
292 if (baseMemberExpr)
293 CheckMemberDeleteExpr(functionDecl, deleteExpr, baseMemberExpr,
294 "unconditional call to delete on an array member, should be using std::unique_ptr");
298 template<typename T>
299 bool any_equal(std::string const & needle, T first) {
300 return needle == first;
303 template<typename T, typename... Args>
304 bool any_equal(std::string const & needle, T first, Args... args) {
305 return needle == first || any_equal(needle, args...);
308 void UseUniquePtr::CheckDeleteLocalVar(const FunctionDecl* functionDecl, const CXXDeleteExpr* deleteExpr, const VarDecl* varDecl)
310 // ignore globals for now
311 if (varDecl->hasGlobalStorage())
312 return;
314 // Ignore times when we are casting from void* to init the var, normally indicates
315 // some complex memory management.
316 if (varDecl->getInit())
318 if (auto explicitCast = dyn_cast<ExplicitCastExpr>(varDecl->getInit()))
320 if (loplugin::TypeCheck(explicitCast->getSubExpr()->getType()).Pointer().Void())
321 return;
325 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sal/qa/"))
326 return;
327 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/comphelper/qa/"))
328 return;
329 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/cppuhelper/qa/"))
330 return;
331 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/libreofficekit/qa/"))
332 return;
333 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/vcl/qa/"))
334 return;
335 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sc/qa/"))
336 return;
337 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sfx2/qa/"))
338 return;
339 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/smoketest/"))
340 return;
341 if (loplugin::hasPathnamePrefix(fn, WORKDIR))
342 return;
343 // linked lists
344 if (fn == SRCDIR "/vcl/source/gdi/regband.cxx")
345 return;
346 // this thing relies on explicit delete
347 if (loplugin::TypeCheck(varDecl->getType()).Pointer().Class("VersionCompat").GlobalNamespace())
348 return;
349 if (loplugin::TypeCheck(varDecl->getType()).Pointer().Class("IMapCompat").GlobalNamespace())
350 return;
351 // passing data to gtk API and I can't figure out the types
352 if (fn == SRCDIR "/vcl/unx/gtk3/gtk3gtkdata.cxx"
353 || fn == SRCDIR "/vcl/unx/gtk/gtkdata.cxx")
354 return;
355 // sometimes this stuff is held by tools::SvRef, sometimes by std::unique_ptr .....
356 if (fn == SRCDIR "/sot/source/unoolestorage/xolesimplestorage.cxx")
357 return;
358 // don't feel like messing with this chunk of sfx2
359 if (fn == SRCDIR "/sfx2/source/appl/appinit.cxx")
360 return;
361 if (fn == SRCDIR "/svx/source/svdraw/svdobj.cxx")
362 return;
363 if (fn == SRCDIR "/svx/source/svdraw/svdmodel.cxx")
364 return;
365 // linked list
366 if (fn == SRCDIR "/basic/source/comp/parser.cxx")
367 return;
368 if (fn == SRCDIR "/basic/source/runtime/runtime.cxx")
369 return;
370 // just horrible
371 if (fn == SRCDIR "/svx/source/form/filtnav.cxx")
372 return;
373 // using clucene macros
374 if (fn == SRCDIR "/helpcompiler/source/HelpSearch.cxx")
375 return;
376 // linked list
377 if (fn == SRCDIR "/filter/source/graphicfilter/ios2met/ios2met.cxx")
378 return;
379 // no idea what this is trying to do
380 if (fn == SRCDIR "/cui/source/customize/SvxMenuConfigPage.cxx")
381 return;
382 // I cannot follow the ownership of OSQLParseNode's
383 if (fn == SRCDIR "/dbaccess/source/core/api/SingleSelectQueryComposer.cxx")
384 return;
385 if (fn == SRCDIR "/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx")
386 return;
387 // linked list
388 if (fn == SRCDIR "/formula/source/core/api/FormulaCompiler.cxx")
389 return;
390 // smuggling data around via SvxFontListItem
391 if (fn == SRCDIR "/extensions/source/propctrlr/fontdialog.cxx")
392 return;
393 // atomics
394 if (fn == SRCDIR "/sc/source/ui/docshell/documentlinkmgr.cxx")
395 return;
396 // finicky
397 if (fn == SRCDIR "/sc/source/core/data/stlpool.cxx")
398 return;
399 // macros
400 if (fn == SRCDIR "/sc/source/core/tool/autoform.cxx")
401 return;
402 // unsure about ownership
403 if (fn == SRCDIR "/xmlsecurity/source/framework/saxeventkeeperimpl.cxx")
404 return;
405 // ScTokenArray ownership complicated between this and the group
406 if (fn == SRCDIR "/sc/source/core/data/formulacell.cxx")
407 return;
408 // macros
409 if (fn == SRCDIR "/sw/source/core/doc/tblafmt.cxx")
410 return;
411 // more ScTokenArray
412 if (fn == SRCDIR "/sc/source/ui/unoobj/tokenuno.cxx")
413 return;
414 // SwDoc::DelTextFormatColl
415 if (fn == SRCDIR "/sw/source/core/doc/docfmt.cxx")
416 return;
417 // SwRootFrame::CalcFrameRects
418 if (fn == SRCDIR "/sw/source/core/layout/trvlfrm.cxx")
419 return;
420 // crazy code
421 if (fn == SRCDIR "/sw/source/core/undo/SwUndoPageDesc.cxx")
422 return;
423 // unsure about the SwLinePortion ownership
424 if (fn == SRCDIR "/sw/source/core/text/itrform2.cxx")
425 return;
426 // can't follow the ownership
427 if (fn == SRCDIR "/sw/source/filter/html/htmlatr.cxx")
428 return;
429 // SwTextFormatter::BuildMultiPortion complicated
430 if (fn == SRCDIR "/sw/source/core/text/pormulti.cxx")
431 return;
432 // SwXMLExport::ExportTableLines
433 if (fn == SRCDIR "/sw/source/filter/xml/xmltble.cxx")
434 return;
435 // SwPagePreview::~SwPagePreview
436 if (fn == SRCDIR "/sw/source/uibase/uiview/pview.cxx")
437 return;
438 // alloc/free routines for the hand constructed virtual function table
439 if (fn == SRCDIR "/sal/textenc/convertisciidevangari.cxx")
440 return;
441 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/bridges/"))
442 return;
443 // bootstrap_map
444 if (fn == SRCDIR "/sal/rtl/bootstrap.cxx")
445 return;
446 // too complicated for my small brain
447 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/cppu/"))
448 return;
449 // linked list
450 if (fn == SRCDIR "/vcl/source/gdi/octree.cxx")
451 return;
452 // linked list
453 if (fn == SRCDIR "/vcl/source/filter/graphicfilter.cxx")
454 return;
455 // linked list
456 if (fn == SRCDIR "/svtools/source/control/ctrltool.cxx")
457 return;
458 // complicated
459 if (fn == SRCDIR "/sfx2/source/control/msgpool.cxx")
460 return;
461 // complicated
462 if (fn == SRCDIR "/svx/source/sdr/contact/objectcontact.cxx")
463 return;
464 // memory management in this module is a mess
465 if (fn == SRCDIR "/idlc/source/aststack.cxx")
466 return;
467 // complicated
468 if (fn == SRCDIR "/cui/source/customize/cfg.cxx")
469 return;
470 // linked list
471 if (fn == SRCDIR "/lotuswordpro/source/filter/lwpfribptr.cxx")
472 return;
473 // complicated
474 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/connectivity/source/drivers/file/"))
475 return;
476 // complicated
477 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/unodevtools/source/skeletonmaker/"))
478 return;
480 llvm::StringRef parentName;
481 if (auto cxxMethodDecl = dyn_cast<CXXMethodDecl>(functionDecl))
483 parentName = cxxMethodDecl->getParent()->getName();
486 // no idea what is going on here
487 if (parentName == "ScChangeActionLinkEntry")
488 return;
489 // ok
490 if (parentName == "SfxItemSet" || parentName == "SfxItemPool")
491 return;
492 // linked list
493 if (parentName == "ScFunctionList" || parentName == "SwNodes"
494 || parentName == "SwUnoCursor" || parentName == "SortedResultSet"
495 || parentName == "Atom" || parentName == "RegionBand" || parentName == "WMFWriter"
496 || parentName == "Scheduler" || parentName == "OpenGLContext"
497 || parentName == "WizardDialog")
498 return;
499 // manual ref counting
500 if (parentName == "ScBroadcastAreaSlot")
501 return;
502 // complicated
503 if (any_equal(parentName, "SwFormatField", "FontPropertyBox", "SdFontPropertyBox",
504 "SwHTMLParser", "PDFWriterImpl", "SbiParser", "DictionaryList", "SwGlossaryHdl", "SwGlossaryGroupDlg"))
505 return;
506 // ok
507 if (any_equal(parentName, "SbTreeListBox"))
508 return;
510 if (functionDecl->getIdentifier())
512 std::string name = functionDecl->getName();
513 if (!parentName.empty())
514 name = std::string(parentName) + "::" + name;
516 // custom deleters
517 if (name == "Proxy_free" || name == "s_free" || name == "binuno_proxy_free")
518 return;
519 if (name == "SvpSalFrame::ReleaseGraphics")
520 return;
521 // don't feel like changing the API functions in registry
522 if (name == "createRegistry" || name == "openRegistry" || name == "closeRegistry" || name == "destroyRegistry"
523 || name == "reg_openRegistry")
524 return;
525 // linked list
526 if (any_equal(name, "TypeWriter::createBlop", "ImplDeleteConfigData", "Config::DeleteGroup",
527 "Config::DeleteKey", "E3dView::DoDepthArrange",
528 "DXFBlocks::Clear", "DXFTables::Clear", "DXFEntities::Clear",
529 "PSWriter::WritePS", "PSWriter::ImplWriteActions", "CUtList::Destroy",
530 "ScBroadcastAreaSlotMachine::UpdateBroadcastAreas"))
531 return;
532 // ok
533 if (any_equal(name, "write_uInt16s_FromOUString", "ProgressMonitor::removeText",
534 "StgDirEntry::SetSize", "UCBStorage::CopyStorageElement_Impl"
535 "OutputDevice::ImplDrawPolyPolygon", "OutputDevice::ImplDrawPolyPolygon",
536 "ImplListBox::InsertEntry", "Edit::dispose",
537 "ViewContact::deleteAllVOCs", "SfxViewFrame::ReleaseObjectShell_Impl",
538 "SfxViewFrame::SwitchToViewShell_Impl", "OfaSmartTagOptionsTabPage::ClearListBox",
539 "OfaSmartTagOptionsTabPage::FillItemSet", "doc_destroy", "lo_destroy",
540 "callColumnFormatDialog"))
541 return;
542 // very dodgy
543 if (any_equal(name, "UCBStorage::OpenStorage_Impl", "SdTransferable::GetData"))
544 return;
545 // complicated ownership
546 if (any_equal(name, "ParseCMAP", "OpenGLSalBitmap::CreateTexture", "X11SalGraphicsImpl::drawAlphaBitmap"
547 "SvEmbedTransferHelper::GetData", "ORoadmap::dispose",
548 "BrowseBox::SetMode", "ExportDialog::GetFilterData", "disposeComVariablesForBasic",
549 "ImpEditEngine::ImpRemoveParagraph", "FactoryImpl::createAdapter",
550 "SfxStateCache::SetVisibleState", "SfxBindings::QueryState",
551 "ViewContact::deleteAllVOCs", "SvxMSDffManager::ProcessObj", "SvEmbedTransferHelper::GetData",
552 "SvXMLExportPropertyMapper::Filter_", "SdXMLExport::ImpGetOrCreatePageMasterInfo",
553 "SfxDocumentDescPage::FillItemSet", "SfxCustomPropertiesPage::FillItemSet",
554 "SfxCmisPropertiesPage::FillItemSet", "SfxObjectShell::DoSaveCompleted",
555 "SfxObjectShell::DoSave_Impl", "SfxObjectShell::PreDoSaveAs_Impl", "SfxObjectShell::Save_Impl",
556 "SfxFrame::DoClose_Impl", "SfxBaseModel::load",
557 "SdrTextObj::TakeTextRect", "SdrTableObj::TakeTextRect", "SdrObjCustomShape::TakeTextRect",
558 "CellProperties::ItemSetChanged", "CellProperties::ItemChange",
559 "TableLayouter::SetBorder", "TableLayouter::ClearBorderLayout",
560 "ImpXPolygon::Resize", "SvxTextEditSourceImpl::GetBackgroundTextForwarder",
561 "Svx3DSceneObject::setPropertyValueImpl", "lcl_RemoveTextEditOutlinerViews",
562 "SdrObjEditView::SdrEndTextEdit", "SvxShape::_setPropertyValue",
563 "AccessibleShape::Init", "AccessibleCell::Init",
564 "SdrTableRtfExporter::WriteCell", "GalleryItem::_getPropertyValues",
565 "VMLExport::StartShape", "DrawingML::WriteText",
566 "MtfTools::DrawText", "FormulaTokenArray::RewriteMissing",
567 "OSQLParseNode::negateSearchCondition", "OSQLParseNodesContainer::clearAndDelete",
568 "SdFilter::GetLibrarySymbol", "SdPage::SetObjText",
569 "SdDrawDocument::InsertBookmarkAsPage", "SdDrawDocument::InsertBookmarkAsObject",
570 "SdDrawDocument::RemoveUnnecessaryMasterPages",
571 "ScTable::CopyConditionalFormat", "ScTable::ValidQuery",
572 "ScTable::SetOptimalHeight", "ScTable::SetOptimalHeightOnly", "ScCompiler::CompileString",
573 "ScProgress::DeleteInterpretProgress", "ScInterpreter::ScBase",
574 "UCBStorage::CopyStorageElement_Impl", "X11SalGraphicsImpl::drawAlphaBitmap",
575 "MasterPagesSelector::ClearPageSet", "View::IsPresObjSelected",
576 "SdDrawPagesAccess::remove", "SdMasterPagesAccess::remove", "View::InsertData",
577 "RemoteServer::execute", "Implementation::ReleaseOutlinerView",
578 "SwFormat::CopyAttrs", "FinitCore", "SwCursorShell::MoveFieldType", "SwExtraPainter::PaintExtra",
579 "SwMarginPortion::AdjustRight", "SwPaintQueue::Repaint", "SwTOXMgr::UpdateOrInsertTOX",
580 "SwBaseShell::Execute", "WW8Export::WriteSdrTextObj"))
581 return;
582 // complicated delete
583 if (name == "X11SalObject::CreateObject")
584 return;
587 report(
588 DiagnosticsEngine::Warning,
589 "call to delete on a var, should be using std::unique_ptr",
590 compat::getBeginLoc(deleteExpr))
591 << deleteExpr->getSourceRange();
592 report(
593 DiagnosticsEngine::Note,
594 "var is here",
595 compat::getBeginLoc(varDecl))
596 << varDecl->getSourceRange();
600 * Look for DELETEZ expressions.
602 void UseUniquePtr::CheckParenExpr(const FunctionDecl* functionDecl, const ParenExpr* parenExpr)
604 auto binaryOp = dyn_cast<BinaryOperator>(parenExpr->getSubExpr());
605 if (!binaryOp || binaryOp->getOpcode() != BO_Comma)
606 return;
607 auto deleteExpr = dyn_cast<CXXDeleteExpr>(binaryOp->getLHS());
608 if (!deleteExpr)
609 return;
610 CheckDeleteExpr(functionDecl, deleteExpr);
613 void UseUniquePtr::CheckLoopDelete(const FunctionDecl* functionDecl, const Stmt* bodyStmt)
615 if (auto deleteExpr = dyn_cast<CXXDeleteExpr>(bodyStmt))
616 CheckLoopDelete(functionDecl, deleteExpr);
617 else if (auto compoundStmt = dyn_cast<CompoundStmt>(bodyStmt))
619 for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
621 if (auto deleteExpr = dyn_cast<CXXDeleteExpr>(*i))
622 CheckLoopDelete(functionDecl, deleteExpr);
627 void UseUniquePtr::CheckLoopDelete(const FunctionDecl* functionDecl, const CXXDeleteExpr* deleteExpr)
629 const MemberExpr* memberExpr = nullptr;
630 const VarDecl* varDecl = nullptr;
631 const Expr* subExpr = deleteExpr->getArgument();
632 // drill down looking for a MemberExpr
633 for (;;)
635 subExpr = subExpr->IgnoreParens()->IgnoreImplicit();
636 if ((memberExpr = dyn_cast<MemberExpr>(subExpr)))
638 if (memberExpr->getMemberDecl()->getName() == "first" || memberExpr->getMemberDecl()->getName() == "second")
640 subExpr = memberExpr->getBase();
641 memberExpr = nullptr;
643 else
644 break;
646 else if (auto declRefExpr = dyn_cast<DeclRefExpr>(subExpr))
648 if ((varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl())))
649 break;
651 else if (auto arraySubscriptExpr = dyn_cast<ArraySubscriptExpr>(subExpr))
652 subExpr = arraySubscriptExpr->getBase();
653 else if (auto cxxOperatorCallExpr = dyn_cast<CXXOperatorCallExpr>(subExpr))
655 // look for deletes of an iterator object where the iterator is over a member field
656 if (auto declRefExpr = dyn_cast<DeclRefExpr>(cxxOperatorCallExpr->getArg(0)->IgnoreImplicit()))
658 if (auto iterVarDecl = dyn_cast<VarDecl>(declRefExpr->getDecl()))
660 auto init = iterVarDecl->getInit();
661 if (init)
663 init = compat::IgnoreImplicit(init);
664 if (!compat::CPlusPlus17(compiler.getLangOpts()))
665 if (auto x = dyn_cast<CXXConstructExpr>(init))
666 if (x->isElidable())
667 init = compat::IgnoreImplicit(x->getArg(0));
668 if (auto x = dyn_cast<CXXConstructExpr>(init))
669 if (x->getNumArgs() == 1
670 || (x->getNumArgs() >= 2 && isa<CXXDefaultArgExpr>(x->getArg(1))))
672 init = compat::IgnoreImplicit(x->getArg(0));
674 if (auto x = dyn_cast<CXXMemberCallExpr>(init))
675 init = x->getImplicitObjectArgument()->IgnoreParenImpCasts();
676 if ((memberExpr = dyn_cast<MemberExpr>(init)))
677 break;
678 // look for deletes of an iterator object where the iterator is over a var
679 if (auto declRefExpr2 = dyn_cast<DeclRefExpr>(init))
681 if ((varDecl = dyn_cast<VarDecl>(declRefExpr2->getDecl())))
682 break;
687 // look for deletes like "delete m_pField[0]"
688 if (cxxOperatorCallExpr->getOperator() == OO_Subscript)
690 subExpr = cxxOperatorCallExpr->getArg(0)->IgnoreImplicit();
691 if ((memberExpr = dyn_cast<MemberExpr>(subExpr)))
692 break;
693 if (auto declRefExpr = dyn_cast<DeclRefExpr>(subExpr))
695 if ((varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl())))
696 break;
699 break;
701 else
702 break;
705 if (memberExpr)
707 // OStorage_Impl::Commit very complicated ownership passing going on
708 if (fn == SRCDIR "/package/source/xstor/xstorage.cxx")
709 return;
710 // complicated
711 if (fn == SRCDIR "/vcl/source/gdi/print.cxx")
712 return;
713 // linked list
714 if (fn == SRCDIR "/basic/source/runtime/runtime.cxx")
715 return;
716 // complicated
717 if (fn == SRCDIR "/sw/source/core/bastyp/swcache.cxx")
718 return;
720 CheckMemberDeleteExpr(functionDecl, deleteExpr, memberExpr, "rather manage this member with std::some_container<std::unique_ptr<T>>");
723 if (varDecl)
725 // ignore if the value for the var comes from somewhere else
726 if (varDecl->hasInit() && isa<ExplicitCastExpr>(varDecl->getInit()->IgnoreImpCasts()))
727 return;
729 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/vcl/qa/"))
730 return;
731 // linked list
732 if (fn == SRCDIR "/registry/source/reflwrit.cxx")
733 return;
734 // linked list
735 if (fn == SRCDIR "/tools/source/generic/config.cxx")
736 return;
737 // linked lists
738 if (fn == SRCDIR "/vcl/source/gdi/regband.cxx")
739 return;
740 // linked lists
741 if (fn == SRCDIR "/vcl/source/gdi/regionband.cxx")
742 return;
743 // linked list
744 if (fn == SRCDIR "/vcl/source/gdi/octree.cxx")
745 return;
746 // linked list
747 if (fn == SRCDIR "/vcl/source/app/scheduler.cxx")
748 return;
749 // linked list
750 if (fn == SRCDIR "/vcl/source/filter/wmf/wmfwr.cxx")
751 return;
752 // linked list
753 if (fn == SRCDIR "/vcl/source/filter/graphicfilter.cxx")
754 return;
755 // valid code
756 if (fn == SRCDIR "/vcl/source/app/salvtables.cxx")
757 return;
758 // undo code is tricky
759 if (fn == SRCDIR "/svl/source/undo/undo.cxx")
760 return;
761 // subclass that messes with parent class in constructor/destructor, yuck
762 if (fn == SRCDIR "/svtools/source/contnr/imivctl1.cxx")
763 return;
764 // SQLParseNode
765 if (fn == SRCDIR "/connectivity/source/parse/sqlnode.cxx")
766 return;
767 // the whole svx model/contact/view thing confuses me
768 if (fn == SRCDIR "/svx/source/sdr/contact/viewcontact.cxx")
769 return;
770 if (fn == SRCDIR "/svx/source/sdr/contact/objectcontact.cxx")
771 return;
772 // no idea
773 if (fn == SRCDIR "/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.cxx")
774 return;
775 // SdrUndo stuff
776 if (fn == SRCDIR "/svx/source/svdraw/svdundo.cxx")
777 return;
778 // TODO the lazydelete stuff should probably just be ripped out altogether now that we have VclPtr
779 if (fn == SRCDIR "/vcl/source/helper/lazydelete.cxx")
780 return;
781 // linked list
782 if (fn == SRCDIR "/filter/source/graphicfilter/idxf/dxfblkrd.cxx")
783 return;
784 if (fn == SRCDIR "/filter/source/graphicfilter/idxf/dxftblrd.cxx")
785 return;
786 if (fn == SRCDIR "/lotuswordpro/source/filter/utlist.cxx")
787 return;
788 if (fn == SRCDIR "/lotuswordpro/source/filter/lwpfribptr.cxx")
789 return;
790 // valid
791 if (fn == SRCDIR "/sd/source/ui/sidebar/MasterPagesSelector.cxx")
792 return;
793 // linked list
794 if (fn == SRCDIR "/sd/source/filter/ppt/pptatom.cxx")
795 return;
796 // linked list
797 if (fn == SRCDIR "/sc/source/core/data/funcdesc.cxx")
798 return;
799 // linked list
800 if (fn == SRCDIR "/sw/source/core/crsr/crsrsh.cxx")
801 return;
802 // no idea
803 if (fn == SRCDIR "/sw/source/core/docnode/nodes.cxx")
804 return;
805 // linked list
806 if (fn == SRCDIR "/sw/source/core/unocore/unocrsr.cxx")
807 return;
808 // linked list
809 if (fn == SRCDIR "/filter/source/graphicfilter/idxf/dxfentrd.cxx")
810 return;
811 // linked list
812 if (fn == SRCDIR "/filter/source/graphicfilter/ios2met/ios2met.cxx")
813 return;
814 // sometimes owning, sometimes not
815 if (fn == SRCDIR "/sw/qa/core/Test-BigPtrArray.cxx")
816 return;
818 report(
819 DiagnosticsEngine::Warning,
820 "loopdelete: rather manage this var with std::some_container<std::unique_ptr<T>>",
821 compat::getBeginLoc(deleteExpr))
822 << deleteExpr->getSourceRange();
823 report(
824 DiagnosticsEngine::Note,
825 "var is here",
826 compat::getBeginLoc(varDecl))
827 << varDecl->getSourceRange();
831 void UseUniquePtr::CheckCXXForRangeStmt(const FunctionDecl* functionDecl, const CXXForRangeStmt* cxxForRangeStmt)
833 CXXDeleteExpr const * deleteExpr = nullptr;
834 if (auto compoundStmt = dyn_cast<CompoundStmt>(cxxForRangeStmt->getBody()))
836 for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
837 if ((deleteExpr = dyn_cast<CXXDeleteExpr>(*i)))
838 break;
840 else
841 deleteExpr = dyn_cast<CXXDeleteExpr>(cxxForRangeStmt->getBody());
842 if (!deleteExpr)
843 return;
845 // check for delete of member
846 if (auto memberExpr = dyn_cast<MemberExpr>(cxxForRangeStmt->getRangeInit()))
848 auto fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
849 if (!fieldDecl)
850 return;
852 // appears to just randomly leak stuff, and it involves some lex/yacc stuff
853 if (fn == SRCDIR "/idlc/source/aststack.cxx")
854 return;
855 // complicated
856 if (fn == SRCDIR "/vcl/source/gdi/print.cxx")
857 return;
858 // sometimes it's an owning field, sometimes not
859 if (fn == SRCDIR "/i18npool/source/localedata/localedata.cxx")
860 return;
862 CheckMemberDeleteExpr(functionDecl, deleteExpr, memberExpr, "rather manage this with std::some_container<std::unique_ptr<T>>");
865 // check for delete of var
866 if (auto declRefExpr = dyn_cast<DeclRefExpr>(cxxForRangeStmt->getRangeInit()->IgnoreParens()->IgnoreImplicit()))
868 auto varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl());
869 if (!varDecl)
870 return;
872 // don't feel like messing with this part of sfx2
873 if (fn == SRCDIR "/sfx2/source/control/msgpool.cxx")
874 return;
875 if (fn == SRCDIR "/sfx2/source/doc/doctemplates.cxx")
876 return;
877 // lex/yacc
878 if (fn == SRCDIR "/hwpfilter/source/grammar.cxx")
879 return;
880 if (fn == SRCDIR "/hwpfilter/source/formula.cxx")
881 return;
882 // no idea why, but ui tests crash afterwards in weird ways
883 if (fn == SRCDIR "/svtools/source/control/roadmap.cxx")
884 return;
885 // sometimes it owns it, sometimes it does not
886 if (fn == SRCDIR "/dbaccess/source/ui/misc/WCopyTable.cxx")
887 return;
888 // SfxPoolItem array
889 if (fn == SRCDIR "/dbaccess/source/ui/misc/UITools.cxx")
890 return;
891 // SfxPoolItem array
892 if (fn == SRCDIR "/sw/source/core/bastyp/init.cxx")
893 return;
894 // SfxPoolItem array
895 if (fn == SRCDIR "/reportdesign/source/ui/misc/UITools.cxx")
896 return;
897 // SfxPoolItem array
898 if (fn == SRCDIR "/reportdesign/source/ui/report/ReportController.cxx")
899 return;
900 // complicated
901 if (fn == SRCDIR "/svx/source/sdr/contact/viewcontact.cxx")
902 return;
903 if (fn == SRCDIR "/svx/source/sdr/contact/objectcontact.cxx")
904 return;
906 report(
907 DiagnosticsEngine::Warning,
908 "rather manage this var with std::some_container<std::unique_ptr<T>>",
909 compat::getBeginLoc(deleteExpr))
910 << deleteExpr->getSourceRange();
911 report(
912 DiagnosticsEngine::Note,
913 "var is here",
914 compat::getBeginLoc(varDecl))
915 << varDecl->getSourceRange();
919 void UseUniquePtr::CheckMemberDeleteExpr(const FunctionDecl* functionDecl, const CXXDeleteExpr* deleteExpr,
920 const MemberExpr* memberExpr, StringRef message)
922 // ignore union games
923 const FieldDecl* fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
924 if (!fieldDecl)
925 return;
926 TagDecl const * td = dyn_cast<TagDecl>(fieldDecl->getDeclContext());
927 if (td->isUnion())
928 return;
930 // ignore calling delete on someone else's field
931 if (auto methodDecl = dyn_cast<CXXMethodDecl>(functionDecl))
932 if (fieldDecl->getParent() != methodDecl->getParent() )
933 return;
935 if (ignoreLocation(fieldDecl))
936 return;
937 // to ignore things like the CPPUNIT macros
938 if (loplugin::hasPathnamePrefix(fn, WORKDIR "/"))
939 return;
940 // passes and stores pointers to member fields
941 if (fn == SRCDIR "/sot/source/sdstor/stgdir.hxx")
942 return;
943 // something platform-specific
944 if (fn == SRCDIR "/hwpfilter/source/htags.h")
945 return;
946 // passes pointers to member fields
947 if (fn == SRCDIR "/sd/inc/sdpptwrp.hxx")
948 return;
949 // @TODO intrusive linked-lists here, with some trickiness
950 if (fn == SRCDIR "/sw/source/filter/html/parcss1.hxx")
951 return;
952 // @TODO SwDoc has some weird ref-counting going on
953 if (fn == SRCDIR "/sw/inc/shellio.hxx")
954 return;
955 // @TODO it's sharing pointers with another class
956 if (fn == SRCDIR "/sc/inc/formulacell.hxx")
957 return;
958 // some weird stuff going on here around struct Entity
959 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sax/"))
960 return;
961 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/include/sax/"))
962 return;
963 // manipulation of tree structures ie. StgAvlNode, don't lend themselves to std::unique_ptr
964 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/sot/"))
965 return;
966 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/include/sot/"))
967 return;
968 // the std::vector is being passed to another class
969 if (fn == SRCDIR "/sfx2/source/explorer/nochaos.cxx")
970 return;
971 auto tc = loplugin::TypeCheck(fieldDecl->getType());
972 // these sw::Ring based classes do not lend themselves to std::unique_ptr management
973 if (tc.Pointer().Class("SwNodeIndex").GlobalNamespace() || tc.Pointer().Class("SwShellTableCursor").GlobalNamespace()
974 || tc.Pointer().Class("SwBlockCursor").GlobalNamespace() || tc.Pointer().Class("SwVisibleCursor").GlobalNamespace()
975 || tc.Pointer().Class("SwShellCursor").GlobalNamespace())
976 return;
977 // there is a loop in ~ImplPrnQueueList deleting stuff on a global data structure
978 if (fn == SRCDIR "/vcl/inc/print.h")
979 return;
980 // painful linked list
981 if (fn == SRCDIR "/basic/source/inc/runtime.hxx")
982 return;
983 // not sure how the node management is working here
984 if (fn == SRCDIR "/i18npool/source/localedata/saxparser.cxx")
985 return;
986 // has a pointer that it only sometimes owns
987 if (fn == SRCDIR "/editeng/source/editeng/impedit.hxx")
988 return;
990 report(
991 DiagnosticsEngine::Warning,
992 message,
993 compat::getBeginLoc(deleteExpr))
994 << deleteExpr->getSourceRange();
995 report(
996 DiagnosticsEngine::Note,
997 "member is here",
998 compat::getBeginLoc(fieldDecl))
999 << fieldDecl->getSourceRange();
1002 bool UseUniquePtr::TraverseFunctionDecl(FunctionDecl* functionDecl)
1004 if (ignoreLocation(functionDecl))
1005 return true;
1007 auto oldCurrent = mpCurrentFunctionDecl;
1008 mpCurrentFunctionDecl = functionDecl;
1009 bool ret = RecursiveASTVisitor::TraverseFunctionDecl(functionDecl);
1010 mpCurrentFunctionDecl = oldCurrent;
1012 return ret;
1015 bool UseUniquePtr::TraverseCXXMethodDecl(CXXMethodDecl* methodDecl)
1017 if (ignoreLocation(methodDecl))
1018 return true;
1020 auto oldCurrent = mpCurrentFunctionDecl;
1021 mpCurrentFunctionDecl = methodDecl;
1022 bool ret = RecursiveASTVisitor::TraverseCXXMethodDecl(methodDecl);
1023 mpCurrentFunctionDecl = oldCurrent;
1025 return ret;
1028 bool UseUniquePtr::TraverseCXXDeductionGuideDecl(CXXDeductionGuideDecl* methodDecl)
1030 if (ignoreLocation(methodDecl))
1031 return true;
1033 auto oldCurrent = mpCurrentFunctionDecl;
1034 mpCurrentFunctionDecl = methodDecl;
1035 bool ret = RecursiveASTVisitor::TraverseCXXDeductionGuideDecl(methodDecl);
1036 mpCurrentFunctionDecl = oldCurrent;
1038 return ret;
1041 bool UseUniquePtr::TraverseCXXConstructorDecl(CXXConstructorDecl* methodDecl)
1043 if (ignoreLocation(methodDecl))
1044 return true;
1046 auto oldCurrent = mpCurrentFunctionDecl;
1047 mpCurrentFunctionDecl = methodDecl;
1048 bool ret = RecursiveASTVisitor::TraverseCXXConstructorDecl(methodDecl);
1049 mpCurrentFunctionDecl = oldCurrent;
1051 return ret;
1054 bool UseUniquePtr::TraverseCXXConversionDecl(CXXConversionDecl* methodDecl)
1056 if (ignoreLocation(methodDecl))
1057 return true;
1059 auto oldCurrent = mpCurrentFunctionDecl;
1060 mpCurrentFunctionDecl = methodDecl;
1061 bool ret = RecursiveASTVisitor::TraverseCXXConversionDecl(methodDecl);
1062 mpCurrentFunctionDecl = oldCurrent;
1064 return ret;
1067 bool UseUniquePtr::TraverseCXXDestructorDecl(CXXDestructorDecl* methodDecl)
1069 if (ignoreLocation(methodDecl))
1070 return true;
1072 auto oldCurrent = mpCurrentFunctionDecl;
1073 mpCurrentFunctionDecl = methodDecl;
1074 bool ret = RecursiveASTVisitor::TraverseCXXDestructorDecl(methodDecl);
1075 mpCurrentFunctionDecl = oldCurrent;
1077 return ret;
1080 bool UseUniquePtr::TraverseConstructorInitializer(CXXCtorInitializer * ctorInit)
1082 if (!ctorInit->getSourceLocation().isValid() || ignoreLocation(ctorInit->getSourceLocation()))
1083 return true;
1084 if (!ctorInit->getMember())
1085 return true;
1086 if (!loplugin::TypeCheck(ctorInit->getMember()->getType()).Class("unique_ptr").StdNamespace())
1087 return true;
1088 auto constructExpr = dyn_cast_or_null<CXXConstructExpr>(ctorInit->getInit());
1089 if (!constructExpr || constructExpr->getNumArgs() == 0)
1090 return true;
1091 auto init = constructExpr->getArg(0)->IgnoreImpCasts();
1092 if (!isa<DeclRefExpr>(init))
1093 return true;
1095 StringRef fn = getFileNameOfSpellingLoc(compiler.getSourceManager().getSpellingLoc(ctorInit->getSourceLocation()));
1096 // don't feel like fiddling with the yacc parser
1097 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/idlc/"))
1098 return true;
1099 // cannot change URE
1100 if (loplugin::hasPathnamePrefix(fn, SRCDIR "/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx"))
1101 return true;
1103 report(
1104 DiagnosticsEngine::Warning,
1105 "should be passing via std::unique_ptr param",
1106 ctorInit->getSourceLocation())
1107 << ctorInit->getSourceRange();
1108 return RecursiveASTVisitor<UseUniquePtr>::TraverseConstructorInitializer(ctorInit);
1111 // Only checks for calls to delete on a pointer param
1112 bool UseUniquePtr::VisitCXXDeleteExpr(const CXXDeleteExpr* deleteExpr)
1114 if (!mpCurrentFunctionDecl)
1115 return true;
1116 if (ignoreLocation(mpCurrentFunctionDecl))
1117 return true;
1118 if (isInUnoIncludeFile(compat::getBeginLoc(mpCurrentFunctionDecl->getCanonicalDecl())))
1119 return true;
1120 auto declRefExpr = dyn_cast<DeclRefExpr>(deleteExpr->getArgument()->IgnoreParenImpCasts()->IgnoreImplicit());
1121 if (!declRefExpr)
1122 return true;
1123 if (auto parmVarDecl = dyn_cast<ParmVarDecl>(declRefExpr->getDecl()))
1124 CheckDeleteParmVar(deleteExpr, parmVarDecl);
1125 else if (auto varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl()))
1126 CheckDeleteLocalVar(mpCurrentFunctionDecl, deleteExpr, varDecl);
1127 return true;
1130 void UseUniquePtr::CheckDeleteParmVar(const CXXDeleteExpr* deleteExpr, const ParmVarDecl* )
1132 if (mpCurrentFunctionDecl->getIdentifier())
1134 auto name = mpCurrentFunctionDecl->getName();
1135 if (name == "delete_IncludesCollection" || name == "convertName"
1136 || name == "createNamedType"
1137 || name == "typelib_typedescriptionreference_release" || name == "deleteExceptions"
1138 || name == "uno_threadpool_destroy"
1139 || name == "AddRanges_Impl"
1140 || name == "DestroySalInstance"
1141 || name == "ImplHandleUserEvent"
1142 || name == "releaseDecimalPtr" // TODO, basic
1143 || name == "replaceAndReset" // TODO, connectivity
1144 || name == "intrusive_ptr_release"
1145 || name == "FreeParaList"
1146 || name == "DeleteSdrUndoAction" // TODO, sc
1147 || name == "lcl_MergeGCBox" || name == "lcl_MergeGCLine" || name == "lcl_DelHFFormat")
1148 return;
1150 if (auto cxxMethodDecl = dyn_cast<CXXMethodDecl>(mpCurrentFunctionDecl))
1152 auto parentName = cxxMethodDecl->getParent()->getName();
1153 // include/o3tl/deleter.hxx
1154 if (parentName == "default_delete")
1155 return;
1156 // TODO Bitmap::ReleaseAccess
1157 // Tricky because it reverberates through other code and requires that BitmapWriteAccess move into /include again
1158 if (parentName == "Bitmap")
1159 return;
1160 // TODO virtual ones are much trickier, leave for later
1161 if (cxxMethodDecl->isVirtual())
1162 return;
1163 // sw/inc/unobaseclass.hxx holds SolarMutex while deleting
1164 if (parentName == "UnoImplPtrDeleter")
1165 return;
1168 // StgAvlNode::Remove
1169 if (fn == SRCDIR "/sot/source/sdstor/stgavl.cxx")
1170 return;
1171 // SfxItemPool::ReleaseDefaults and SfxItemPool::Free
1172 if (fn == SRCDIR "/svl/source/items/itempool.cxx")
1173 return;
1174 // SwContourCache
1175 if (fn == SRCDIR "/sw/source/core/text/txtfly.cxx")
1176 return;
1177 // too messy to cope with the SQL parser
1178 if (fn == SRCDIR "/connectivity/source/parse/sqlnode.cxx")
1179 return;
1180 // I can't figure out the ownership of the SfxMedium in the call site(s)
1181 if (fn == SRCDIR "/sfx2/source/doc/sfxbasemodel.cxx")
1182 return;
1183 // pointer passed via IMPL_LINK
1184 if (fn == SRCDIR "/sfx2/source/control/dispatch.cxx")
1185 return;
1186 // NavigatorTreeModel::Remove
1187 if (fn == SRCDIR "/svx/source/form/navigatortreemodel.cxx")
1188 return;
1189 // SdrModel::AddUndo
1190 if (fn == SRCDIR "/svx/source/svdraw/svdmodel.cxx")
1191 return;
1192 // undo callback
1193 if (fn == SRCDIR "/basctl/source/basicide/baside3.cxx")
1194 return;
1195 // ActualizeProgress::TimeoutHdl
1196 if (fn == SRCDIR "/cui/source/dialogs/cuigaldlg.cxx")
1197 return;
1198 // ToolbarSaveInData::RemoveToolbar
1199 if (fn == SRCDIR "/cui/source/customize/cfg.cxx")
1200 return;
1201 // OStorage_Impl::RemoveElement very complicated ownership passing going on
1202 if (fn == SRCDIR "/package/source/xstor/xstorage.cxx")
1203 return;
1204 // actually held via shared_ptr, uses protected deleter object
1205 if (fn == SRCDIR "/sd/source/ui/framework/tools/FrameworkHelper.cxx")
1206 return;
1207 // actually held via shared_ptr, uses protected deleter object
1208 if (fn == SRCDIR "/sd/source/ui/presenter/CanvasUpdateRequester.cxx")
1209 return;
1210 // actually held via shared_ptr, uses protected deleter object
1211 if (fn == SRCDIR "/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx")
1212 return;
1213 // actually held via shared_ptr, uses protected deleter object
1214 if (fn == SRCDIR "/sd/source/ui/sidebar/MasterPageContainer.cxx")
1215 return;
1216 // actually held via shared_ptr, uses protected deleter object
1217 if (fn == SRCDIR "/sd/source/ui/tools/TimerBasedTaskExecution.cxx")
1218 return;
1219 // actually held via shared_ptr, uses protected deleter object
1220 if (fn == SRCDIR "/sd/source/ui/view/ViewShellImplementation.cxx")
1221 return;
1222 // ScBroadcastAreaSlot::StartListeningArea manual ref-counting of ScBroadcastArea
1223 if (fn == SRCDIR "/sc/source/core/data/bcaslot.cxx")
1224 return;
1225 // ScDrawLayer::AddCalcUndo undo stuff
1226 if (fn == SRCDIR "/sc/source/core/data/drwlayer.cxx")
1227 return;
1228 // ScTable::SetFormulaCell
1229 if (fn == SRCDIR "/sc/source/core/data/table2.cxx")
1230 return;
1231 // ScDocument::SetFormulaCell
1232 if (fn == SRCDIR "/sc/source/core/data/documen2.cxx")
1233 return;
1234 // RemoveEditAttribsHandler, stored in mdds block
1235 if (fn == SRCDIR "/sc/source/core/data/column2.cxx")
1236 return;
1237 // just turns into a mess
1238 if (fn == SRCDIR "/sc/source/ui/Accessibility/AccessibleDocument.cxx")
1239 return;
1240 // SwCache::DeleteObj, linked list
1241 if (fn == SRCDIR "/sw/source/core/bastyp/swcache.cxx")
1242 return;
1243 // SAXEventKeeperImpl::smashBufferNode
1244 if (fn == SRCDIR "/xmlsecurity/source/framework/saxeventkeeperimpl.cxx")
1245 return;
1246 // SwDoc::DeleteExtTextInput
1247 if (fn == SRCDIR "/sw/source/core/doc/extinput.cxx")
1248 return;
1249 // SwDoc::DelSectionFormat
1250 if (fn == SRCDIR "/sw/source/core/docnode/ndsect.cxx")
1251 return;
1252 // SwFrame::DestroyFrame
1253 if (fn == SRCDIR "/sw/source/core/layout/ssfrm.cxx")
1254 return;
1255 // SwGluePortion::Join
1256 if (fn == SRCDIR "/sw/source/core/text/porglue.cxx")
1257 return;
1258 // SwDoc::DelFrameFormat
1259 if (fn == SRCDIR "/sw/source/core/doc/docfmt.cxx")
1260 return;
1261 // SwTextAttr::Destroy
1262 if (fn == SRCDIR "/sw/source/core/txtnode/txatbase.cxx")
1263 return;
1264 // IMPL_LINK( SwDoc, AddDrawUndo, SdrUndoAction *, pUndo, void )
1265 if (fn == SRCDIR "/sw/source/core/undo/undraw.cxx")
1266 return;
1267 // SwHTMLParser::EndAttr
1268 if (fn == SRCDIR "/sw/source/filter/html/swhtml.cxx")
1269 return;
1270 // SwGlossaryHdl::Expand sometimes the pointer is owned, sometimes it is not
1271 if (fn == SRCDIR "/sw/source/uibase/dochdl/gloshdl.cxx")
1272 return;
1273 // SwWrtShell::Insert only owned sometimes
1274 if (fn == SRCDIR "/sw/source/uibase/wrtsh/wrtsh1.cxx")
1275 return;
1276 // NodeArrayDeleter
1277 if (fn == SRCDIR "/unoxml/source/rdf/librdf_repository.cxx")
1278 return;
1279 // SmCursor::LineToList ran out of enthusiasm to rework the node handling
1280 if (fn == SRCDIR "/starmath/source/cursor.cxx")
1281 return;
1282 // XMLEventOASISTransformerContext::FlushEventMap
1283 if (fn == SRCDIR "/xmloff/source/transform/EventOASISTContext.cxx")
1284 return;
1285 // XMLEventOOoTransformerContext::FlushEventMap
1286 if (fn == SRCDIR "/xmloff/source/transform/EventOOoTContext.cxx")
1287 return;
1288 // SbiProcDef::Match
1289 if (fn == SRCDIR "/basic/source/comp/symtbl.cxx")
1290 return;
1293 Sometimes we can pass the param as std::unique_ptr<T>& or std::unique_ptr, sometimes the method
1294 just needs to be inlined, which normally exposes more simplification.
1296 report(
1297 DiagnosticsEngine::Warning,
1298 "calling delete on a pointer param, should be either whitelisted or simplified",
1299 compat::getBeginLoc(deleteExpr))
1300 << deleteExpr->getSourceRange();
1304 loplugin::Plugin::Registration< UseUniquePtr > X("useuniqueptr", false);
1308 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */