summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2017-01-11 14:19:47 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2017-01-23 06:59:17 +0000
commit98e4013c22c4ce63090a575e698cc2af82925e6b (patch)
tree571d99c39420e929cd43e0365354da1aced03e68 /compilerplugins
parent2d1cecf02b34d855c8d64e3271bffbcbf9bf4138 (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.cxx137
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: */