/* -*- 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/. */ #include #include #include #include #include #include "plugin.hxx" /** 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: public RecursiveASTVisitor, public loplugin::Plugin { public: explicit UseUniquePtr(InstantiationData const & data): Plugin(data) {} virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } bool VisitCXXDestructorDecl(const CXXDestructorDecl* ); }; bool UseUniquePtr::VisitCXXDestructorDecl(const CXXDestructorDecl* destructorDecl) { if (ignoreLocation(destructorDecl)) return true; if (isInUnoIncludeFile(destructorDecl)) return true; /* StringRef aFileName = compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(destructorDecl->getLocStart())); // weird stuff, passing pointers to internal members of struct if (aFileName.startswith(SRCDIR "/include/jvmfwk/framework.hxx")) return true; */ if (destructorDecl->getBody() == nullptr) return true; const CompoundStmt* compoundStmt = dyn_cast< CompoundStmt >( destructorDecl->getBody() ); if (compoundStmt == nullptr) { return true; } if (compoundStmt->size() != 1) { return true; } const CXXDeleteExpr* deleteExpr = dyn_cast(compoundStmt->body_front()); if (deleteExpr == nullptr) { return true; } const ImplicitCastExpr* pCastExpr = dyn_cast(deleteExpr->getArgument()); if (!pCastExpr) return true; const MemberExpr* pMemberExpr = dyn_cast(pCastExpr->getSubExpr()); if (!pMemberExpr) return true; // ignore union games const FieldDecl* pFieldDecl = dyn_cast(pMemberExpr->getMemberDecl()); if (!pFieldDecl) return true; TagDecl const * td = dyn_cast(pFieldDecl->getDeclContext()); if (td->isUnion()) return true; // ignore calling delete on someone else's field if (pFieldDecl->getParent() != destructorDecl->getParent() ) return true; if (ignoreLocation(pFieldDecl)) return true; // to ignore things like the CPPUNIT macros StringRef aFileName = compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(pFieldDecl->getLocStart())); if (aFileName.startswith(WORKDIR)) return true; // weird stuff, passing pointers to internal members of struct if (aFileName.startswith(SRCDIR "/include/jvmfwk/framework.hxx")) return true; if (aFileName.startswith(SRCDIR "/jvmfwk/")) return true; // passes and stores pointers to member fields if (aFileName.startswith(SRCDIR "/sot/source/sdstor/stgdir.hxx")) return true; // passes and stores pointers to member fields if (aFileName.startswith(SRCDIR "/desktop/source/migration/services/jvmfwk.cxx")) return true; // something platform-specific if (aFileName.startswith(SRCDIR "/hwpfilter/source/htags.h")) return true; // @TODO there is clearly a bug in the ownership here, the operator= method cannot be right if (aFileName.startswith(SRCDIR "/include/formula/formdata.hxx")) return true; // passes pointers to member fields if (aFileName.startswith(SRCDIR "/sd/inc/sdpptwrp.hxx")) return true; // @TODO there is clearly a bug in the ownership here, the ScJumpMatrixToken copy constructor cannot be right if (aFileName.startswith(SRCDIR "/sc/inc/token.hxx")) return true; // @TODO intrusive linked-lists here, with some trickiness if (aFileName.startswith(SRCDIR "/sw/source/filter/html/parcss1.hxx")) return true; // @TODO SwDoc has some weird ref-counting going on if (aFileName.startswith(SRCDIR "/sw/inc/shellio.hxx")) return true; report( DiagnosticsEngine::Warning, "a destructor with only a single unconditional call to delete on a member, is a sure sign it should be using std::unique_ptr for that field", deleteExpr->getLocStart()) << deleteExpr->getSourceRange(); report( DiagnosticsEngine::Note, "member is here", pFieldDecl->getLocStart()) << pFieldDecl->getSourceRange(); return true; } loplugin::Plugin::Registration< UseUniquePtr > X("useuniqueptr"); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */