Kaydet (Commit) 22bba5f3 authored tarafından Noel Grandin's avatar Noel Grandin

teach useuniqueptr loplugin about "if(field != null) delete field"

Change-Id: I938deef90c8d6ceb0e72ab3f6ee2cbddc6f72b8d
Reviewed-on: https://gerrit.libreoffice.org/47730Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarNoel Grandin <noel.grandin@collabora.co.uk>
üst 920447d4
...@@ -94,4 +94,22 @@ class Foo8 { ...@@ -94,4 +94,22 @@ class Foo8 {
delete m_pbar2; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}} delete m_pbar2; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}}
} }
}; };
class Foo9 {
XXX* m_pbar1; // expected-note {{member is here [loplugin:useuniqueptr]}}
XXX* m_pbar2; // expected-note {{member is here [loplugin:useuniqueptr]}}
XXX* m_pbar3; // expected-note {{member is here [loplugin:useuniqueptr]}}
~Foo9()
{
if (m_pbar1)
{
delete m_pbar1; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}}
}
if (m_pbar2 != nullptr)
{
delete m_pbar2; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}}
}
if (m_pbar3 != nullptr)
delete m_pbar3; // expected-error {{unconditional call to delete on a member, should be using std::unique_ptr [loplugin:useuniqueptr]}}
}
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
...@@ -39,6 +39,7 @@ public: ...@@ -39,6 +39,7 @@ public:
bool VisitCompoundStmt(const CompoundStmt* ); bool VisitCompoundStmt(const CompoundStmt* );
private: private:
void CheckForUnconditionalDelete(const CXXDestructorDecl*, const CompoundStmt* ); void CheckForUnconditionalDelete(const CXXDestructorDecl*, const CompoundStmt* );
void CheckDeleteExpr(const CXXDestructorDecl*, const CXXDeleteExpr* );
void CheckForForLoopDelete(const CXXDestructorDecl*, const CompoundStmt* ); void CheckForForLoopDelete(const CXXDestructorDecl*, const CompoundStmt* );
void CheckForRangedLoopDelete(const CXXDestructorDecl*, const CompoundStmt* ); void CheckForRangedLoopDelete(const CXXDestructorDecl*, const CompoundStmt* );
}; };
...@@ -66,69 +67,114 @@ void UseUniquePtr::CheckForUnconditionalDelete(const CXXDestructorDecl* destruct ...@@ -66,69 +67,114 @@ void UseUniquePtr::CheckForUnconditionalDelete(const CXXDestructorDecl* destruct
for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i) for (auto i = compoundStmt->body_begin(); i != compoundStmt->body_end(); ++i)
{ {
auto deleteExpr = dyn_cast<CXXDeleteExpr>(*i); auto deleteExpr = dyn_cast<CXXDeleteExpr>(*i);
if (!deleteExpr) if (deleteExpr)
continue; {
CheckDeleteExpr(destructorDecl, deleteExpr);
const ImplicitCastExpr* pCastExpr = dyn_cast<ImplicitCastExpr>(deleteExpr->getArgument());
if (!pCastExpr)
continue; continue;
const MemberExpr* pMemberExpr = dyn_cast<MemberExpr>(pCastExpr->getSubExpr()); }
if (!pMemberExpr) // Check for conditional deletes like:
// if (m_pField != nullptr) delete m_pField;
auto ifStmt = dyn_cast<IfStmt>(*i);
if (!ifStmt)
continue; continue;
auto cond = ifStmt->getCond()->IgnoreImpCasts();
// ignore union games if (auto ifCondMemberExpr = dyn_cast<MemberExpr>(cond))
const FieldDecl* pFieldDecl = dyn_cast<FieldDecl>(pMemberExpr->getMemberDecl()); {
if (!pFieldDecl) // ignore "if (bMine)"
if (!loplugin::TypeCheck(ifCondMemberExpr->getType()).Pointer())
continue;
}
else if (auto binaryOp = dyn_cast<BinaryOperator>(cond))
{
if (!isa<MemberExpr>(binaryOp->getLHS()->IgnoreImpCasts()))
continue;
}
else
continue; continue;
TagDecl const * td = dyn_cast<TagDecl>(pFieldDecl->getDeclContext()); deleteExpr = dyn_cast<CXXDeleteExpr>(ifStmt->getThen());
if (td->isUnion()) if (deleteExpr)
{
CheckDeleteExpr(destructorDecl, deleteExpr);
continue; continue;
}
// ignore calling delete on someone else's field auto ifThenCompoundStmt = dyn_cast<CompoundStmt>(ifStmt->getThen());
if (pFieldDecl->getParent() != destructorDecl->getParent() ) if (!ifThenCompoundStmt)
continue; continue;
for (auto j = ifThenCompoundStmt->body_begin(); j != ifThenCompoundStmt->body_end(); ++j)
{
auto ifDeleteExpr = dyn_cast<CXXDeleteExpr>(*j);
if (ifDeleteExpr)
CheckDeleteExpr(destructorDecl, ifDeleteExpr);
}
}
}
if (ignoreLocation(pFieldDecl)) void UseUniquePtr::CheckDeleteExpr(const CXXDestructorDecl* destructorDecl, const CXXDeleteExpr* deleteExpr)
continue; {
// to ignore things like the CPPUNIT macros const ImplicitCastExpr* pCastExpr = dyn_cast<ImplicitCastExpr>(deleteExpr->getArgument());
StringRef aFileName = compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(pFieldDecl->getLocStart())); if (!pCastExpr)
if (loplugin::hasPathnamePrefix(aFileName, WORKDIR)) return;
continue; const MemberExpr* pMemberExpr = dyn_cast<MemberExpr>(pCastExpr->getSubExpr());
// passes and stores pointers to member fields if (!pMemberExpr)
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sot/source/sdstor/stgdir.hxx")) return;
continue;
// something platform-specific // ignore union games
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/hwpfilter/source/htags.h")) const FieldDecl* pFieldDecl = dyn_cast<FieldDecl>(pMemberExpr->getMemberDecl());
continue; if (!pFieldDecl)
// passes pointers to member fields return;
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sd/inc/sdpptwrp.hxx")) TagDecl const * td = dyn_cast<TagDecl>(pFieldDecl->getDeclContext());
continue; if (td->isUnion())
// @TODO intrusive linked-lists here, with some trickiness return;
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sw/source/filter/html/parcss1.hxx"))
continue; // ignore calling delete on someone else's field
// @TODO SwDoc has some weird ref-counting going on if (pFieldDecl->getParent() != destructorDecl->getParent() )
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sw/inc/shellio.hxx")) return;
continue;
// @TODO it's sharing pointers with another class if (ignoreLocation(pFieldDecl))
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sc/inc/formulacell.hxx")) return;
continue; // to ignore things like the CPPUNIT macros
// some weird stuff going on here around struct Entity StringRef aFileName = compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(pFieldDecl->getLocStart()));
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sax/")) if (loplugin::hasPathnamePrefix(aFileName, WORKDIR))
continue; return;
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/include/sax/")) // passes and stores pointers to member fields
continue; if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sot/source/sdstor/stgdir.hxx"))
return;
// something platform-specific
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/hwpfilter/source/htags.h"))
return;
// passes pointers to member fields
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sd/inc/sdpptwrp.hxx"))
return;
// @TODO intrusive linked-lists here, with some trickiness
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sw/source/filter/html/parcss1.hxx"))
return;
// @TODO SwDoc has some weird ref-counting going on
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sw/inc/shellio.hxx"))
return;
// @TODO it's sharing pointers with another class
if (loplugin::hasPathnamePrefix(aFileName, SRCDIR "/sc/inc/formulacell.hxx"))
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;
report( report(
DiagnosticsEngine::Warning, DiagnosticsEngine::Warning,
"unconditional call to delete on a member, should be using std::unique_ptr", "unconditional call to delete on a member, should be using std::unique_ptr",
deleteExpr->getLocStart()) deleteExpr->getLocStart())
<< deleteExpr->getSourceRange(); << deleteExpr->getSourceRange();
report( report(
DiagnosticsEngine::Note, DiagnosticsEngine::Note,
"member is here", "member is here",
pFieldDecl->getLocStart()) pFieldDecl->getLocStart())
<< pFieldDecl->getSourceRange(); << pFieldDecl->getSourceRange();
}
} }
void UseUniquePtr::CheckForForLoopDelete(const CXXDestructorDecl* destructorDecl, const CompoundStmt* compoundStmt) void UseUniquePtr::CheckForForLoopDelete(const CXXDestructorDecl* destructorDecl, const CompoundStmt* compoundStmt)
......
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