diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2015-02-07 10:15:30 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2015-02-07 12:35:55 +0100 |
commit | d2e9b222d7025c53aa82e5718418ea712d21ac3c (patch) | |
tree | 163c39a9c94af0d9460e6d3f576a5021954f8ee5 | |
parent | 905d4db48a0b98f540c8abc3e12fb80be4826029 (diff) |
loplugin:deletedspecial to help add SAL_DELETED_FUNCTION annotations
...to special member function declarations that were left undefined. Helps
compilers do a better job at identifiying unused class members. This plugin
uses heuristics and whitelists do identify applicable declarations, but is not
appropriate for "unattended" use so is placed into store/.
The following commits contain the results of running this plugin, per module:
* Declarations of undefined special member functions are mmarked
SAL_DELETED_FUNCTION (aka "= delete", which is deemed superior to deriving the
class from boost::noncopyable, cf. Howard Hinnant's reply to
<http://stackoverflow.com/questions/7823990/what-are-the-advantages-of-boostnoncopyable>.
* Any redundant "explicit" or SAL_DLLPRIVATE markers are removed from the
deleted definitions.
* Some redundant declarations of undefined default ctors are simply removed;
smelled like clueless cargo-cult to have them declared at all.
* Some declarations of undefined operator == etc. are left in (and marked
SAL_DELETED_FUNCTION) for now, to be on the safe side, though they are likely
clueless cargo-cult, too.
* Most "static-only" classes are replaced with namespaces (and some where that
would be non-trivial due to private members are marked TODO for later).
* Newly identified unused class members are removed.
Change-Id: Ibeaae4fd579d7a0971a2c2a654a2263acd13414a
-rw-r--r-- | compilerplugins/clang/store/deletedspecial.cxx | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/compilerplugins/clang/store/deletedspecial.cxx b/compilerplugins/clang/store/deletedspecial.cxx new file mode 100644 index 000000000000..7b23e2005b1d --- /dev/null +++ b/compilerplugins/clang/store/deletedspecial.cxx @@ -0,0 +1,151 @@ +/* -*- 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 <iterator> +#include <string> + +#include "compat.hxx" +#include "plugin.hxx" + +// Second-guess that certain private special member function declarations for +// which no definition can be found are left undefined to prevent them from +// being implicitly declared. Such situations are better expressed by marking +// the function as SAL_DELETED_FUNCTION (it e.g. helps compilers determine +// whether class members are unused if all of a class's member definitions are +// seen in a compilation unit). (Default constructors for classes with multiple +// constructors are exempted as they would not be implicitly declared. +// Destructors are exempted because it is likely that a destructor is defined +// private on purpose.) + +namespace { + +CXXRecordDecl const * getClass(CXXMethodDecl const * decl) { + CXXRecordDecl const * cls = dyn_cast<CXXRecordDecl>(decl->getDeclContext()); + assert(cls != nullptr); + return cls; +} + +class DeletedSpecial: + public RecursiveASTVisitor<DeletedSpecial>, public loplugin::Plugin +{ +public: + explicit DeletedSpecial(InstantiationData const & data): Plugin(data) {} + + virtual void run() override; + + bool VisitCXXMethodDecl(CXXMethodDecl const * decl); + +private: + bool whitelist( + CXXMethodDecl const * decl, std::string const & name, + std::string const & path); +}; + +void DeletedSpecial::run() { + if (compiler.getLangOpts().CPlusPlus + && compiler.getPreprocessor().getIdentifierInfo( + "LIBO_INTERNAL_ONLY")->hasMacroDefinition()) + { + TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); + } +} + +bool DeletedSpecial::VisitCXXMethodDecl(CXXMethodDecl const * decl) { + if (ignoreLocation(decl) || !compat::isFirstDecl(*decl) || decl->isDefined() + || decl->isDefaulted() || decl->getAccess() != AS_private) + { + return true; + } + std::string desc; + if (decl->isCopyAssignmentOperator()) { + if (whitelist(decl, "ImpGraphic", "vcl/inc/impgraph.hxx") + || whitelist(decl, "SwSubFont", "sw/source/core/inc/swfont.hxx")) + { + return true; + } + desc = "copy assignment operator"; + } else if (decl->isMoveAssignmentOperator()) { + desc = "move assignment operator"; + } else { + CXXConstructorDecl const * ctor = dyn_cast<CXXConstructorDecl>(decl); + CXXRecordDecl const * cls = getClass(decl); + if (ctor != nullptr && ctor->isCopyConstructor()) { + if (whitelist(decl, "ImpGraphic", "vcl/inc/impgraph.hxx") + || whitelist(decl, "SbMethod", "include/basic/sbmeth.hxx") + || whitelist(decl, "ScDBCollection::NamedDBs", "sc/inc/dbdata.hxx") + || whitelist(decl, "ScDrawPage", "sc/inc/drawpage.hxx") + || whitelist(decl, "ScFormEditData", "sc/source/ui/inc/formdata.hxx") + || whitelist(decl, "SmEditSource", "starmath/source/accessibility.hxx") + || whitelist(decl, "SwChartDataSequence", "sw/inc/unochart.hxx") + || whitelist(decl, "SwDPage", "sw/inc/dpage.hxx") + || whitelist(decl, "SwRedlineExtraData_Format", "sw/inc/redline.hxx") + || whitelist(decl, "SwRedlineExtraData_FormattingChanges", "sw/inc/redline.hxx") + || whitelist(decl, "SwTextAPIEditSource", "sw/source/core/inc/textapi.hxx") + || whitelist(decl, "XclImpBiff5Decrypter", "sc/source/filter/inc/xistream.hxx") + || whitelist(decl, "XclImpBiff8Decrypter", "sc/source/filter/inc/xistream.hxx") + || whitelist(decl, "configmgr::LocalizedPropertyNode", "configmgr/source/localizedpropertynode.hxx") + || whitelist(decl, "configmgr::LocalizedValueNode", "configmgr/source/localizedvaluenode.hxx") + || whitelist(decl, "configmgr::PropertyNode", "configmgr/source/propertynode.hxx") + || whitelist(decl, "oox::xls::BiffDecoder_RCF", "sc/source/filter/inc/biffcodec.hxx") + || whitelist(decl, "oox::xls::BiffDecoder_XOR", "sc/source/filter/inc/biffcodec.hxx") + || whitelist(decl, "rptui::OReportPage", "reportdesign/inc/RptPage.hxx")) + { + return true; + } + desc = "copy constructor"; + } else if (ctor != nullptr && ctor->isMoveConstructor()) { + desc = "move constructor"; + } else if (ctor != nullptr && ctor->isDefaultConstructor() + && std::distance(cls->ctor_begin(), cls->ctor_end()) == 1) + { + if (whitelist(decl, "DocTemplLocaleHelper", "sfx2/source/doc/doctemplateslocal.hxx") + || whitelist(decl, "ScViewDataTable", "sc/source/filter/excel/../../ui/inc/viewdata.hxx") + || whitelist(decl, "ScViewDataTable", "sc/source/ui/inc/viewdata.hxx") + || whitelist(decl, "SwLineInfo", "sw/source/core/text/inftxt.hxx") + || whitelist(decl, "XRenderPeer", "vcl/unx/generic/gdi/xrender_peer.hxx") + || whitelist(decl, "desktop::OfficeIPCThread", "desktop/source/app/officeipcthread.hxx") + || whitelist(decl, "desktop::OfficeIPCThread", "desktop/source/lib/../app/officeipcthread.hxx") + || whitelist(decl, "sd::DiscoveryService", "sd/source/ui/remotecontrol/DiscoveryService.hxx") + || whitelist(decl, "sd::IconCache", "sd/source/ui/inc/tools/IconCache.hxx") + || whitelist(decl, "sd::slidesorter::cache::PageCacheManager", "sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx") + || whitelist(decl, "sfx2::sidebar::CommandInfoProvider", "include/sfx2/sidebar/CommandInfoProvider.hxx") + || whitelist(decl, "writerfilter::ooxml::OOXMLFactory", "writerfilter/source/ooxml/OOXMLFactory.hxx")) + { + return true; + } + desc = "default constructor"; + } else { + return true; + } + } + report( + DiagnosticsEngine::Warning, + ("private %0 is not defined at least in this compilation unit, maybe it" + " should be marked as deleted?"), + decl->getLocation()) + << desc << decl->getSourceRange(); + return true; +} + +bool DeletedSpecial::whitelist( + CXXMethodDecl const * decl, std::string const & name, + std::string const & path) +{ + return getClass(decl)->getQualifiedNameAsString() == name + && (compiler.getSourceManager().getFilename( + compiler.getSourceManager().getSpellingLoc(decl->getLocation())) + == SRCDIR "/" + path); +} + +loplugin::Plugin::Registration<DeletedSpecial> X("deletedspecial", true); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |