2017-01-11 14:19:47 +02:00
|
|
|
/* -*- 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/.
|
|
|
|
*/
|
|
|
|
|
2017-04-14 08:42:15 +10:00
|
|
|
#include <memory>
|
2017-01-11 14:19:47 +02:00
|
|
|
#include <cassert>
|
|
|
|
#include <string>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <set>
|
|
|
|
#include "plugin.hxx"
|
2017-07-14 14:36:52 +02:00
|
|
|
#include "check.hxx"
|
2017-01-11 14:19:47 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Find destructors that only contain a single call to delete of a field. In which
|
|
|
|
case that field should really be managed by unique_ptr.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class UseUniquePtr:
|
2018-08-23 14:35:15 +02:00
|
|
|
public loplugin::FilteringPlugin<UseUniquePtr>
|
2017-01-11 14:19:47 +02:00
|
|
|
{
|
|
|
|
public:
|
2017-11-07 11:50:47 +01:00
|
|
|
explicit UseUniquePtr(loplugin::InstantiationData const & data):
|
2018-08-23 14:35:15 +02:00
|
|
|
FilteringPlugin(data) {}
|
2017-01-11 14:19:47 +02:00
|
|
|
|
|
|
|
virtual void run() override
|
|
|
|
{
|
2018-05-29 11:28:07 +02:00
|
|
|
std::string fn(handler.getMainFileName());
|
2018-04-06 13:20:46 +02:00
|
|
|
loplugin::normalizeDotDotInFilePath(fn);
|
|
|
|
// can't change these because we pass them down to the SfxItemPool stuff
|
|
|
|
if (fn == SRCDIR "/sc/source/core/data/docpool.cxx")
|
|
|
|
return;
|
|
|
|
// this just too clever for me
|
|
|
|
if (fn == SRCDIR "/sc/source/core/tool/chgtrack.cxx")
|
|
|
|
return;
|
2018-04-16 12:06:48 +02:00
|
|
|
// too clever
|
|
|
|
if (fn == SRCDIR "/pyuno/source/module/pyuno_runtime.cxx")
|
|
|
|
return;
|
2018-05-14 16:17:19 +02:00
|
|
|
// m_pExampleSet here is very badly managed. sometimes it is owning, sometimes not,
|
2018-05-09 09:40:59 +02:00
|
|
|
// and the logic depends on overriding methods.
|
|
|
|
if (fn == SRCDIR "/sfx2/source/dialog/tabdlg.cxx")
|
|
|
|
return;
|
2018-05-09 14:00:59 +02:00
|
|
|
// pLongArr is being deleted here because we temporarily overwrite a pointer to someone else's buffer, with a pointer
|
|
|
|
// to our own buffer
|
|
|
|
if (fn == SRCDIR "/editeng/source/misc/txtrange.cxx")
|
|
|
|
return;
|
2018-05-09 14:53:07 +02:00
|
|
|
// can't use std::set<std::unique_ptr<>> until C++14
|
|
|
|
if (fn == SRCDIR "/editeng/source/misc/svxacorr.cxx")
|
|
|
|
return;
|
2018-05-17 14:51:04 +02:00
|
|
|
// horrible horrible spawn of evil ownership and deletion here
|
|
|
|
if (fn == SRCDIR "/sfx2/source/view/ipclient.cxx")
|
|
|
|
return;
|
2018-05-18 13:44:18 +02:00
|
|
|
// sometimes it owns, sometimes it doesn't
|
|
|
|
if (fn == SRCDIR "/editeng/source/misc/svxacorr.cxx")
|
|
|
|
return;
|
2018-06-28 13:48:17 +02:00
|
|
|
// SwDoc::m_PageDescs has weird handling
|
|
|
|
if (fn == SRCDIR "/sw/source/core/doc/docnew.cxx")
|
|
|
|
return;
|
|
|
|
// SwRedlineData::pNext and pExtraData have complex handling
|
|
|
|
if (fn == SRCDIR "/sw/source/core/doc/docredln.cxx")
|
|
|
|
return;
|
2018-07-03 09:36:24 +02:00
|
|
|
// ScTempDocSource::pTempDoc
|
|
|
|
if (fn == SRCDIR "/sc/source/ui/unoobj/funcuno.cxx")
|
|
|
|
return;
|
2018-07-12 16:52:52 +02:00
|
|
|
// SwAttrIter::m_pFont
|
2018-07-13 11:27:23 +02:00
|
|
|
if (fn == SRCDIR "/sw/source/core/text/itratr.cxx"
|
|
|
|
|| fn == SRCDIR "/sw/source/core/text/redlnitr.cxx")
|
2018-07-12 16:52:52 +02:00
|
|
|
return;
|
|
|
|
// SwWrongList
|
|
|
|
if (fn == SRCDIR "/sw/source/core/text/wrong.cxx")
|
|
|
|
return;
|
2018-07-13 11:27:23 +02:00
|
|
|
// SwLineLayout::m_pNext
|
|
|
|
if (fn == SRCDIR "/sw/source/core/text/porlay.cxx")
|
|
|
|
return;
|
2018-07-16 14:40:20 +02:00
|
|
|
// ODatabaseExport::m_aDestColumns
|
|
|
|
if (fn == SRCDIR "/dbaccess/source/ui/misc/DExport.cxx")
|
|
|
|
return;
|
2018-07-16 16:41:48 +02:00
|
|
|
// ScTabView::pDrawActual and pDrawOld
|
|
|
|
if (fn == SRCDIR "/sc/source/ui/view/tabview5.cxx")
|
|
|
|
return;
|
2018-07-18 11:35:46 +02:00
|
|
|
// SwHTMLParser::m_pPendStack
|
|
|
|
if (fn == SRCDIR "/sw/source/filter/html/htmlcss1.cxx")
|
|
|
|
return;
|
2018-07-19 12:11:06 +02:00
|
|
|
// Visual Studio 2017 has trouble with these
|
|
|
|
if (fn == SRCDIR "/comphelper/source/property/MasterPropertySet.cxx"
|
|
|
|
|| fn == SRCDIR "/comphelper/source/property/MasterPropertySetInfo.cxx")
|
|
|
|
return;
|
2018-07-19 13:08:41 +02:00
|
|
|
// SwTableLine::m_aBoxes
|
|
|
|
if (fn == SRCDIR "/sw/source/core/table/swtable.cxx")
|
|
|
|
return;
|
|
|
|
// SwHTMLParser::m_pFormImpl
|
|
|
|
if (fn == SRCDIR "/sw/source/filter/html/htmlform.cxx")
|
|
|
|
return;
|
|
|
|
// SwHTMLParser::m_pPendStack, pNext
|
|
|
|
if (fn == SRCDIR "/sw/source/filter/html/htmltab.cxx")
|
|
|
|
return;
|
|
|
|
// SaveLine::pBox, pNext
|
|
|
|
if (fn == SRCDIR "/sw/source/core/undo/untbl.cxx")
|
|
|
|
return;
|
2018-07-23 09:24:24 +02:00
|
|
|
// RedlineInfo::pNextRedline
|
|
|
|
if (fn == SRCDIR "/sw/source/filter/xml/XMLRedlineImportHelper.cxx")
|
|
|
|
return;
|
2018-07-23 15:35:42 +02:00
|
|
|
// SfxObjectShell::pMedium
|
|
|
|
if (fn == SRCDIR "/sfx2/source/doc/objxtor.cxx")
|
|
|
|
return;
|
2018-07-26 16:22:07 +02:00
|
|
|
// various
|
|
|
|
if (fn == SRCDIR "/sw/source/filter/ww8/wrtww8.cxx")
|
|
|
|
return;
|
|
|
|
// WW8TabBandDesc
|
|
|
|
if (fn == SRCDIR "/sw/source/filter/ww8/ww8par2.cxx")
|
|
|
|
return;
|
2018-09-03 09:58:12 +02:00
|
|
|
// ZipOutputStream, ownership of ZipEntry is horribly complicated here
|
|
|
|
if (fn == SRCDIR "/package/source/zipapi/ZipOutputStream.cxx")
|
|
|
|
return;
|
2018-04-06 13:20:46 +02:00
|
|
|
|
2017-01-11 14:19:47 +02:00
|
|
|
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
|
|
|
|
}
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
bool VisitCXXMethodDecl(const CXXMethodDecl* );
|
2017-06-26 09:48:30 +02:00
|
|
|
bool VisitCompoundStmt(const CompoundStmt* );
|
2018-06-21 15:32:52 +02:00
|
|
|
bool VisitCXXDeleteExpr(const CXXDeleteExpr* );
|
|
|
|
bool TraverseFunctionDecl(FunctionDecl* );
|
2018-08-16 13:46:39 +02:00
|
|
|
bool TraverseCXXMethodDecl(CXXMethodDecl* );
|
|
|
|
bool TraverseCXXConstructorDecl(CXXConstructorDecl* );
|
2018-08-17 14:40:29 +02:00
|
|
|
bool TraverseConstructorInitializer(CXXCtorInitializer*);
|
|
|
|
|
2017-06-26 09:48:30 +02:00
|
|
|
private:
|
2018-05-02 14:46:26 +02:00
|
|
|
void CheckCompoundStmt(const CXXMethodDecl*, const CompoundStmt* );
|
2018-08-16 13:46:39 +02:00
|
|
|
void CheckIfStmt(const CXXMethodDecl* methodDecl, const IfStmt* );
|
|
|
|
void CheckCXXForRangeStmt(const CXXMethodDecl*, const CXXForRangeStmt* );
|
2018-04-12 11:23:58 +02:00
|
|
|
void CheckLoopDelete(const CXXMethodDecl*, const Stmt* );
|
|
|
|
void CheckLoopDelete(const CXXMethodDecl*, const CXXDeleteExpr* );
|
|
|
|
void CheckDeleteExpr(const CXXMethodDecl*, const CXXDeleteExpr*);
|
2018-04-24 14:04:53 +02:00
|
|
|
void CheckParenExpr(const CXXMethodDecl*, const ParenExpr*);
|
2018-04-12 11:23:58 +02:00
|
|
|
void CheckDeleteExpr(const CXXMethodDecl*, const CXXDeleteExpr*,
|
2018-01-17 13:14:21 +02:00
|
|
|
const MemberExpr*, StringRef message);
|
2018-06-21 15:32:52 +02:00
|
|
|
FunctionDecl const * mpCurrentFunctionDecl = nullptr;
|
2017-01-11 14:19:47 +02:00
|
|
|
};
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
bool UseUniquePtr::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
|
2017-01-11 14:19:47 +02:00
|
|
|
{
|
2018-04-12 11:23:58 +02:00
|
|
|
if (ignoreLocation(methodDecl))
|
2017-01-11 14:19:47 +02:00
|
|
|
return true;
|
2018-04-12 11:23:58 +02:00
|
|
|
if (isInUnoIncludeFile(methodDecl))
|
2017-01-11 14:19:47 +02:00
|
|
|
return true;
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
const CompoundStmt* compoundStmt = dyn_cast_or_null< CompoundStmt >( methodDecl->getBody() );
|
2018-01-10 11:29:36 +02:00
|
|
|
if (!compoundStmt || compoundStmt->size() == 0)
|
2017-01-11 14:19:47 +02:00
|
|
|
return true;
|
2017-05-12 15:32:36 +02:00
|
|
|
|
2018-05-02 14:46:26 +02:00
|
|
|
CheckCompoundStmt(methodDecl, compoundStmt);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
/**
|
|
|
|
* check for simple call to delete i.e. direct unconditional call, or if-guarded call
|
|
|
|
*/
|
2018-05-02 14:46:26 +02:00
|
|
|
void UseUniquePtr::CheckCompoundStmt(const CXXMethodDecl* methodDecl, const CompoundStmt* compoundStmt)
|
|
|
|
{
|
2018-01-17 13:14:21 +02:00
|
|
|
for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
|
|
|
|
{
|
|
|
|
if (auto cxxForRangeStmt = dyn_cast<CXXForRangeStmt>(*i))
|
2018-08-16 13:46:39 +02:00
|
|
|
CheckCXXForRangeStmt(methodDecl, cxxForRangeStmt);
|
2018-01-17 13:14:21 +02:00
|
|
|
else if (auto forStmt = dyn_cast<ForStmt>(*i))
|
2018-04-12 11:23:58 +02:00
|
|
|
CheckLoopDelete(methodDecl, forStmt->getBody());
|
2018-01-17 13:14:21 +02:00
|
|
|
else if (auto whileStmt = dyn_cast<WhileStmt>(*i))
|
2018-04-12 11:23:58 +02:00
|
|
|
CheckLoopDelete(methodDecl, whileStmt->getBody());
|
2018-05-02 14:46:26 +02:00
|
|
|
// check for unconditional inner compound statements
|
|
|
|
else if (auto innerCompoundStmt = dyn_cast<CompoundStmt>(*i))
|
|
|
|
CheckCompoundStmt(methodDecl, innerCompoundStmt);
|
2018-08-16 13:46:39 +02:00
|
|
|
else if (auto deleteExpr = dyn_cast<CXXDeleteExpr>(*i))
|
|
|
|
CheckDeleteExpr(methodDecl, deleteExpr);
|
|
|
|
else if (auto parenExpr = dyn_cast<ParenExpr>(*i))
|
|
|
|
CheckParenExpr(methodDecl, parenExpr);
|
|
|
|
else if (auto ifStmt = dyn_cast<IfStmt>(*i))
|
|
|
|
CheckIfStmt(methodDecl, ifStmt);
|
2018-01-17 13:14:21 +02:00
|
|
|
}
|
2017-06-26 09:48:30 +02:00
|
|
|
}
|
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
// Check for conditional deletes like:
|
|
|
|
// if (m_pField != nullptr) delete m_pField;
|
|
|
|
void UseUniquePtr::CheckIfStmt(const CXXMethodDecl* methodDecl, const IfStmt* ifStmt)
|
2017-06-26 09:48:30 +02:00
|
|
|
{
|
2018-08-16 13:46:39 +02:00
|
|
|
auto cond = ifStmt->getCond()->IgnoreImpCasts();
|
|
|
|
if (auto ifCondMemberExpr = dyn_cast<MemberExpr>(cond))
|
2018-01-10 11:29:36 +02:00
|
|
|
{
|
2018-08-16 13:46:39 +02:00
|
|
|
// ignore "if (bMine)"
|
|
|
|
if (!loplugin::TypeCheck(ifCondMemberExpr->getType()).Pointer())
|
|
|
|
return;
|
|
|
|
// good
|
|
|
|
}
|
|
|
|
else if (auto binaryOp = dyn_cast<BinaryOperator>(cond))
|
|
|
|
{
|
|
|
|
if (!isa<MemberExpr>(binaryOp->getLHS()->IgnoreImpCasts()))
|
|
|
|
return;
|
|
|
|
if (!isa<CXXNullPtrLiteralExpr>(binaryOp->getRHS()->IgnoreImpCasts()))
|
|
|
|
return;
|
|
|
|
// good
|
|
|
|
}
|
|
|
|
else // ignore anything more complicated
|
|
|
|
return;
|
2018-01-17 13:14:21 +02:00
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
auto deleteExpr = dyn_cast<CXXDeleteExpr>(ifStmt->getThen());
|
|
|
|
if (deleteExpr)
|
|
|
|
{
|
|
|
|
CheckDeleteExpr(methodDecl, deleteExpr);
|
|
|
|
return;
|
|
|
|
}
|
2018-01-17 13:14:21 +02:00
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
auto parenExpr = dyn_cast<ParenExpr>(ifStmt->getThen());
|
|
|
|
if (parenExpr)
|
|
|
|
{
|
|
|
|
CheckParenExpr(methodDecl, parenExpr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ifThenCompoundStmt = dyn_cast<CompoundStmt>(ifStmt->getThen());
|
|
|
|
if (!ifThenCompoundStmt)
|
|
|
|
return;
|
|
|
|
for (auto j = ifThenCompoundStmt->body_begin(); j != ifThenCompoundStmt->body_end(); ++j)
|
|
|
|
{
|
|
|
|
auto ifDeleteExpr = dyn_cast<CXXDeleteExpr>(*j);
|
|
|
|
if (ifDeleteExpr)
|
|
|
|
CheckDeleteExpr(methodDecl, ifDeleteExpr);
|
|
|
|
ParenExpr const * parenExpr = dyn_cast<ParenExpr>(*j);
|
2018-04-24 14:04:53 +02:00
|
|
|
if (parenExpr)
|
|
|
|
CheckParenExpr(methodDecl, parenExpr);
|
2018-01-10 11:29:36 +02:00
|
|
|
}
|
2017-01-11 14:19:47 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
void UseUniquePtr::CheckDeleteExpr(const CXXMethodDecl* methodDecl, const CXXDeleteExpr* deleteExpr)
|
2018-01-10 16:23:41 +02:00
|
|
|
{
|
2018-08-16 13:46:39 +02:00
|
|
|
auto deleteExprArg = deleteExpr->getArgument()->IgnoreParenImpCasts();
|
|
|
|
|
|
|
|
const MemberExpr* memberExpr = dyn_cast<MemberExpr>(deleteExprArg);
|
|
|
|
if (memberExpr)
|
|
|
|
{
|
|
|
|
CheckDeleteExpr(methodDecl, deleteExpr, memberExpr,
|
|
|
|
"unconditional call to delete on a member, should be using std::unique_ptr");
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
2018-08-16 13:46:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const ArraySubscriptExpr* arrayExpr = dyn_cast<ArraySubscriptExpr>(deleteExprArg);
|
|
|
|
if (arrayExpr)
|
|
|
|
{
|
|
|
|
auto baseMemberExpr = dyn_cast<MemberExpr>(arrayExpr->getBase()->IgnoreParenImpCasts());
|
|
|
|
if (baseMemberExpr)
|
|
|
|
CheckDeleteExpr(methodDecl, deleteExpr, baseMemberExpr,
|
|
|
|
"unconditional call to delete on a member, should be using std::unique_ptr");
|
|
|
|
}
|
2018-01-17 13:14:21 +02:00
|
|
|
}
|
2018-01-10 16:23:41 +02:00
|
|
|
|
2018-04-24 14:04:53 +02:00
|
|
|
/**
|
|
|
|
* Look for DELETEZ expressions.
|
|
|
|
*/
|
|
|
|
void UseUniquePtr::CheckParenExpr(const CXXMethodDecl* methodDecl, const ParenExpr* parenExpr)
|
|
|
|
{
|
|
|
|
auto binaryOp = dyn_cast<BinaryOperator>(parenExpr->getSubExpr());
|
|
|
|
if (!binaryOp || binaryOp->getOpcode() != BO_Comma)
|
|
|
|
return;
|
|
|
|
auto deleteExpr = dyn_cast<CXXDeleteExpr>(binaryOp->getLHS());
|
|
|
|
if (!deleteExpr)
|
|
|
|
return;
|
|
|
|
CheckDeleteExpr(methodDecl, deleteExpr);
|
|
|
|
}
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
void UseUniquePtr::CheckDeleteExpr(const CXXMethodDecl* methodDecl, const CXXDeleteExpr* deleteExpr,
|
2018-01-17 13:14:21 +02:00
|
|
|
const MemberExpr* memberExpr, StringRef message)
|
|
|
|
{
|
2018-01-10 16:23:41 +02:00
|
|
|
// ignore union games
|
2018-01-17 13:14:21 +02:00
|
|
|
const FieldDecl* fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
|
|
|
|
if (!fieldDecl)
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
2018-01-17 13:14:21 +02:00
|
|
|
TagDecl const * td = dyn_cast<TagDecl>(fieldDecl->getDeclContext());
|
2018-01-10 16:23:41 +02:00
|
|
|
if (td->isUnion())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// ignore calling delete on someone else's field
|
2018-04-12 11:23:58 +02:00
|
|
|
if (fieldDecl->getParent() != methodDecl->getParent() )
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
|
2018-01-17 13:14:21 +02:00
|
|
|
if (ignoreLocation(fieldDecl))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// to ignore things like the CPPUNIT macros
|
2018-05-29 11:28:07 +02:00
|
|
|
StringRef aFileName = getFileNameOfSpellingLoc(
|
2018-08-10 12:35:21 +02:00
|
|
|
compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(fieldDecl)));
|
2018-03-26 13:37:06 +02:00
|
|
|
if (loplugin::hasPathnamePrefix(aFileName, WORKDIR "/"))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// passes and stores pointers to member fields
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/sot/source/sdstor/stgdir.hxx"))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// something platform-specific
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/hwpfilter/source/htags.h"))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// passes pointers to member fields
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/sd/inc/sdpptwrp.hxx"))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// @TODO intrusive linked-lists here, with some trickiness
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/sw/source/filter/html/parcss1.hxx"))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// @TODO SwDoc has some weird ref-counting going on
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/sw/inc/shellio.hxx"))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// @TODO it's sharing pointers with another class
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/sc/inc/formulacell.hxx"))
|
2018-01-10 16:23:41 +02:00
|
|
|
return;
|
|
|
|
// some weird stuff going on here around struct Entity
|
|
|
|
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sax/"))
|
|
|
|
return;
|
|
|
|
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/include/sax/"))
|
|
|
|
return;
|
|
|
|
// manipulation of tree structures ie. StgAvlNode, don't lend themselves to std::unique_ptr
|
|
|
|
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sot/"))
|
|
|
|
return;
|
|
|
|
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/include/sot/"))
|
|
|
|
return;
|
2018-01-17 13:14:21 +02:00
|
|
|
// the std::vector is being passed to another class
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/sfx2/source/explorer/nochaos.cxx"))
|
2018-01-17 13:14:21 +02:00
|
|
|
return;
|
|
|
|
auto tc = loplugin::TypeCheck(fieldDecl->getType());
|
2018-06-26 14:07:28 +02:00
|
|
|
// these sw::Ring based classes do not lend themselves to std::unique_ptr management
|
|
|
|
if (tc.Pointer().Class("SwNodeIndex").GlobalNamespace() || tc.Pointer().Class("SwShellTableCursor").GlobalNamespace()
|
|
|
|
|| tc.Pointer().Class("SwBlockCursor").GlobalNamespace() || tc.Pointer().Class("SwVisibleCursor").GlobalNamespace()
|
|
|
|
|| tc.Pointer().Class("SwShellCursor").GlobalNamespace())
|
|
|
|
return;
|
2018-01-17 13:14:21 +02:00
|
|
|
// there is a loop in ~ImplPrnQueueList deleting stuff on a global data structure
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/vcl/inc/print.h"))
|
2018-01-17 13:14:21 +02:00
|
|
|
return;
|
|
|
|
// painful linked list
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/basic/source/inc/runtime.hxx"))
|
2018-01-17 13:14:21 +02:00
|
|
|
return;
|
2018-01-22 14:04:06 +02:00
|
|
|
// not sure how the node management is working here
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/i18npool/source/localedata/saxparser.cxx"))
|
2018-01-22 14:04:06 +02:00
|
|
|
return;
|
2018-01-29 12:13:56 +02:00
|
|
|
// has a pointer that it only sometimes owns
|
2018-03-26 13:26:46 +02:00
|
|
|
if (loplugin::isSamePathname(aFileName, SRCDIR "/editeng/source/editeng/impedit.hxx"))
|
2018-01-29 12:13:56 +02:00
|
|
|
return;
|
2018-01-10 16:23:41 +02:00
|
|
|
|
|
|
|
report(
|
|
|
|
DiagnosticsEngine::Warning,
|
2018-01-17 13:14:21 +02:00
|
|
|
message,
|
2018-08-10 12:35:21 +02:00
|
|
|
compat::getBeginLoc(deleteExpr))
|
2018-01-10 16:23:41 +02:00
|
|
|
<< deleteExpr->getSourceRange();
|
|
|
|
report(
|
|
|
|
DiagnosticsEngine::Note,
|
|
|
|
"member is here",
|
2018-08-10 12:35:21 +02:00
|
|
|
compat::getBeginLoc(fieldDecl))
|
2018-01-17 13:14:21 +02:00
|
|
|
<< fieldDecl->getSourceRange();
|
2018-01-10 16:23:41 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
void UseUniquePtr::CheckLoopDelete(const CXXMethodDecl* methodDecl, const Stmt* bodyStmt)
|
2017-08-23 08:49:02 +02:00
|
|
|
{
|
2018-01-17 13:14:21 +02:00
|
|
|
if (auto deleteExpr = dyn_cast<CXXDeleteExpr>(bodyStmt))
|
2018-04-12 11:23:58 +02:00
|
|
|
CheckLoopDelete(methodDecl, deleteExpr);
|
2018-01-17 13:14:21 +02:00
|
|
|
else if (auto compoundStmt = dyn_cast<CompoundStmt>(bodyStmt))
|
2017-08-23 08:49:02 +02:00
|
|
|
{
|
2018-01-17 13:14:21 +02:00
|
|
|
for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
|
2017-08-23 08:49:02 +02:00
|
|
|
{
|
2018-01-17 13:14:21 +02:00
|
|
|
if (auto deleteExpr = dyn_cast<CXXDeleteExpr>(*i))
|
2018-04-12 11:23:58 +02:00
|
|
|
CheckLoopDelete(methodDecl, deleteExpr);
|
2017-08-23 08:49:02 +02:00
|
|
|
}
|
2018-01-10 11:29:36 +02:00
|
|
|
}
|
2017-08-23 08:49:02 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
void UseUniquePtr::CheckLoopDelete(const CXXMethodDecl* methodDecl, const CXXDeleteExpr* deleteExpr)
|
2017-08-23 08:49:02 +02:00
|
|
|
{
|
2018-01-17 13:14:21 +02:00
|
|
|
const MemberExpr* memberExpr = nullptr;
|
|
|
|
const Expr* subExpr = deleteExpr->getArgument();
|
2018-08-16 13:46:39 +02:00
|
|
|
// drill down looking for a MemberExpr
|
2018-01-17 13:14:21 +02:00
|
|
|
for (;;)
|
2018-01-10 11:29:36 +02:00
|
|
|
{
|
2018-01-17 13:14:21 +02:00
|
|
|
subExpr = subExpr->IgnoreImpCasts();
|
|
|
|
if ((memberExpr = dyn_cast<MemberExpr>(subExpr)))
|
|
|
|
break;
|
|
|
|
else if (auto arraySubscriptExpr = dyn_cast<ArraySubscriptExpr>(subExpr))
|
|
|
|
subExpr = arraySubscriptExpr->getBase();
|
|
|
|
else if (auto cxxOperatorCallExpr = dyn_cast<CXXOperatorCallExpr>(subExpr))
|
|
|
|
{
|
2018-08-16 13:46:39 +02:00
|
|
|
// look for deletes of an iterator object where the iterator is over a member field
|
|
|
|
if (auto declRefExpr = dyn_cast<DeclRefExpr>(cxxOperatorCallExpr->getArg(0)->IgnoreImpCasts()))
|
|
|
|
{
|
|
|
|
if (auto varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl()))
|
|
|
|
{
|
|
|
|
auto init = varDecl->getInit();
|
|
|
|
if (auto x = dyn_cast<ExprWithCleanups>(init))
|
|
|
|
init = x->getSubExpr();
|
|
|
|
if (auto x = dyn_cast<CXXBindTemporaryExpr>(init))
|
|
|
|
init = x->getSubExpr();
|
|
|
|
if (auto x = dyn_cast<CXXMemberCallExpr>(init))
|
|
|
|
init = x->getImplicitObjectArgument();
|
|
|
|
memberExpr = dyn_cast<MemberExpr>(init);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// look for deletes like "delete m_pField[0]"
|
2018-01-17 13:14:21 +02:00
|
|
|
if (cxxOperatorCallExpr->getOperator() == OO_Subscript)
|
|
|
|
{
|
|
|
|
memberExpr = dyn_cast<MemberExpr>(cxxOperatorCallExpr->getArg(0));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2018-01-15 14:56:29 +02:00
|
|
|
else
|
2018-01-17 13:14:21 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!memberExpr)
|
|
|
|
return;
|
2018-01-10 11:29:36 +02:00
|
|
|
|
2018-09-03 09:58:12 +02:00
|
|
|
std::string fn(handler.getMainFileName());
|
|
|
|
loplugin::normalizeDotDotInFilePath(fn);
|
|
|
|
// OStorage_Impl::Commit very complicated ownership passing going on
|
|
|
|
if (fn == SRCDIR "/package/source/xstor/xstorage.cxx")
|
|
|
|
return;
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
CheckDeleteExpr(methodDecl, deleteExpr, memberExpr, "rather manage with std::some_container<std::unique_ptr<T>>");
|
2018-01-17 13:14:21 +02:00
|
|
|
}
|
2018-01-10 11:29:36 +02:00
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
void UseUniquePtr::CheckCXXForRangeStmt(const CXXMethodDecl* methodDecl, const CXXForRangeStmt* cxxForRangeStmt)
|
2018-01-17 13:14:21 +02:00
|
|
|
{
|
|
|
|
CXXDeleteExpr const * deleteExpr = nullptr;
|
|
|
|
if (auto compoundStmt = dyn_cast<CompoundStmt>(cxxForRangeStmt->getBody()))
|
2018-08-16 13:46:39 +02:00
|
|
|
{
|
|
|
|
for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
|
|
|
|
if ((deleteExpr = dyn_cast<CXXDeleteExpr>(*i)))
|
|
|
|
break;
|
|
|
|
}
|
2018-01-17 13:14:21 +02:00
|
|
|
else
|
|
|
|
deleteExpr = dyn_cast<CXXDeleteExpr>(cxxForRangeStmt->getBody());
|
|
|
|
if (!deleteExpr)
|
|
|
|
return;
|
|
|
|
auto memberExpr = dyn_cast<MemberExpr>(cxxForRangeStmt->getRangeInit());
|
|
|
|
if (!memberExpr)
|
|
|
|
return;
|
|
|
|
auto fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
|
|
|
|
if (!fieldDecl)
|
|
|
|
return;
|
2018-01-10 11:29:36 +02:00
|
|
|
|
2018-09-03 09:58:12 +02:00
|
|
|
std::string fn(handler.getMainFileName());
|
|
|
|
loplugin::normalizeDotDotInFilePath(fn);
|
|
|
|
// appears to just randomly leak stuff, and it involves some lex/yacc stuff
|
|
|
|
if (fn == SRCDIR "/idlc/source/aststack.cxx")
|
|
|
|
return;
|
|
|
|
|
2018-04-12 11:23:58 +02:00
|
|
|
CheckDeleteExpr(methodDecl, deleteExpr, memberExpr, "rather manage with std::some_container<std::unique_ptr<T>>");
|
2017-08-23 08:49:02 +02:00
|
|
|
}
|
|
|
|
|
2017-01-31 14:46:38 +02:00
|
|
|
bool UseUniquePtr::VisitCompoundStmt(const CompoundStmt* compoundStmt)
|
|
|
|
{
|
|
|
|
if (ignoreLocation(compoundStmt))
|
|
|
|
return true;
|
2018-08-10 12:35:21 +02:00
|
|
|
if (isInUnoIncludeFile(compat::getBeginLoc(compoundStmt)))
|
2017-01-31 14:46:38 +02:00
|
|
|
return true;
|
|
|
|
if (compoundStmt->size() == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-06 09:46:06 +02:00
|
|
|
auto lastStmt = compoundStmt->body_back();
|
|
|
|
if (compoundStmt->size() > 1) {
|
|
|
|
if (isa<ReturnStmt>(lastStmt))
|
|
|
|
lastStmt = *(++compoundStmt->body_rbegin());
|
|
|
|
}
|
|
|
|
auto deleteExpr = dyn_cast<CXXDeleteExpr>(lastStmt);
|
2017-01-31 14:46:38 +02:00
|
|
|
if (deleteExpr == nullptr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
auto declRefExpr = dyn_cast<DeclRefExpr>(deleteExpr->getArgument()->IgnoreParenImpCasts());
|
2017-01-31 14:46:38 +02:00
|
|
|
if (!declRefExpr)
|
|
|
|
return true;
|
2017-04-06 09:46:06 +02:00
|
|
|
auto varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl());
|
2017-01-31 14:46:38 +02:00
|
|
|
if (!varDecl)
|
|
|
|
return true;
|
2017-04-06 15:20:15 +02:00
|
|
|
if (!varDecl->hasInit()
|
|
|
|
|| !isa<CXXNewExpr>(
|
|
|
|
varDecl->getInit()->IgnoreImplicit()->IgnoreParenImpCasts()))
|
2017-01-31 14:46:38 +02:00
|
|
|
return true;
|
|
|
|
// determine if the var is declared inside the same block as the delete.
|
|
|
|
// @TODO there should surely be a better way to do this
|
2018-08-10 12:35:21 +02:00
|
|
|
if (compat::getBeginLoc(varDecl) < compat::getBeginLoc(compoundStmt))
|
2017-01-31 14:46:38 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
report(
|
|
|
|
DiagnosticsEngine::Warning,
|
|
|
|
"deleting a local variable at the end of a block, is a sure sign it should be using std::unique_ptr for that var",
|
2018-08-10 12:35:21 +02:00
|
|
|
compat::getBeginLoc(deleteExpr))
|
2017-01-31 14:46:38 +02:00
|
|
|
<< deleteExpr->getSourceRange();
|
|
|
|
report(
|
|
|
|
DiagnosticsEngine::Note,
|
|
|
|
"var is here",
|
2018-08-10 12:35:21 +02:00
|
|
|
compat::getBeginLoc(varDecl))
|
2017-01-31 14:46:38 +02:00
|
|
|
<< varDecl->getSourceRange();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-21 15:32:52 +02:00
|
|
|
bool UseUniquePtr::TraverseFunctionDecl(FunctionDecl* functionDecl)
|
|
|
|
{
|
|
|
|
if (ignoreLocation(functionDecl))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
auto oldCurrent = mpCurrentFunctionDecl;
|
|
|
|
mpCurrentFunctionDecl = functionDecl;
|
|
|
|
bool ret = RecursiveASTVisitor::TraverseFunctionDecl(functionDecl);
|
|
|
|
mpCurrentFunctionDecl = oldCurrent;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
bool UseUniquePtr::TraverseCXXMethodDecl(CXXMethodDecl* methodDecl)
|
|
|
|
{
|
|
|
|
if (ignoreLocation(methodDecl))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
auto oldCurrent = mpCurrentFunctionDecl;
|
|
|
|
mpCurrentFunctionDecl = methodDecl;
|
|
|
|
bool ret = RecursiveASTVisitor::TraverseCXXMethodDecl(methodDecl);
|
|
|
|
mpCurrentFunctionDecl = oldCurrent;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UseUniquePtr::TraverseCXXConstructorDecl(CXXConstructorDecl* methodDecl)
|
|
|
|
{
|
|
|
|
if (ignoreLocation(methodDecl))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
auto oldCurrent = mpCurrentFunctionDecl;
|
|
|
|
mpCurrentFunctionDecl = methodDecl;
|
|
|
|
bool ret = RecursiveASTVisitor::TraverseCXXConstructorDecl(methodDecl);
|
|
|
|
mpCurrentFunctionDecl = oldCurrent;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-21 15:32:52 +02:00
|
|
|
bool UseUniquePtr::VisitCXXDeleteExpr(const CXXDeleteExpr* deleteExpr)
|
|
|
|
{
|
|
|
|
if (!mpCurrentFunctionDecl)
|
|
|
|
return true;
|
|
|
|
if (ignoreLocation(mpCurrentFunctionDecl))
|
|
|
|
return true;
|
2018-08-10 12:35:21 +02:00
|
|
|
if (isInUnoIncludeFile(compat::getBeginLoc(mpCurrentFunctionDecl->getCanonicalDecl())))
|
2018-06-21 15:32:52 +02:00
|
|
|
return true;
|
|
|
|
if (mpCurrentFunctionDecl->getIdentifier())
|
|
|
|
{
|
|
|
|
auto name = mpCurrentFunctionDecl->getName();
|
|
|
|
if (name == "delete_IncludesCollection" || name == "convertName"
|
|
|
|
|| name == "createNamedType"
|
|
|
|
|| name == "typelib_typedescriptionreference_release" || name == "deleteExceptions"
|
|
|
|
|| name == "uno_threadpool_destroy"
|
|
|
|
|| name == "AddRanges_Impl"
|
|
|
|
|| name == "DestroySalInstance"
|
|
|
|
|| name == "ImplHandleUserEvent"
|
|
|
|
|| name == "releaseDecimalPtr" // TODO, basic
|
|
|
|
|| name == "replaceAndReset" // TODO, connectivity
|
|
|
|
|| name == "intrusive_ptr_release"
|
|
|
|
|| name == "FreeParaList"
|
|
|
|
|| name == "DeleteSdrUndoAction" // TODO, sc
|
|
|
|
|| name == "lcl_MergeGCBox" || name == "lcl_MergeGCLine" || name == "lcl_DelHFFormat")
|
|
|
|
return true;
|
|
|
|
}
|
2018-08-16 13:46:39 +02:00
|
|
|
if (auto cxxMethodDecl = dyn_cast<CXXMethodDecl>(mpCurrentFunctionDecl))
|
|
|
|
{
|
|
|
|
// include/o3tl/deleter.hxx
|
|
|
|
if (cxxMethodDecl->getParent()->getName() == "default_delete")
|
|
|
|
return true;
|
|
|
|
// TODO Bitmap::ReleaseAccess
|
|
|
|
// Tricky because it reverberates through other code and requires that BitmapWriteAccess move into /include again
|
|
|
|
if (cxxMethodDecl->getParent()->getName() == "Bitmap")
|
|
|
|
return true;
|
|
|
|
// TODO virtual ones are much trickier, leave for later
|
|
|
|
if (cxxMethodDecl->isVirtual())
|
|
|
|
return true;
|
|
|
|
// sw/inc/unobaseclass.hxx holds SolarMutex while deleting
|
|
|
|
if (cxxMethodDecl->getParent()->getName() == "UnoImplPtrDeleter")
|
|
|
|
return true;
|
|
|
|
}
|
2018-06-21 15:32:52 +02:00
|
|
|
|
|
|
|
auto declRefExpr = dyn_cast<DeclRefExpr>(deleteExpr->getArgument()->IgnoreParenImpCasts());
|
|
|
|
if (!declRefExpr)
|
|
|
|
return true;
|
|
|
|
auto varDecl = dyn_cast<ParmVarDecl>(declRefExpr->getDecl());
|
|
|
|
if (!varDecl)
|
|
|
|
return true;
|
|
|
|
|
2018-08-16 13:46:39 +02:00
|
|
|
std::string fn(handler.getMainFileName());
|
|
|
|
loplugin::normalizeDotDotInFilePath(fn);
|
|
|
|
|
|
|
|
// StgAvlNode::Remove
|
|
|
|
if (fn == SRCDIR "/sot/source/sdstor/stgavl.cxx")
|
|
|
|
return true;
|
|
|
|
// SfxItemPool::ReleaseDefaults and SfxItemPool::Free
|
|
|
|
if (fn == SRCDIR "/svl/source/items/itempool.cxx")
|
|
|
|
return true;
|
|
|
|
// SwContourCache
|
|
|
|
if (fn == SRCDIR "/sw/source/core/text/txtfly.cxx")
|
|
|
|
return true;
|
|
|
|
// too messy to cope with the SQL parser
|
|
|
|
if (fn == SRCDIR "/connectivity/source/parse/sqlnode.cxx")
|
|
|
|
return true;
|
|
|
|
// I can't figure out the ownership of the SfxMedium in the call site(s)
|
|
|
|
if (fn == SRCDIR "/sfx2/source/doc/sfxbasemodel.cxx")
|
|
|
|
return true;
|
|
|
|
// pointer passed via IMPL_LINK
|
|
|
|
if (fn == SRCDIR "/sfx2/source/control/dispatch.cxx")
|
|
|
|
return true;
|
|
|
|
// NavigatorTreeModel::Remove
|
|
|
|
if (fn == SRCDIR "/svx/source/form/navigatortreemodel.cxx")
|
|
|
|
return true;
|
|
|
|
// SdrModel::AddUndo
|
|
|
|
if (fn == SRCDIR "/svx/source/svdraw/svdmodel.cxx")
|
|
|
|
return true;
|
|
|
|
// undo callback
|
|
|
|
if (fn == SRCDIR "/basctl/source/basicide/baside3.cxx")
|
|
|
|
return true;
|
|
|
|
// ActualizeProgress::TimeoutHdl
|
|
|
|
if (fn == SRCDIR "/cui/source/dialogs/cuigaldlg.cxx")
|
|
|
|
return true;
|
|
|
|
// ToolbarSaveInData::RemoveToolbar
|
|
|
|
if (fn == SRCDIR "/cui/source/customize/cfg.cxx")
|
|
|
|
return true;
|
|
|
|
// OStorage_Impl::RemoveElement very complicated ownership passing going on
|
|
|
|
if (fn == SRCDIR "/package/source/xstor/xstorage.cxx")
|
|
|
|
return true;
|
|
|
|
// actually held via shared_ptr, uses protected deleter object
|
|
|
|
if (fn == SRCDIR "/sd/source/ui/framework/tools/FrameworkHelper.cxx")
|
|
|
|
return true;
|
|
|
|
// actually held via shared_ptr, uses protected deleter object
|
|
|
|
if (fn == SRCDIR "/sd/source/ui/presenter/CanvasUpdateRequester.cxx")
|
|
|
|
return true;
|
|
|
|
// actually held via shared_ptr, uses protected deleter object
|
|
|
|
if (fn == SRCDIR "/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx")
|
|
|
|
return true;
|
|
|
|
// actually held via shared_ptr, uses protected deleter object
|
|
|
|
if (fn == SRCDIR "/sd/source/ui/sidebar/MasterPageContainer.cxx")
|
|
|
|
return true;
|
|
|
|
// actually held via shared_ptr, uses protected deleter object
|
|
|
|
if (fn == SRCDIR "/sd/source/ui/tools/TimerBasedTaskExecution.cxx")
|
|
|
|
return true;
|
|
|
|
// actually held via shared_ptr, uses protected deleter object
|
|
|
|
if (fn == SRCDIR "/sd/source/ui/view/ViewShellImplementation.cxx")
|
|
|
|
return true;
|
|
|
|
// ScBroadcastAreaSlot::StartListeningArea manual ref-counting of ScBroadcastArea
|
|
|
|
if (fn == SRCDIR "/sc/source/core/data/bcaslot.cxx")
|
|
|
|
return true;
|
|
|
|
// ScDrawLayer::AddCalcUndo undo stuff
|
|
|
|
if (fn == SRCDIR "/sc/source/core/data/drwlayer.cxx")
|
|
|
|
return true;
|
|
|
|
// ScTable::SetFormulaCell
|
|
|
|
if (fn == SRCDIR "/sc/source/core/data/table2.cxx")
|
|
|
|
return true;
|
|
|
|
// ScDocument::SetFormulaCell
|
|
|
|
if (fn == SRCDIR "/sc/source/core/data/documen2.cxx")
|
|
|
|
return true;
|
|
|
|
// RemoveEditAttribsHandler, stored in mdds block
|
|
|
|
if (fn == SRCDIR "/sc/source/core/data/column2.cxx")
|
|
|
|
return true;
|
|
|
|
// just turns into a mess
|
|
|
|
if (fn == SRCDIR "/sc/source/ui/Accessibility/AccessibleDocument.cxx")
|
|
|
|
return true;
|
|
|
|
// SwCache::DeleteObj, linked list
|
|
|
|
if (fn == SRCDIR "/sw/source/core/bastyp/swcache.cxx")
|
|
|
|
return true;
|
|
|
|
// SAXEventKeeperImpl::smashBufferNode
|
|
|
|
if (fn == SRCDIR "/xmlsecurity/source/framework/saxeventkeeperimpl.cxx")
|
|
|
|
return true;
|
|
|
|
// SwDoc::DeleteExtTextInput
|
|
|
|
if (fn == SRCDIR "/sw/source/core/doc/extinput.cxx")
|
|
|
|
return true;
|
|
|
|
// SwDoc::DelSectionFormat
|
|
|
|
if (fn == SRCDIR "/sw/source/core/docnode/ndsect.cxx")
|
|
|
|
return true;
|
|
|
|
// SwFrame::DestroyFrame
|
|
|
|
if (fn == SRCDIR "/sw/source/core/layout/ssfrm.cxx")
|
|
|
|
return true;
|
|
|
|
// SwGluePortion::Join
|
|
|
|
if (fn == SRCDIR "/sw/source/core/text/porglue.cxx")
|
|
|
|
return true;
|
|
|
|
// SwDoc::DelFrameFormat
|
|
|
|
if (fn == SRCDIR "/sw/source/core/doc/docfmt.cxx")
|
|
|
|
return true;
|
|
|
|
// SwTextAttr::Destroy
|
|
|
|
if (fn == SRCDIR "/sw/source/core/txtnode/txatbase.cxx")
|
|
|
|
return true;
|
|
|
|
// IMPL_LINK( SwDoc, AddDrawUndo, SdrUndoAction *, pUndo, void )
|
|
|
|
if (fn == SRCDIR "/sw/source/core/undo/undraw.cxx")
|
|
|
|
return true;
|
|
|
|
// SwHTMLParser::EndAttr
|
|
|
|
if (fn == SRCDIR "/sw/source/filter/html/swhtml.cxx")
|
|
|
|
return true;
|
|
|
|
// SwGlossaryHdl::Expand sometimes the pointer is owned, sometimes it is not
|
|
|
|
if (fn == SRCDIR "/sw/source/uibase/dochdl/gloshdl.cxx")
|
|
|
|
return true;
|
|
|
|
// SwWrtShell::Insert only owned sometimes
|
|
|
|
if (fn == SRCDIR "/sw/source/uibase/wrtsh/wrtsh1.cxx")
|
|
|
|
return true;
|
|
|
|
// NodeArrayDeleter
|
|
|
|
if (fn == SRCDIR "/unoxml/source/rdf/librdf_repository.cxx")
|
|
|
|
return true;
|
2018-08-29 21:50:24 +02:00
|
|
|
// SmCursor::LineToList ran out of enthusiasm to rework the node handling
|
2018-08-16 13:46:39 +02:00
|
|
|
if (fn == SRCDIR "/starmath/source/cursor.cxx")
|
|
|
|
return true;
|
|
|
|
// XMLEventOASISTransformerContext::FlushEventMap
|
|
|
|
if (fn == SRCDIR "/xmloff/source/transform/EventOASISTContext.cxx")
|
|
|
|
return true;
|
|
|
|
// XMLEventOOoTransformerContext::FlushEventMap
|
|
|
|
if (fn == SRCDIR "/xmloff/source/transform/EventOOoTContext.cxx")
|
|
|
|
return true;
|
|
|
|
|
2018-06-21 15:32:52 +02:00
|
|
|
/*
|
|
|
|
Sometimes we can pass the param as std::unique_ptr<T>& or std::unique_ptr, sometimes the method
|
|
|
|
just needs to be inlined, which normally exposes more simplification.
|
|
|
|
*/
|
|
|
|
report(
|
|
|
|
DiagnosticsEngine::Warning,
|
2018-08-16 13:46:39 +02:00
|
|
|
"calling delete on a pointer param, should be either whitelisted or simplified",
|
2018-08-10 12:35:21 +02:00
|
|
|
compat::getBeginLoc(deleteExpr))
|
2018-06-21 15:32:52 +02:00
|
|
|
<< deleteExpr->getSourceRange();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-08-17 14:40:29 +02:00
|
|
|
bool UseUniquePtr::TraverseConstructorInitializer(CXXCtorInitializer * ctorInit)
|
|
|
|
{
|
|
|
|
if (!ctorInit->getSourceLocation().isValid() || ignoreLocation(ctorInit->getSourceLocation()))
|
|
|
|
return true;
|
|
|
|
if (!ctorInit->getMember())
|
|
|
|
return true;
|
|
|
|
if (!loplugin::TypeCheck(ctorInit->getMember()->getType()).Class("unique_ptr").StdNamespace())
|
|
|
|
return true;
|
2018-09-03 09:58:12 +02:00
|
|
|
auto constructExpr = dyn_cast_or_null<CXXConstructExpr>(ctorInit->getInit());
|
|
|
|
if (!constructExpr || constructExpr->getNumArgs() == 0)
|
2018-08-17 14:40:29 +02:00
|
|
|
return true;
|
|
|
|
auto init = constructExpr->getArg(0)->IgnoreImpCasts();
|
|
|
|
if (!isa<DeclRefExpr>(init))
|
|
|
|
return true;
|
2018-09-03 09:58:12 +02:00
|
|
|
|
|
|
|
StringRef fn = getFileNameOfSpellingLoc(compiler.getSourceManager().getSpellingLoc(ctorInit->getSourceLocation()));
|
|
|
|
// don't feel like fiddling with the yacc parser
|
|
|
|
if (loplugin::hasPathnamePrefix(fn, SRCDIR "/idlc/"))
|
|
|
|
return true;
|
|
|
|
// cannot change URE
|
|
|
|
if (loplugin::hasPathnamePrefix(fn, SRCDIR "/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
2018-08-17 14:40:29 +02:00
|
|
|
report(
|
|
|
|
DiagnosticsEngine::Warning,
|
|
|
|
"should be passing via std::unique_ptr param",
|
|
|
|
ctorInit->getSourceLocation())
|
|
|
|
<< ctorInit->getSourceRange();
|
|
|
|
return RecursiveASTVisitor<UseUniquePtr>::TraverseConstructorInitializer(ctorInit);
|
|
|
|
}
|
|
|
|
|
2018-01-10 11:29:36 +02:00
|
|
|
loplugin::Plugin::Registration< UseUniquePtr > X("useuniqueptr", false);
|
2017-01-11 14:19:47 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|