summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/refcountingbase.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/refcountingbase.cxx')
-rw-r--r--compilerplugins/clang/refcountingbase.cxx141
1 files changed, 141 insertions, 0 deletions
diff --git a/compilerplugins/clang/refcountingbase.cxx b/compilerplugins/clang/refcountingbase.cxx
new file mode 100644
index 0000000000..dddc7335e8
--- /dev/null
+++ b/compilerplugins/clang/refcountingbase.cxx
@@ -0,0 +1,141 @@
+/* -*- 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/.
+ */
+
+#ifndef LO_CLANG_SHARED_PLUGINS
+
+#include <string>
+#include <iostream>
+#include <map>
+#include <set>
+
+#include "plugin.hxx"
+#include "check.hxx"
+#include "clang/AST/CXXInheritance.h"
+
+/**
+ * Make sure a class does not have multiple reference-counting base classes
+ */
+namespace
+{
+class RefCountingBase : public loplugin::FilteringPlugin<RefCountingBase>
+{
+public:
+ explicit RefCountingBase(loplugin::InstantiationData const& data)
+ : FilteringPlugin(data)
+ {
+ }
+
+ bool preRun() override { return compiler.getLangOpts().CPlusPlus; }
+
+ void run() override
+ {
+ if (preRun())
+ {
+ TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
+ }
+ }
+
+ bool VisitCXXRecordDecl(CXXRecordDecl const*);
+};
+
+bool RefCountingBase::VisitCXXRecordDecl(CXXRecordDecl const* recordDecl)
+{
+ if (ignoreLocation(recordDecl))
+ return true;
+ if (!recordDecl->isThisDeclarationADefinition())
+ return true;
+
+ int virtualWeakBase = 0;
+ int virtualOWeakObject = 0;
+ int virtualSimpleReferenceObject = 0;
+ int virtualSvRefBase = 0;
+ int virtualXmlImportContenxt = 0;
+ int virtualVclReferenceBase = 0;
+ int noRefCountingBases = 0;
+ std::string basePaths;
+ auto BaseMatchesCallback = [&](const CXXBaseSpecifier* cxxBaseSpecifier, CXXBasePath& Paths) {
+ if (!cxxBaseSpecifier->getType().getTypePtr())
+ return false;
+ const CXXRecordDecl* baseCXXRecordDecl = cxxBaseSpecifier->getType()->getAsCXXRecordDecl();
+ if (!baseCXXRecordDecl)
+ return false;
+ if (baseCXXRecordDecl->isInvalidDecl())
+ return false;
+
+ if (baseCXXRecordDecl->getName() != "WeakBase" // tools::WeakBase
+ && baseCXXRecordDecl->getName() != "OWeakObject" // cppu::WeakBase
+ && baseCXXRecordDecl->getName()
+ != "SimpleReferenceObject" // salhelper::SimpleReferenceObject
+ && baseCXXRecordDecl->getName() != "SvRefBase" // tool::SvRefBase
+ && baseCXXRecordDecl->getName() != "SvXMLImportContext" // in xmloff
+ && baseCXXRecordDecl->getName() != "VclReferenceBase") // in vcl
+ return false;
+ if (cxxBaseSpecifier->isVirtual())
+ {
+ if (baseCXXRecordDecl->getName() == "WeakBase")
+ virtualWeakBase = 1;
+ else if (baseCXXRecordDecl->getName() != "OWeakObject")
+ virtualOWeakObject = 1;
+ else if (baseCXXRecordDecl->getName() != "SimpleReferenceObject")
+ virtualSimpleReferenceObject = 1;
+ else if (baseCXXRecordDecl->getName() != "SvRefBase")
+ virtualSvRefBase = 1;
+ else if (baseCXXRecordDecl->getName() != "SvXMLImportContext")
+ virtualXmlImportContenxt = 1;
+ else if (baseCXXRecordDecl->getName() != "VclReferenceBase")
+ virtualVclReferenceBase = 1;
+ else
+ assert(false);
+ }
+ else
+ ++noRefCountingBases;
+ std::string sPath;
+ for (CXXBasePathElement const& pathElement : Paths)
+ {
+ if (!sPath.empty())
+ {
+ sPath += "->";
+ }
+ if (pathElement.Class->hasDefinition())
+ sPath += pathElement.Class->getNameAsString();
+ else
+ sPath += "???";
+ }
+ sPath += "->";
+ sPath += baseCXXRecordDecl->getNameAsString();
+ if (!basePaths.empty())
+ basePaths += ", ";
+ basePaths += sPath;
+ return false;
+ };
+
+ CXXBasePaths aPaths;
+ recordDecl->lookupInBases(BaseMatchesCallback, aPaths);
+
+ int total = virtualWeakBase + virtualOWeakObject + virtualSimpleReferenceObject
+ + virtualSvRefBase + virtualXmlImportContenxt + virtualVclReferenceBase
+ + noRefCountingBases;
+ if (total > 1)
+ {
+ report(DiagnosticsEngine::Warning,
+ "this class has multiple copies of a reference-counting base class, through "
+ "inheritance paths %0",
+ recordDecl->getBeginLoc())
+ << basePaths << recordDecl->getSourceRange();
+ }
+ return true;
+}
+
+loplugin::Plugin::Registration<RefCountingBase> refcountingbase("refcountingbase", true);
+
+} // namespace
+
+#endif // LO_CLANG_SHARED_PLUGINS
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */