1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #ifndef LO_CLANG_SHARED_PLUGINS
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.
24 : public loplugin::FilteringPlugin
<WeakObject
>
28 explicit WeakObject(loplugin::InstantiationData
const& rData
): FilteringPlugin(rData
)
31 virtual bool preRun() override
{
32 return compiler
.getLangOpts().CPlusPlus
; // no OWeakObject in C
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"))
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
))
60 bool VisitCXXMethodDecl(CXXMethodDecl
const*const pMethodDecl
)
62 if (ignoreLocation(pMethodDecl
)) {
65 if (!pMethodDecl
->isThisDeclarationADefinition()
66 || pMethodDecl
->isLateTemplateParsed())
70 if (!pMethodDecl
->isInstance()) {
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")) {
79 if (pMethodDecl
->getNumParams() != 0) {
82 if (loplugin::TypeCheck(QualType(pMethodDecl
->getParent()->getTypeForDecl(), 0)).Class("OWeakObject").Namespace("cppu"))
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")) {
98 if (pOverridden
== nullptr)
102 if (!isDerivedFromOWeakObject(pOverridden
))
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
));
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())
124 // Allow this convenient shortcut:
125 auto td
= dyn_cast
<TypeDecl
>(pCalled
->getParent());
127 && (loplugin::TypeCheck(td
).Class("OWeakObject").Namespace("cppu").GlobalNamespace()
128 || loplugin::TypeCheck(td
).Class("OWeakAggObject").Namespace("cppu").GlobalNamespace()))
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
151 report(DiagnosticsEngine::Warning
,
152 "override of OWeakObject::release() does not call superclass release()",
153 pMethodDecl
->getLocation())
154 << pMethodDecl
->getSourceRange();
161 loplugin::Plugin::Registration
<WeakObject
> weakobject("weakobject");
165 #endif // LO_CLANG_SHARED_PLUGINS
167 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */