Kaydet (Commit) 05a337e2 authored tarafından Noel Grandin's avatar Noel Grandin

loplugin:useuniqueptr look for deleting in loops with iterators

Change-Id: I0e5bf671ee11265c0afa8770430ec9e064e05fe3
Reviewed-on: https://gerrit.libreoffice.org/61402
Tested-by: Jenkins
Reviewed-by: 's avatarNoel Grandin <noel.grandin@collabora.co.uk>
üst 67405c33
......@@ -96,7 +96,7 @@ class Class8 {
std::unordered_map<int, int*> m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}}
~Class8()
{
for (auto i : m_pbar)
for (auto & i : m_pbar)
delete i.second; // expected-error {{rather manage this with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}}
}
};
......@@ -250,8 +250,51 @@ namespace foo20
}
};
// ------------------------------------------------------------------------------------------------
// tests for deleting when looping via iterators
// ------------------------------------------------------------------------------------------------
void foo21()
{
std::vector<bool*> vec; // expected-note {{var is here [loplugin:useuniqueptr]}}
for(auto it = vec.begin(); it != vec.end(); ++it)
delete *it; // expected-error {{rather manage this var with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}}
}
void foo22()
{
std::unordered_map<int, float*> map; // expected-note {{var is here [loplugin:useuniqueptr]}}
for(auto it = map.begin(); it != map.end(); ++it)
delete it->second; // expected-error {{rather manage this var with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}}
}
class Foo23
{
std::unordered_map<int, float*> map; // expected-note {{member is here [loplugin:useuniqueptr]}}
~Foo23()
{
for(auto it = map.begin(); it != map.end(); ++it)
delete it->second; // expected-error {{rather manage with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}}
}
};
#if CLANG_VERSION >= 50000
class Foo24
{
typedef std::vector<int*> HTMLAttrs;
HTMLAttrs m_aSetAttrTab; // expected-note {{member is here [loplugin:useuniqueptr]}}
~Foo24()
{
for ( HTMLAttrs::const_iterator it = m_aSetAttrTab.begin(); it != m_aSetAttrTab.end(); ++it )
delete *it; // expected-error {{rather manage with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}}
}
};
#endif
// ------------------------------------------------------------------------------------------------
// tests for passing owning pointers to constructors
// ------------------------------------------------------------------------------------------------
class Bravo1
{
......@@ -268,4 +311,5 @@ class Bravo2
{}
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
......@@ -124,11 +124,15 @@ public:
}
bool VisitFunctionDecl(const FunctionDecl* );
bool VisitCompoundStmt(const CompoundStmt* );
bool VisitCXXDeleteExpr(const CXXDeleteExpr* );
bool TraverseFunctionDecl(FunctionDecl* );
#if CLANG_VERSION >= 50000
bool TraverseCXXDeductionGuideDecl(CXXDeductionGuideDecl* );
#endif
bool TraverseCXXMethodDecl(CXXMethodDecl* );
bool TraverseCXXConstructorDecl(CXXConstructorDecl* );
bool TraverseCXXConversionDecl(CXXConversionDecl* );
bool TraverseCXXDestructorDecl(CXXDestructorDecl* );
bool TraverseConstructorInitializer(CXXCtorInitializer*);
private:
......@@ -139,7 +143,7 @@ private:
void CheckLoopDelete(const FunctionDecl*, const CXXDeleteExpr* );
void CheckDeleteExpr(const FunctionDecl*, const CXXDeleteExpr*);
void CheckParenExpr(const FunctionDecl*, const ParenExpr*);
void CheckDeleteExpr(const FunctionDecl*, const CXXDeleteExpr*,
void CheckMemberDeleteExpr(const FunctionDecl*, const CXXDeleteExpr*,
const MemberExpr*, StringRef message);
FunctionDecl const * mpCurrentFunctionDecl = nullptr;
std::string fn;
......@@ -270,7 +274,7 @@ void UseUniquePtr::CheckDeleteExpr(const FunctionDecl* functionDecl, const CXXDe
if (fn == SRCDIR "/sc/source/filter/html/htmlpars.cxx")
return;
CheckDeleteExpr(functionDecl, deleteExpr, memberExpr,
CheckMemberDeleteExpr(functionDecl, deleteExpr, memberExpr,
"unconditional call to delete on a member, should be using std::unique_ptr");
return;
}
......@@ -422,7 +426,7 @@ void UseUniquePtr::CheckDeleteExpr(const FunctionDecl* functionDecl, const CXXDe
{
auto baseMemberExpr = dyn_cast<MemberExpr>(arrayExpr->getBase()->IgnoreParenImpCasts());
if (baseMemberExpr)
CheckDeleteExpr(functionDecl, deleteExpr, baseMemberExpr,
CheckMemberDeleteExpr(functionDecl, deleteExpr, baseMemberExpr,
"unconditional call to delete on an array member, should be using std::unique_ptr");
}
}
......@@ -441,89 +445,6 @@ void UseUniquePtr::CheckParenExpr(const FunctionDecl* functionDecl, const ParenE
CheckDeleteExpr(functionDecl, deleteExpr);
}
void UseUniquePtr::CheckDeleteExpr(const FunctionDecl* functionDecl, const CXXDeleteExpr* deleteExpr,
const MemberExpr* memberExpr, StringRef message)
{
// ignore union games
const FieldDecl* fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
if (!fieldDecl)
return;
TagDecl const * td = dyn_cast<TagDecl>(fieldDecl->getDeclContext());
if (td->isUnion())
return;
// ignore calling delete on someone else's field
if (auto methodDecl = dyn_cast<CXXMethodDecl>(functionDecl))
if (fieldDecl->getParent() != methodDecl->getParent() )
return;
if (ignoreLocation(fieldDecl))
return;
// to ignore things like the CPPUNIT macros
if (startswith(fn, WORKDIR "/"))
return;
// passes and stores pointers to member fields
if (fn == SRCDIR "/sot/source/sdstor/stgdir.hxx")
return;
// something platform-specific
if (fn == SRCDIR "/hwpfilter/source/htags.h")
return;
// passes pointers to member fields
if (fn == SRCDIR "/sd/inc/sdpptwrp.hxx")
return;
// @TODO intrusive linked-lists here, with some trickiness
if (fn == SRCDIR "/sw/source/filter/html/parcss1.hxx")
return;
// @TODO SwDoc has some weird ref-counting going on
if (fn == SRCDIR "/sw/inc/shellio.hxx")
return;
// @TODO it's sharing pointers with another class
if (fn == SRCDIR "/sc/inc/formulacell.hxx")
return;
// some weird stuff going on here around struct Entity
if (startswith(fn, SRCDIR "/sax/"))
return;
if (startswith(fn, SRCDIR "/include/sax/"))
return;
// manipulation of tree structures ie. StgAvlNode, don't lend themselves to std::unique_ptr
if (startswith(fn, SRCDIR "/sot/"))
return;
if (startswith(fn, SRCDIR "/include/sot/"))
return;
// the std::vector is being passed to another class
if (fn == SRCDIR "/sfx2/source/explorer/nochaos.cxx")
return;
auto tc = loplugin::TypeCheck(fieldDecl->getType());
// 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;
// there is a loop in ~ImplPrnQueueList deleting stuff on a global data structure
if (fn == SRCDIR "/vcl/inc/print.h")
return;
// painful linked list
if (fn == SRCDIR "/basic/source/inc/runtime.hxx")
return;
// not sure how the node management is working here
if (fn == SRCDIR "/i18npool/source/localedata/saxparser.cxx")
return;
// has a pointer that it only sometimes owns
if (fn == SRCDIR "/editeng/source/editeng/impedit.hxx")
return;
report(
DiagnosticsEngine::Warning,
message,
compat::getBeginLoc(deleteExpr))
<< deleteExpr->getSourceRange();
report(
DiagnosticsEngine::Note,
"member is here",
compat::getBeginLoc(fieldDecl))
<< fieldDecl->getSourceRange();
}
void UseUniquePtr::CheckLoopDelete(const FunctionDecl* functionDecl, const Stmt* bodyStmt)
{
if (auto deleteExpr = dyn_cast<CXXDeleteExpr>(bodyStmt))
......@@ -541,13 +462,27 @@ void UseUniquePtr::CheckLoopDelete(const FunctionDecl* functionDecl, const Stmt*
void UseUniquePtr::CheckLoopDelete(const FunctionDecl* functionDecl, const CXXDeleteExpr* deleteExpr)
{
const MemberExpr* memberExpr = nullptr;
const VarDecl* varDecl = nullptr;
const Expr* subExpr = deleteExpr->getArgument();
// drill down looking for a MemberExpr
for (;;)
{
subExpr = subExpr->IgnoreImpCasts();
subExpr = subExpr->IgnoreParenImpCasts();
if ((memberExpr = dyn_cast<MemberExpr>(subExpr)))
break;
{
if (memberExpr->getMemberDecl()->getName() == "first" || memberExpr->getMemberDecl()->getName() == "second")
{
subExpr = memberExpr->getBase();
memberExpr = nullptr;
}
else
break;
}
else if (auto declRefExpr = dyn_cast<DeclRefExpr>(subExpr))
{
if ((varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl())))
break;
}
else if (auto arraySubscriptExpr = dyn_cast<ArraySubscriptExpr>(subExpr))
subExpr = arraySubscriptExpr->getBase();
else if (auto cxxOperatorCallExpr = dyn_cast<CXXOperatorCallExpr>(subExpr))
......@@ -555,46 +490,171 @@ void UseUniquePtr::CheckLoopDelete(const FunctionDecl* functionDecl, const CXXDe
// 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()))
if (auto iterVarDecl = dyn_cast<VarDecl>(declRefExpr->getDecl()))
{
auto init = varDecl->getInit();
auto init = iterVarDecl->getInit();
if (init)
{
if (auto x = dyn_cast<ExprWithCleanups>(init))
init = x->getSubExpr();
if (auto x = dyn_cast<CXXBindTemporaryExpr>(init))
init = x->getSubExpr();
init = init->IgnoreImplicit();
if (auto x = dyn_cast<CXXConstructExpr>(init))
if (x->getNumArgs() == 1)
init = x->getArg(0)->IgnoreImplicit();
if (auto x = dyn_cast<CXXMemberCallExpr>(init))
init = x->getImplicitObjectArgument();
memberExpr = dyn_cast<MemberExpr>(init);
if ((memberExpr = dyn_cast<MemberExpr>(init)))
break;
// look for deletes of an iterator object where the iterator is over a var
if (auto declRefExpr2 = dyn_cast<DeclRefExpr>(init))
{
if ((varDecl = dyn_cast<VarDecl>(declRefExpr2->getDecl())))
break;
}
}
break;
}
}
// look for deletes like "delete m_pField[0]"
if (cxxOperatorCallExpr->getOperator() == OO_Subscript)
{
memberExpr = dyn_cast<MemberExpr>(cxxOperatorCallExpr->getArg(0));
subExpr = cxxOperatorCallExpr->getArg(0)->IgnoreImpCasts();
if ((memberExpr = dyn_cast<MemberExpr>(subExpr)))
break;
if (auto declRefExpr = dyn_cast<DeclRefExpr>(subExpr))
{
if ((varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl())))
break;
}
}
break;
}
else
break;
}
if (!memberExpr)
return;
// OStorage_Impl::Commit very complicated ownership passing going on
if (fn == SRCDIR "/package/source/xstor/xstorage.cxx")
return;
// complicated
if (fn == SRCDIR "/vcl/source/gdi/print.cxx")
return;
// linked list
if (fn == SRCDIR "/basic/source/runtime/runtime.cxx")
return;
if (memberExpr)
{
// OStorage_Impl::Commit very complicated ownership passing going on
if (fn == SRCDIR "/package/source/xstor/xstorage.cxx")
return;
// complicated
if (fn == SRCDIR "/vcl/source/gdi/print.cxx")
return;
// linked list
if (fn == SRCDIR "/basic/source/runtime/runtime.cxx")
return;
// complicated
if (fn == SRCDIR "/sw/source/core/bastyp/swcache.cxx")
return;
CheckMemberDeleteExpr(functionDecl, deleteExpr, memberExpr, "rather manage with std::some_container<std::unique_ptr<T>>");
}
if (varDecl)
{
// ignore if the value for the var comes from somewhere else
if (varDecl->hasInit() && isa<ExplicitCastExpr>(varDecl->getInit()->IgnoreImpCasts()))
return;
if (startswith(fn, SRCDIR "/vcl/qa/"))
return;
// linked list
if (fn == SRCDIR "/registry/source/reflwrit.cxx")
return;
// linked list
if (fn == SRCDIR "/tools/source/generic/config.cxx")
return;
// linked lists
if (fn == SRCDIR "/vcl/source/gdi/regband.cxx")
return;
// linked lists
if (fn == SRCDIR "/vcl/source/gdi/regionband.cxx")
return;
// linked list
if (fn == SRCDIR "/vcl/source/gdi/octree.cxx")
return;
// linked list
if (fn == SRCDIR "/vcl/source/app/scheduler.cxx")
return;
// linked list
if (fn == SRCDIR "/vcl/source/filter/wmf/wmfwr.cxx")
return;
// linked list
if (fn == SRCDIR "/vcl/source/filter/graphicfilter.cxx")
return;
// valid code
if (fn == SRCDIR "/vcl/source/app/salvtables.cxx")
return;
// undo code is tricky
if (fn == SRCDIR "/svl/source/undo/undo.cxx")
return;
// subclass that messes with parent class in constructor/destructor, yuck
if (fn == SRCDIR "/svtools/source/contnr/imivctl1.cxx")
return;
// SQLParseNode
if (fn == SRCDIR "/connectivity/source/parse/sqlnode.cxx")
return;
// the whole svx model/contact/view thing confuses me
if (fn == SRCDIR "/svx/source/sdr/contact/viewcontact.cxx")
return;
if (fn == SRCDIR "/svx/source/sdr/contact/objectcontact.cxx")
return;
// no idea
if (fn == SRCDIR "/svx/source/unodialogs/textconversiondlgs/chinese_dictionarydialog.cxx")
return;
// SdrUndo stuff
if (fn == SRCDIR "/svx/source/svdraw/svdundo.cxx")
return;
// TODO the lazydelete stuff should probably just be ripped out altogether nowthat we have VclPtr
if (fn == SRCDIR "/vcl/source/helper/lazydelete.cxx")
return;
// linked list
if (fn == SRCDIR "/filter/source/graphicfilter/idxf/dxfblkrd.cxx")
return;
if (fn == SRCDIR "/filter/source/graphicfilter/idxf/dxftblrd.cxx")
return;
if (fn == SRCDIR "/lotuswordpro/source/filter/utlist.cxx")
return;
if (fn == SRCDIR "/lotuswordpro/source/filter/lwpfribptr.cxx")
return;
// valid
if (fn == SRCDIR "/sd/source/ui/sidebar/MasterPagesSelector.cxx")
return;
// linked list
if (fn == SRCDIR "/sd/source/filter/ppt/pptatom.cxx")
return;
// linked list
if (fn == SRCDIR "/sc/source/core/data/funcdesc.cxx")
return;
// linked list
if (fn == SRCDIR "/sw/source/core/crsr/crsrsh.cxx")
return;
// no idea
if (fn == SRCDIR "/sw/source/core/docnode/nodes.cxx")
return;
// linked list
if (fn == SRCDIR "/sw/source/core/unocore/unocrsr.cxx")
return;
// linked list
if (fn == SRCDIR "/filter/source/graphicfilter/idxf/dxfentrd.cxx")
return;
// linked list
if (fn == SRCDIR "/filter/source/graphicfilter/ios2met/ios2met.cxx")
return;
// sometimes owning, sometimes not
if (fn == SRCDIR "/sw/qa/core/Test-BigPtrArray.cxx")
return;
CheckDeleteExpr(functionDecl, deleteExpr, memberExpr, "rather manage with std::some_container<std::unique_ptr<T>>");
report(
DiagnosticsEngine::Warning,
"loopdelete: rather manage this var with std::some_container<std::unique_ptr<T>>",
compat::getBeginLoc(deleteExpr))
<< deleteExpr->getSourceRange();
report(
DiagnosticsEngine::Note,
"var is here",
compat::getBeginLoc(varDecl))
<< varDecl->getSourceRange();
}
}
void UseUniquePtr::CheckCXXForRangeStmt(const FunctionDecl* functionDecl, const CXXForRangeStmt* cxxForRangeStmt)
......@@ -611,6 +671,7 @@ void UseUniquePtr::CheckCXXForRangeStmt(const FunctionDecl* functionDecl, const
if (!deleteExpr)
return;
// check for delete of member
if (auto memberExpr = dyn_cast<MemberExpr>(cxxForRangeStmt->getRangeInit()))
{
auto fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
......@@ -623,11 +684,15 @@ void UseUniquePtr::CheckCXXForRangeStmt(const FunctionDecl* functionDecl, const
// complicated
if (fn == SRCDIR "/vcl/source/gdi/print.cxx")
return;
// sometimes it's an owning field, sometimes not
if (fn == SRCDIR "/i18npool/source/localedata/localedata.cxx")
return;
CheckDeleteExpr(functionDecl, deleteExpr, memberExpr, "rather manage this with std::some_container<std::unique_ptr<T>>");
CheckMemberDeleteExpr(functionDecl, deleteExpr, memberExpr, "rather manage this with std::some_container<std::unique_ptr<T>>");
}
if (auto declRefExpr = dyn_cast<DeclRefExpr>(cxxForRangeStmt->getRangeInit()))
// check for delete of var
if (auto declRefExpr = dyn_cast<DeclRefExpr>(cxxForRangeStmt->getRangeInit()->IgnoreParenImpCasts()))
{
auto varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl());
if (!varDecl)
......@@ -675,52 +740,87 @@ void UseUniquePtr::CheckCXXForRangeStmt(const FunctionDecl* functionDecl, const
}
}
bool UseUniquePtr::VisitCompoundStmt(const CompoundStmt* compoundStmt)
void UseUniquePtr::CheckMemberDeleteExpr(const FunctionDecl* functionDecl, const CXXDeleteExpr* deleteExpr,
const MemberExpr* memberExpr, StringRef message)
{
if (ignoreLocation(compoundStmt))
return true;
if (isInUnoIncludeFile(compat::getBeginLoc(compoundStmt)))
return true;
if (compoundStmt->size() == 0) {
return true;
}
// ignore union games
const FieldDecl* fieldDecl = dyn_cast<FieldDecl>(memberExpr->getMemberDecl());
if (!fieldDecl)
return;
TagDecl const * td = dyn_cast<TagDecl>(fieldDecl->getDeclContext());
if (td->isUnion())
return;
auto lastStmt = compoundStmt->body_back();
if (compoundStmt->size() > 1) {
if (isa<ReturnStmt>(lastStmt))
lastStmt = *(++compoundStmt->body_rbegin());
}
auto deleteExpr = dyn_cast<CXXDeleteExpr>(lastStmt);
if (deleteExpr == nullptr) {
return true;
}
// ignore calling delete on someone else's field
if (auto methodDecl = dyn_cast<CXXMethodDecl>(functionDecl))
if (fieldDecl->getParent() != methodDecl->getParent() )
return;
auto declRefExpr = dyn_cast<DeclRefExpr>(deleteExpr->getArgument()->IgnoreParenImpCasts());
if (!declRefExpr)
return true;
auto varDecl = dyn_cast<VarDecl>(declRefExpr->getDecl());
if (!varDecl)
return true;
if (!varDecl->hasInit()
|| !isa<CXXNewExpr>(
varDecl->getInit()->IgnoreImplicit()->IgnoreParenImpCasts()))
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
if (compat::getBeginLoc(varDecl) < compat::getBeginLoc(compoundStmt))
return true;
if (ignoreLocation(fieldDecl))
return;
// to ignore things like the CPPUNIT macros
if (startswith(fn, WORKDIR "/"))
return;
// passes and stores pointers to member fields
if (fn == SRCDIR "/sot/source/sdstor/stgdir.hxx")
return;
// something platform-specific
if (fn == SRCDIR "/hwpfilter/source/htags.h")
return;
// passes pointers to member fields
if (fn == SRCDIR "/sd/inc/sdpptwrp.hxx")
return;
// @TODO intrusive linked-lists here, with some trickiness
if (fn == SRCDIR "/sw/source/filter/html/parcss1.hxx")
return;
// @TODO SwDoc has some weird ref-counting going on
if (fn == SRCDIR "/sw/inc/shellio.hxx")
return;
// @TODO it's sharing pointers with another class
if (fn == SRCDIR "/sc/inc/formulacell.hxx")
return;
// some weird stuff going on here around struct Entity
if (startswith(fn, SRCDIR "/sax/"))
return;
if (startswith(fn, SRCDIR "/include/sax/"))
return;
// manipulation of tree structures ie. StgAvlNode, don't lend themselves to std::unique_ptr
if (startswith(fn, SRCDIR "/sot/"))
return;
if (startswith(fn, SRCDIR "/include/sot/"))
return;
// the std::vector is being passed to another class
if (fn == SRCDIR "/sfx2/source/explorer/nochaos.cxx")
return;
auto tc = loplugin::TypeCheck(fieldDecl->getType());
// 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;
// there is a loop in ~ImplPrnQueueList deleting stuff on a global data structure
if (fn == SRCDIR "/vcl/inc/print.h")
return;
// painful linked list
if (fn == SRCDIR "/basic/source/inc/runtime.hxx")
return;
// not sure how the node management is working here
if (fn == SRCDIR "/i18npool/source/localedata/saxparser.cxx")
return;
// has a pointer that it only sometimes owns
if (fn == SRCDIR "/editeng/source/editeng/impedit.hxx")
return;
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",
message,
compat::getBeginLoc(deleteExpr))
<< deleteExpr->getSourceRange();
report(
DiagnosticsEngine::Note,
"var is here",
compat::getBeginLoc(varDecl))
<< varDecl->getSourceRange();
return true;
"member is here",
compat::getBeginLoc(fieldDecl))
<< fieldDecl->getSourceRange();
}
bool UseUniquePtr::TraverseFunctionDecl(FunctionDecl* functionDecl)
......@@ -749,6 +849,21 @@ bool UseUniquePtr::TraverseCXXMethodDecl(CXXMethodDecl* methodDecl)
return ret;
}
#if CLANG_VERSION >= 50000
bool UseUniquePtr::TraverseCXXDeductionGuideDecl(CXXDeductionGuideDecl* methodDecl)
{
if (ignoreLocation(methodDecl))
return true;
auto oldCurrent = mpCurrentFunctionDecl;
mpCurrentFunctionDecl = methodDecl;
bool ret = RecursiveASTVisitor::TraverseCXXDeductionGuideDecl(methodDecl);
mpCurrentFunctionDecl = oldCurrent;
return ret;
}
#endif
bool UseUniquePtr::TraverseCXXConstructorDecl(CXXConstructorDecl* methodDecl)
{
if (ignoreLocation(methodDecl))
......@@ -762,6 +877,64 @@ bool UseUniquePtr::TraverseCXXConstructorDecl(CXXConstructorDecl* methodDecl)
return ret;
}
bool UseUniquePtr::TraverseCXXConversionDecl(CXXConversionDecl* methodDecl)
{
if (ignoreLocation(methodDecl))
return true;
auto oldCurrent = mpCurrentFunctionDecl;
mpCurrentFunctionDecl = methodDecl;
bool ret = RecursiveASTVisitor::TraverseCXXConversionDecl(methodDecl);
mpCurrentFunctionDecl = oldCurrent;
return ret;
}
bool UseUniquePtr::TraverseCXXDestructorDecl(CXXDestructorDecl* methodDecl)
{
if (ignoreLocation(methodDecl))
return true;
auto oldCurrent = mpCurrentFunctionDecl;
mpCurrentFunctionDecl = methodDecl;
bool ret = RecursiveASTVisitor::TraverseCXXDestructorDecl(methodDecl);
mpCurrentFunctionDecl = oldCurrent;
return ret;
}
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;
auto constructExpr = dyn_cast_or_null<CXXConstructExpr>(ctorInit->getInit());
if (!constructExpr || constructExpr->getNumArgs() == 0)
return true;
auto init = constructExpr->getArg(0)->IgnoreImpCasts();
if (!isa<DeclRefExpr>(init))
return true;
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;
report(
DiagnosticsEngine::Warning,
"should be passing via std::unique_ptr param",
ctorInit->getSourceLocation())
<< ctorInit->getSourceRange();
return RecursiveASTVisitor<UseUniquePtr>::TraverseConstructorInitializer(ctorInit);
}
// Only checks for calls to delete on a pointer param
bool UseUniquePtr::VisitCXXDeleteExpr(const CXXDeleteExpr* deleteExpr)
{
if (!mpCurrentFunctionDecl)
......@@ -945,37 +1118,6 @@ bool UseUniquePtr::VisitCXXDeleteExpr(const CXXDeleteExpr* deleteExpr)
return true;
}
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;
auto constructExpr = dyn_cast_or_null<CXXConstructExpr>(ctorInit->getInit());
if (!constructExpr || constructExpr->getNumArgs() == 0)
return true;
auto init = constructExpr->getArg(0)->IgnoreImpCasts();
if (!isa<DeclRefExpr>(init))
return true;
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;
report(
DiagnosticsEngine::Warning,
"should be passing via std::unique_ptr param",
ctorInit->getSourceLocation())
<< ctorInit->getSourceRange();
return RecursiveASTVisitor<UseUniquePtr>::TraverseConstructorInitializer(ctorInit);
}
loplugin::Plugin::Registration< UseUniquePtr > X("useuniqueptr", false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment