diff options
author | Noel Grandin <noel@peralex.com> | 2016-06-22 12:08:45 +0200 |
---|---|---|
committer | Noel Grandin <noelgrandin@gmail.com> | 2016-07-12 08:45:14 +0000 |
commit | 52b91f3454394a1792dec018804bf2c969f564e5 (patch) | |
tree | b72a1bedae05e7e16268487e6d16773f8ee57674 /compilerplugins | |
parent | c44726c48228d9c6a5960e302b1c0bd16b0099c4 (diff) |
new loplugin fragiledestructor
fix up a small number of places that it finds
Change-Id: Iedc91e141edfb28f727454f698cd2155a7fd5bf4
Reviewed-on: https://gerrit.libreoffice.org/26566
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Noel Grandin <noelgrandin@gmail.com>
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/fragiledestructor.cxx | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/compilerplugins/clang/fragiledestructor.cxx b/compilerplugins/clang/fragiledestructor.cxx new file mode 100644 index 000000000000..ebce1d677f8b --- /dev/null +++ b/compilerplugins/clang/fragiledestructor.cxx @@ -0,0 +1,113 @@ +/* -*- 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 <string> +#include <iostream> + +#include "plugin.hxx" +#include "compat.hxx" +#include "clang/AST/CXXInheritance.h" + + +// Check for calls to virtual methods from destructors. These are dangerous because intention might be to call +// a method on a subclass, while in actual fact, it only calls the method on the current or super class. +// + +namespace { + +class FragileDestructor: + public RecursiveASTVisitor<FragileDestructor>, public loplugin::Plugin +{ +public: + explicit FragileDestructor(InstantiationData const & data): Plugin(data) {} + + virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); } + + bool VisitCXXDestructorDecl(const CXXDestructorDecl *); + + bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *); + +private: + bool mbChecking = false; +}; + +bool FragileDestructor::VisitCXXDestructorDecl(const CXXDestructorDecl* pCXXDestructorDecl) +{ + if (ignoreLocation(pCXXDestructorDecl)) { + return true; + } + if (!pCXXDestructorDecl->isThisDeclarationADefinition()) { + return true; + } + // ignore this for now, too tricky for me to work out + StringRef aFileName = compiler.getSourceManager().getFilename( + compiler.getSourceManager().getSpellingLoc(pCXXDestructorDecl->getLocStart())); + if (aFileName.startswith(SRCDIR "/include/comphelper/") + || aFileName.startswith(SRCDIR "/include/cppuhelper/") + || aFileName.startswith(SRCDIR "/cppuhelper/") + || aFileName.startswith(SRCDIR "/comphelper/") + // dont know how to detect this in clang - it is making an explicit call to it's own method, so presumably OK + || aFileName == SRCDIR "/basic/source/sbx/sbxvalue.cxx" + ) + return true; + mbChecking = true; + Stmt * pStmt = pCXXDestructorDecl->getBody(); + TraverseStmt(pStmt); + mbChecking = false; + return true; +} + +bool FragileDestructor::VisitCXXMemberCallExpr(const CXXMemberCallExpr* callExpr) +{ + if (!mbChecking || ignoreLocation(callExpr)) { + return true; + } + const CXXMethodDecl* methodDecl = callExpr->getMethodDecl(); + if (!methodDecl->isVirtual() || methodDecl->hasAttr<FinalAttr>()) { + return true; + } + const CXXRecordDecl* parentRecordDecl = methodDecl->getParent(); + if (parentRecordDecl->hasAttr<FinalAttr>()) { + return true; + } + if (!callExpr->getImplicitObjectArgument()->IgnoreImpCasts()->isImplicitCXXThis()) { + return true; + } + // if we see an explicit call to it's own method, thats OK + auto s1 = compiler.getSourceManager().getCharacterData(callExpr->getLocStart()); + auto s2 = compiler.getSourceManager().getCharacterData(callExpr->getLocEnd()); + std::string tok(s1, s2-s1); + if (tok.find("::") != std::string::npos) { + return true; + } + // e.g. osl/thread.hxx and cppuhelper/compbase.hxx + StringRef aFileName = compiler.getSourceManager().getFilename(compiler.getSourceManager().getSpellingLoc(methodDecl->getLocStart())); + if (aFileName.startswith(SRCDIR "/include/osl/") + || aFileName.startswith(SRCDIR "/include/comphelper/") + || aFileName.startswith(SRCDIR "/include/cppuhelper/")) + return true; + report( + DiagnosticsEngine::Warning, + "calling virtual method from destructor, either make the virtual method SAL_FINAL, or make this class SAL_FINAL", + callExpr->getLocStart()) + << callExpr->getSourceRange(); + report( + DiagnosticsEngine::Note, + "callee method here", + methodDecl->getLocStart()) + << methodDecl->getSourceRange(); + return true; +} + + +loplugin::Plugin::Registration< FragileDestructor > X("fragiledestructor", false); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |