diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-01-11 14:19:47 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2017-01-23 06:59:17 +0000 |
commit | 98e4013c22c4ce63090a575e698cc2af82925e6b (patch) | |
tree | 571d99c39420e929cd43e0365354da1aced03e68 /compilerplugins | |
parent | 2d1cecf02b34d855c8d64e3271bffbcbf9bf4138 (diff) |
new loplugin useuniqueptr
Change-Id: Ic7a8b32887c968d86568e4cfad7ddd1f4da7c73f
Reviewed-on: https://gerrit.libreoffice.org/33339
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/useuniqueptr.cxx | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/compilerplugins/clang/useuniqueptr.cxx b/compilerplugins/clang/useuniqueptr.cxx new file mode 100644 index 000000000000..82d95e56c45a --- /dev/null +++ b/compilerplugins/clang/useuniqueptr.cxx @@ -0,0 +1,137 @@ +/* -*- 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 <cassert> +#include <string> +#include <iostream> +#include <fstream> +#include <set> +#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<UseUniquePtr>, 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<CXXDeleteExpr>(compoundStmt->body_front()); + if (deleteExpr == nullptr) { + return true; + } + + const ImplicitCastExpr* pCastExpr = dyn_cast<ImplicitCastExpr>(deleteExpr->getArgument()); + if (!pCastExpr) + return true; + const MemberExpr* pMemberExpr = dyn_cast<MemberExpr>(pCastExpr->getSubExpr()); + if (!pMemberExpr) + return true; + + // ignore union games + const FieldDecl* pFieldDecl = dyn_cast<FieldDecl>(pMemberExpr->getMemberDecl()); + if (!pFieldDecl) + return true; + TagDecl const * td = dyn_cast<TagDecl>(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: */ |