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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
16 #include "clang/AST/CXXInheritance.h"
19 // Check for calls to virtual methods from destructors. These are dangerous because intention might be to call
20 // a method on a subclass, while in actual fact, it only calls the method on the current or super class.
25 class FragileDestructor
:
26 public loplugin::FilteringPlugin
<FragileDestructor
>
29 explicit FragileDestructor(loplugin::InstantiationData
const & data
):
30 FilteringPlugin(data
) {}
32 virtual bool preRun() override
34 StringRef
fn(handler
.getMainFileName());
36 // TODO, these all need fixing
38 if (loplugin::isSamePathname(fn
, SRCDIR
"/comphelper/source/misc/proxyaggregation.cxx"))
40 if (loplugin::isSamePathname(fn
, SRCDIR
"/svx/source/svdraw/svdpntv.cxx")) // ~SdrPaintView calling ClearPageView
42 if (loplugin::isSamePathname(fn
, SRCDIR
"/svx/source/svdraw/svdobj.cxx")) // ~SdrObject calling GetLastBoundRect
44 if (loplugin::isSamePathname(fn
, SRCDIR
"/svx/source/svdraw/svdedxv.cxx")) // ~SdrObjEditView calling SdrEndTextEdit
46 if (loplugin::isSamePathname(fn
, SRCDIR
"/connectivity/source/drivers/file/FStatement.cxx")) // ~OStatement_Base calling disposing
48 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/core/CustomAnimationEffect.cxx")) // ~EffectSequenceHelper calling reset
50 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/view/sdview.cxx")) // ~View calling DeleteWindowFromPaintView
52 if (loplugin::isSamePathname(fn
, SRCDIR
"/sw/source/core/layout/ssfrm.cxx")) // ~SwFrame calling IsDeleteForbidden
58 virtual void run() override
61 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
64 bool PreTraverseCXXDestructorDecl(CXXDestructorDecl
*);
65 bool PostTraverseCXXDestructorDecl(CXXDestructorDecl
*, bool);
66 bool TraverseCXXDestructorDecl(CXXDestructorDecl
*);
67 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr
*);
70 std::vector
<CXXDestructorDecl
*> m_vDestructors
;
73 bool FragileDestructor::PreTraverseCXXDestructorDecl(CXXDestructorDecl
* cxxDestructorDecl
)
75 if (ignoreLocation(cxxDestructorDecl
))
77 if (!cxxDestructorDecl
->isThisDeclarationADefinition())
79 if (cxxDestructorDecl
->getParent()->hasAttr
<FinalAttr
>())
81 m_vDestructors
.push_back(cxxDestructorDecl
);
85 bool FragileDestructor::PostTraverseCXXDestructorDecl(CXXDestructorDecl
* cxxDestructorDecl
, bool)
87 if (!m_vDestructors
.empty() && m_vDestructors
.back() == cxxDestructorDecl
)
88 m_vDestructors
.pop_back();
92 bool FragileDestructor::TraverseCXXDestructorDecl(CXXDestructorDecl
* cxxDestructorDecl
)
94 PreTraverseCXXDestructorDecl(cxxDestructorDecl
);
95 auto ret
= FilteringPlugin::TraverseCXXDestructorDecl(cxxDestructorDecl
);
96 PostTraverseCXXDestructorDecl(cxxDestructorDecl
, ret
);
100 bool FragileDestructor::VisitCXXMemberCallExpr(const CXXMemberCallExpr
* callExpr
)
102 if (m_vDestructors
.empty() || ignoreLocation(callExpr
))
104 const CXXMethodDecl
* methodDecl
= callExpr
->getMethodDecl();
105 if (!methodDecl
->isVirtual() || methodDecl
->hasAttr
<FinalAttr
>())
107 const CXXRecordDecl
* parentRecordDecl
= methodDecl
->getParent();
108 if (parentRecordDecl
->hasAttr
<FinalAttr
>())
110 if (!callExpr
->getImplicitObjectArgument()->IgnoreImpCasts()->isImplicitCXXThis())
113 // if we see an explicit call to its own method, that's OK
114 auto s1
= compiler
.getSourceManager().getCharacterData(compat::getBeginLoc(callExpr
));
115 auto s2
= compiler
.getSourceManager().getCharacterData(compat::getEndLoc(callExpr
));
116 std::string
tok(s1
, s2
-s1
);
117 if (tok
.find("::") != std::string::npos
)
120 // Very common pattern that we call acquire/dispose in destructors of UNO objects
121 // to make sure they are cleaned up.
122 if (methodDecl
->getName() == "acquire" || methodDecl
->getName() == "dispose")
126 DiagnosticsEngine::Warning
,
127 "calling virtual method from destructor, either make the virtual method final, or make this class final",
128 compat::getBeginLoc(callExpr
))
129 << callExpr
->getSourceRange();
131 DiagnosticsEngine::Note
,
132 "callee method here",
133 compat::getBeginLoc(methodDecl
))
134 << methodDecl
->getSourceRange();
139 loplugin::Plugin::Registration
<FragileDestructor
> fragiledestructor("fragiledestructor");
143 #endif // LO_CLANG_SHARED_PLUGINS
145 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */