bump product version to 6.4.0.3
[LibreOffice.git] / compilerplugins / clang / weakobject.cxx
blobafa652befc1ac1d86fbd785c494757d1a23c148c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #ifndef LO_CLANG_SHARED_PLUGINS
12 #include "check.hxx"
13 #include "plugin.hxx"
15 /* OWeakObject::release() disposes weak references. If that isn't done
16 * because a sub-class improperly overrides release() then
17 * OWeakConnectionPoint::m_pObject continues to point to the deleted object
18 * and that could result in use-after-free.
21 namespace {
23 class WeakObject
24 : public loplugin::FilteringPlugin<WeakObject>
27 public:
28 explicit WeakObject(loplugin::InstantiationData const& rData): FilteringPlugin(rData)
31 virtual bool preRun() override {
32 return compiler.getLangOpts().CPlusPlus; // no OWeakObject in C
34 void run() override {
35 if( preRun()) {
36 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
40 bool isDerivedFromOWeakObject(CXXMethodDecl const*const pMethodDecl)
42 QualType const pClass(pMethodDecl->getParent()->getTypeForDecl(), 0);
43 if (loplugin::TypeCheck(pClass).Class("OWeakObject").Namespace("cppu"))
45 return true;
47 // hopefully it's faster to recurse overridden methods than the
48 // thicket of WeakImplHelper32 but that is purely speculation
49 for (auto it = pMethodDecl->begin_overridden_methods();
50 it != pMethodDecl->end_overridden_methods(); ++it)
52 if (isDerivedFromOWeakObject(*it))
54 return true;
57 return false;
60 bool VisitCXXMethodDecl(CXXMethodDecl const*const pMethodDecl)
62 if (ignoreLocation(pMethodDecl)) {
63 return true;
65 if (!pMethodDecl->isThisDeclarationADefinition()
66 || pMethodDecl->isLateTemplateParsed())
68 return true;
70 if (!pMethodDecl->isInstance()) {
71 return true;
73 // this is too "simple", if a NamedDecl class has a getName() member expecting it to actually work would clearly be unreasonable if (pMethodDecl->getName() != "release") {
74 if (auto const i = pMethodDecl->getIdentifier()) {
75 if (i != nullptr && !i->isStr("release")) {
76 return true;
79 if (pMethodDecl->getNumParams() != 0) {
80 return true;
82 if (loplugin::TypeCheck(QualType(pMethodDecl->getParent()->getTypeForDecl(), 0)).Class("OWeakObject").Namespace("cppu"))
84 return true;
87 CXXMethodDecl const* pOverridden(nullptr);
88 for (auto it = pMethodDecl->begin_overridden_methods();
89 it != pMethodDecl->end_overridden_methods(); ++it)
91 if (auto const i = (*it)->getIdentifier()) {
92 if (i != nullptr && i->isStr("release")) {
93 pOverridden = *it;
94 break;
98 if (pOverridden == nullptr)
100 return true;
102 if (!isDerivedFromOWeakObject(pOverridden))
104 return true;
106 CompoundStmt const*const pCompoundStatement(
107 dyn_cast<CompoundStmt>(pMethodDecl->getBody()));
108 for (auto i = pCompoundStatement->body_begin();
109 i != pCompoundStatement->body_end(); ++i)
111 // note: this is not a CXXMemberCallExpr
112 CallExpr const*const pCallExpr(dyn_cast<CallExpr>(*i));
113 if (pCallExpr)
115 // note: this is only sometimes a CXXMethodDecl
116 FunctionDecl const*const pCalled(pCallExpr->getDirectCallee());
117 if (pCalled->getName() == "release")
119 //this never works && pCalled == pOverridden
120 if (pCalled->getParent() == pOverridden->getParent())
122 return true;
124 // Allow this convenient shortcut:
125 auto td = dyn_cast<TypeDecl>(pCalled->getParent());
126 if (td != nullptr
127 && (loplugin::TypeCheck(td).Class("OWeakObject").Namespace("cppu").GlobalNamespace()
128 || loplugin::TypeCheck(td).Class("OWeakAggObject").Namespace("cppu").GlobalNamespace()))
130 return true;
136 // whitelist
137 auto tc = loplugin::TypeCheck(pMethodDecl->getParent());
138 if ( tc.Class("OWeakAggObject").Namespace("cppu").GlobalNamespace() // conditional call
139 || tc.Class("WeakComponentImplHelperBase").Namespace("cppu").GlobalNamespace() // extra magic
140 || tc.Class("WeakAggComponentImplHelperBase").Namespace("cppu").GlobalNamespace() // extra magic
141 || tc.Class("CDOMImplementation").Namespace("DOM").GlobalNamespace() // a static oddity
142 || tc.Class("SwXTextFrame").GlobalNamespace() // ambiguous, 3 parents
143 || tc.Class("SwXTextDocument").GlobalNamespace() // ambiguous, ~4 parents
144 || tc.Class("SdStyleSheet").GlobalNamespace() // same extra magic as WeakComponentImplHelperBase
145 || tc.Class("SdXImpressDocument").GlobalNamespace() // same extra magic as WeakComponentImplHelperBase
148 return true;
151 report(DiagnosticsEngine::Warning,
152 "override of OWeakObject::release() does not call superclass release()",
153 pMethodDecl->getLocation())
154 << pMethodDecl->getSourceRange();
156 return true;
161 loplugin::Plugin::Registration<WeakObject> weakobject("weakobject");
163 } // namespace
165 #endif // LO_CLANG_SHARED_PLUGINS
167 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */