diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-08-23 08:49:02 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-08-23 18:35:00 +0200 |
commit | c66568d6b0bbcce26cbdc5a4e5f6e4c0ae748e45 (patch) | |
tree | 2237871caf9e1f78875e808ef81f565ba1aaf61f | |
parent | 87f1f7fdb34fe452ac540524224e1e808ce5d3a2 (diff) |
loplugin:useuniqueptr, look for containers..
that can use std::unique_ptr, and apply it in i18npool
Change-Id: Ib410abaf73d5f392c7a7a9a322872b08c948f9e9
Reviewed-on: https://gerrit.libreoffice.org/41438
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r-- | compilerplugins/clang/test/useuniqueptr.cxx | 45 | ||||
-rw-r--r-- | compilerplugins/clang/useuniqueptr.cxx | 133 | ||||
-rw-r--r-- | i18npool/inc/breakiterator_unicode.hxx | 5 | ||||
-rw-r--r-- | i18npool/source/breakiterator/breakiterator_unicode.cxx | 20 | ||||
-rw-r--r-- | i18npool/source/localedata/LocaleNode.cxx | 4 | ||||
-rw-r--r-- | i18npool/source/localedata/LocaleNode.hxx | 5 |
6 files changed, 186 insertions, 26 deletions
diff --git a/compilerplugins/clang/test/useuniqueptr.cxx b/compilerplugins/clang/test/useuniqueptr.cxx index 7e64bcca8986..b45781925630 100644 --- a/compilerplugins/clang/test/useuniqueptr.cxx +++ b/compilerplugins/clang/test/useuniqueptr.cxx @@ -7,6 +7,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <array> +#include <unordered_map> + struct XXX { ~XXX() {} }; @@ -40,4 +43,46 @@ class Foo3 { delete[] m_pbar; } }; + +class Class4 { + int* m_pbar[10]; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class4() + { + for (int i = 0; i < 10; ++i) + delete m_pbar[i]; // expected-error {{rather manage with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +class Class5 { + int* m_pbar[10]; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class5() + { + for (auto p : m_pbar) + delete p; // expected-error {{rather manage with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +class Class6 { + std::array<int*,10> m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class6() + { + for (auto p : m_pbar) + delete p; // expected-error {{rather manage with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +class Class7 { + std::array<int*,10> m_pbar; // expected-note {{member is here [loplugin:useuniqueptr]}} + ~Class7() + { + for (int i = 0; i < 10; ++i) + delete m_pbar[i]; // expected-error {{rather manage with std::some_container<std::unique_ptr<T>> [loplugin:useuniqueptr]}} + } +}; +// don't warn for maps, MSVC 2015 has problems with mixing std::map/std::unordered_map and std::unique_ptr +class Class8 { + std::unordered_map<int, int*> m_pbar; + ~Class8() + { + for (auto i : m_pbar) + delete i.second; + } +}; /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/compilerplugins/clang/useuniqueptr.cxx b/compilerplugins/clang/useuniqueptr.cxx index 977404ab2ae6..e47ebd23450a 100644 --- a/compilerplugins/clang/useuniqueptr.cxx +++ b/compilerplugins/clang/useuniqueptr.cxx @@ -38,6 +38,8 @@ public: bool VisitCompoundStmt(const CompoundStmt* ); private: void CheckForSingleUnconditionalDelete(const CXXDestructorDecl*, const CompoundStmt* ); + void CheckForForLoopDelete(const CXXDestructorDecl*, const CompoundStmt* ); + void CheckForRangedLoopDelete(const CXXDestructorDecl*, const CompoundStmt* ); void CheckForDeleteOfPOD(const CompoundStmt* ); }; @@ -52,8 +54,13 @@ bool UseUniquePtr::VisitCXXDestructorDecl(const CXXDestructorDecl* destructorDec if (!compoundStmt) return true; - CheckForSingleUnconditionalDelete(destructorDecl, compoundStmt); - CheckForDeleteOfPOD(compoundStmt); + if (compoundStmt->size() > 0) + { + CheckForSingleUnconditionalDelete(destructorDecl, compoundStmt); + CheckForDeleteOfPOD(compoundStmt); + CheckForForLoopDelete(destructorDecl, compoundStmt); + CheckForRangedLoopDelete(destructorDecl, compoundStmt); + } return true; } @@ -78,9 +85,15 @@ void UseUniquePtr::CheckForSingleUnconditionalDelete(const CXXDestructorDecl* de deleteExpr = dyn_cast<CXXDeleteExpr>(compoundStmt->body_front()); } } else { - return; + // look for the following pattern: + // delete m_pbar; + // m_pbar = nullptr; + if (auto binaryOp = dyn_cast<BinaryOperator>(compoundStmt->body_back())) { + if (binaryOp->getOpcode() == BO_Assign) + deleteExpr = dyn_cast<CXXDeleteExpr>(*(++compoundStmt->body_rbegin())); + } } - if (deleteExpr == nullptr) + if (!deleteExpr) return; const ImplicitCastExpr* pCastExpr = dyn_cast<ImplicitCastExpr>(deleteExpr->getArgument()); @@ -145,6 +158,116 @@ void UseUniquePtr::CheckForSingleUnconditionalDelete(const CXXDestructorDecl* de << pFieldDecl->getSourceRange(); } +void UseUniquePtr::CheckForForLoopDelete(const CXXDestructorDecl* destructorDecl, const CompoundStmt* compoundStmt) +{ + auto forStmt = dyn_cast<ForStmt>(compoundStmt->body_back()); + if (!forStmt) + return; + auto deleteExpr = dyn_cast<CXXDeleteExpr>(forStmt->getBody()); + if (!deleteExpr) + return; + + const MemberExpr* memberExpr = nullptr; + const Expr* subExpr = deleteExpr->getArgument(); + for (;;) + { + 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)) + { + if (cxxOperatorCallExpr->getOperator() == OO_Subscript) + { + memberExpr = dyn_cast<MemberExpr>(cxxOperatorCallExpr->getArg(0)); + break; + } + return; + } + else + return; + } + + // 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 (fieldDecl->getParent() != destructorDecl->getParent() ) + return; + + if (ignoreLocation(fieldDecl)) + return; + // to ignore things like the CPPUNIT macros + StringRef aFileName = compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(fieldDecl->getLocStart())); + if (loplugin::hasPathnamePrefix(aFileName, WORKDIR)) + return; + + report( + DiagnosticsEngine::Warning, + "rather manage with std::some_container<std::unique_ptr<T>>", + deleteExpr->getLocStart()) + << deleteExpr->getSourceRange(); + report( + DiagnosticsEngine::Note, + "member is here", + fieldDecl->getLocStart()) + << fieldDecl->getSourceRange(); +} + +void UseUniquePtr::CheckForRangedLoopDelete(const CXXDestructorDecl* destructorDecl, const CompoundStmt* compoundStmt) +{ + auto cxxForRangeStmt = dyn_cast<CXXForRangeStmt>(compoundStmt->body_back()); + if (!cxxForRangeStmt) + return; + auto 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; + + // ignore union games + TagDecl const * td = dyn_cast<TagDecl>(fieldDecl->getDeclContext()); + if (td->isUnion()) + return; + + // ignore calling delete on someone else's field + if (fieldDecl->getParent() != destructorDecl->getParent() ) + return; + + if (ignoreLocation(fieldDecl)) + return; + + // to ignore things like the CPPUNIT macros + StringRef aFileName = compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(fieldDecl->getLocStart())); + if (loplugin::hasPathnamePrefix(aFileName, WORKDIR)) + return; + // ignore std::map and std::unordered_map, MSVC 2015 has problems with mixing these with std::unique_ptr + auto tc = loplugin::TypeCheck(fieldDecl->getType()); + if (tc.Class("map").StdNamespace() || tc.Class("unordered_map").StdNamespace()) + return; + + report( + DiagnosticsEngine::Warning, + "rather manage with std::some_container<std::unique_ptr<T>>", + deleteExpr->getLocStart()) + << deleteExpr->getSourceRange(); + report( + DiagnosticsEngine::Note, + "member is here", + fieldDecl->getLocStart()) + << fieldDecl->getSourceRange(); +} + bool UseUniquePtr::VisitCompoundStmt(const CompoundStmt* compoundStmt) { if (ignoreLocation(compoundStmt)) @@ -255,7 +378,7 @@ void UseUniquePtr::CheckForDeleteOfPOD(const CompoundStmt* compoundStmt) -loplugin::Plugin::Registration< UseUniquePtr > X("useuniqueptr"); +loplugin::Plugin::Registration< UseUniquePtr > X("useuniqueptr", false); } diff --git a/i18npool/inc/breakiterator_unicode.hxx b/i18npool/inc/breakiterator_unicode.hxx index 42dcb305777a..8783764cb0e1 100644 --- a/i18npool/inc/breakiterator_unicode.hxx +++ b/i18npool/inc/breakiterator_unicode.hxx @@ -22,6 +22,7 @@ #include <breakiteratorImpl.hxx> #include <unicode/brkiter.h> +#include <memory> namespace com { namespace sun { namespace star { namespace i18n { @@ -74,10 +75,10 @@ protected: { OUString aICUText; UText* ut; - icu::BreakIterator* aBreakIterator; + std::unique_ptr<icu::BreakIterator> aBreakIterator; css::lang::Locale maLocale; - BI_Data() : ut(nullptr), aBreakIterator(nullptr) + BI_Data() : ut(nullptr) { } ~BI_Data() diff --git a/i18npool/source/breakiterator/breakiterator_unicode.cxx b/i18npool/source/breakiterator/breakiterator_unicode.cxx index 2256755e85be..cf781eb414a0 100644 --- a/i18npool/source/breakiterator/breakiterator_unicode.cxx +++ b/i18npool/source/breakiterator/breakiterator_unicode.cxx @@ -49,11 +49,6 @@ BreakIterator_Unicode::BreakIterator_Unicode() BreakIterator_Unicode::~BreakIterator_Unicode() { - delete character.aBreakIterator; - delete sentence.aBreakIterator; - delete line.aBreakIterator; - for (BI_Data & word : words) - delete word.aBreakIterator; } /* @@ -107,10 +102,7 @@ void SAL_CALL BreakIterator_Unicode::loadICUBreakIterator(const css::lang::Local rLocale.Language != icuBI->maLocale.Language || rLocale.Country != icuBI->maLocale.Country || rLocale.Variant != icuBI->maLocale.Variant) { - if (icuBI->aBreakIterator) { - delete icuBI->aBreakIterator; - icuBI->aBreakIterator=nullptr; - } + icuBI->aBreakIterator.reset(); if (rule) { uno::Sequence< OUString > breakRules = LocaleDataImpl::get()->getBreakIteratorRules(rLocale); @@ -160,7 +152,7 @@ void SAL_CALL BreakIterator_Unicode::loadICUBreakIterator(const css::lang::Local case LOAD_LINE_BREAKITERATOR: rbi->publicSetBreakType(UBRK_LINE); break; } #endif - icuBI->aBreakIterator = rbi; + icuBI->aBreakIterator.reset( rbi ); } } @@ -170,16 +162,16 @@ void SAL_CALL BreakIterator_Unicode::loadICUBreakIterator(const css::lang::Local status = U_ZERO_ERROR; switch (rBreakType) { case LOAD_CHARACTER_BREAKITERATOR: - icuBI->aBreakIterator = icu::BreakIterator::createCharacterInstance(icuLocale, status); + icuBI->aBreakIterator.reset( icu::BreakIterator::createCharacterInstance(icuLocale, status) ); break; case LOAD_WORD_BREAKITERATOR: - icuBI->aBreakIterator = icu::BreakIterator::createWordInstance(icuLocale, status); + icuBI->aBreakIterator.reset( icu::BreakIterator::createWordInstance(icuLocale, status) ); break; case LOAD_SENTENCE_BREAKITERATOR: - icuBI->aBreakIterator = icu::BreakIterator::createSentenceInstance(icuLocale, status); + icuBI->aBreakIterator.reset( icu::BreakIterator::createSentenceInstance(icuLocale, status) ); break; case LOAD_LINE_BREAKITERATOR: - icuBI->aBreakIterator = icu::BreakIterator::createLineInstance(icuLocale, status); + icuBI->aBreakIterator.reset( icu::BreakIterator::createLineInstance(icuLocale, status) ); break; } if ( !U_SUCCESS(status) ) { diff --git a/i18npool/source/localedata/LocaleNode.cxx b/i18npool/source/localedata/LocaleNode.cxx index a17ff49cefcf..5d3e29a3531c 100644 --- a/i18npool/source/localedata/LocaleNode.cxx +++ b/i18npool/source/localedata/LocaleNode.cxx @@ -73,7 +73,7 @@ void LocaleNode::printR () const { } void LocaleNode::addChild ( LocaleNode * node) { - children.push_back(node); + children.emplace_back(node); node->parent = this; } @@ -99,8 +99,6 @@ const LocaleNode * LocaleNode::findNode ( const sal_Char *name) const { LocaleNode::~LocaleNode() { - for (size_t i=0; i < children.size(); ++i) - delete children[i]; } LocaleNode* LocaleNode::createNode (const OUString& name, const Reference< XAttributeList > & attr) diff --git a/i18npool/source/localedata/LocaleNode.hxx b/i18npool/source/localedata/LocaleNode.hxx index c3e6c57e6a22..0f089d162bf3 100644 --- a/i18npool/source/localedata/LocaleNode.hxx +++ b/i18npool/source/localedata/LocaleNode.hxx @@ -23,6 +23,7 @@ #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> #include <vector> +#include <memory> #include <com/sun/star/lang/XComponent.hpp> #include <com/sun/star/xml/sax/SAXParseException.hpp> @@ -85,7 +86,7 @@ class LocaleNode OUString aValue; Attr aAttribs; LocaleNode * parent; - std::vector<LocaleNode*> children; + std::vector<std::unique_ptr<LocaleNode>> children; protected: mutable int nError; @@ -97,7 +98,7 @@ public: const OUString& getValue() const { return aValue; }; const Attr& getAttr() const { return aAttribs; }; sal_Int32 getNumberOfChildren () const { return sal_Int32(children.size()); }; - LocaleNode * getChildAt (sal_Int32 idx) const { return children[idx] ; }; + LocaleNode * getChildAt (sal_Int32 idx) const { return children[idx].get(); }; const LocaleNode * findNode ( const sal_Char *name) const; void print () const; void printR () const; |