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/.
13 /* OWeakObject::release() disposes weak references. If that isn't done
14 * because a sub-class improperly overrides release() then
15 * OWeakConnectionPoint::m_pObject continues to point to the deleted object
16 * and that could result in use-after-free.
22 : public clang::RecursiveASTVisitor
<WeakObject
>
23 , public loplugin::Plugin
27 explicit WeakObject(loplugin::InstantiationData
const& rData
): Plugin(rData
)
31 if (compiler
.getLangOpts().CPlusPlus
) { // no OWeakObject in C
32 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
36 bool isDerivedFromOWeakObject(CXXMethodDecl
const*const pMethodDecl
)
38 QualType
const pClass(pMethodDecl
->getParent()->getTypeForDecl(), 0);
39 if (loplugin::TypeCheck(pClass
).Class("OWeakObject").Namespace("cppu"))
43 // hopefully it's faster to recurse overridden methods than the
44 // thicket of WeakImplHelper32 but that is purely speculation
45 for (auto it
= pMethodDecl
->begin_overridden_methods();
46 it
!= pMethodDecl
->end_overridden_methods(); ++it
)
48 if (isDerivedFromOWeakObject(*it
))
56 bool VisitCXXMethodDecl(CXXMethodDecl
const*const pMethodDecl
)
58 if (ignoreLocation(pMethodDecl
)) {
61 if (!pMethodDecl
->isThisDeclarationADefinition()
62 || pMethodDecl
->isLateTemplateParsed())
66 if (!pMethodDecl
->isInstance()) {
69 // 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") {
70 if (auto const i
= pMethodDecl
->getIdentifier()) {
71 if (i
!= nullptr && !i
->isStr("release")) {
75 if (pMethodDecl
->getNumParams() != 0) {
78 if (loplugin::TypeCheck(QualType(pMethodDecl
->getParent()->getTypeForDecl(), 0)).Class("OWeakObject").Namespace("cppu"))
83 CXXMethodDecl
const* pOverridden(nullptr);
84 for (auto it
= pMethodDecl
->begin_overridden_methods();
85 it
!= pMethodDecl
->end_overridden_methods(); ++it
)
87 if (auto const i
= (*it
)->getIdentifier()) {
88 if (i
!= nullptr && i
->isStr("release")) {
94 if (pOverridden
== nullptr)
98 if (!isDerivedFromOWeakObject(pOverridden
))
102 CompoundStmt
const*const pCompoundStatement(
103 dyn_cast
<CompoundStmt
>(pMethodDecl
->getBody()));
104 for (auto i
= pCompoundStatement
->body_begin();
105 i
!= pCompoundStatement
->body_end(); ++i
)
107 // note: this is not a CXXMemberCallExpr
108 CallExpr
const*const pCallExpr(dyn_cast
<CallExpr
>(*i
));
111 // note: this is only sometimes a CXXMethodDecl
112 FunctionDecl
const*const pCalled(pCallExpr
->getDirectCallee());
113 if (pCalled
->getName() == "release")
115 //this never works && pCalled == pOverridden
116 if (pCalled
->getParent() == pOverridden
->getParent())
120 // Allow this convenient shortcut:
121 auto td
= dyn_cast
<TypeDecl
>(pCalled
->getParent());
123 && (loplugin::TypeCheck(td
).Class("OWeakObject").Namespace("cppu").GlobalNamespace()
124 || loplugin::TypeCheck(td
).Class("OWeakAggObject").Namespace("cppu").GlobalNamespace()))
133 auto tc
= loplugin::TypeCheck(pMethodDecl
->getParent());
134 if ( tc
.Class("OWeakAggObject").Namespace("cppu").GlobalNamespace() // conditional call
135 || tc
.Class("WeakComponentImplHelperBase").Namespace("cppu").GlobalNamespace() // extra magic
136 || tc
.Class("WeakAggComponentImplHelperBase").Namespace("cppu").GlobalNamespace() // extra magic
137 || tc
.Class("CDOMImplementation").Namespace("DOM").GlobalNamespace() // a static oddity
138 || tc
.Class("SwXTextFrame").GlobalNamespace() // ambiguous, 3 parents
139 || tc
.Class("SwXTextDocument").GlobalNamespace() // ambiguous, ~4 parents
140 || tc
.Class("SdStyleSheet").GlobalNamespace() // same extra magic as WeakComponentImplHelperBase
141 || tc
.Class("SdXImpressDocument").GlobalNamespace() // same extra magic as WeakComponentImplHelperBase
147 report(DiagnosticsEngine::Warning
,
148 "override of OWeakObject::release() does not call superclass release()",
149 pMethodDecl
->getLocation())
150 << pMethodDecl
->getSourceRange();
157 loplugin::Plugin::Registration
<WeakObject
> X("weakobject");
161 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */