[en_US] Added 13 autocorrect words
[LibreOffice.git] / compilerplugins / clang / fragiledestructor.cxx
bloba1a09a2e608190163b478c568c4eb6f444032fbb
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 */
9 #ifndef LO_CLANG_SHARED_PLUGINS
11 #include <string>
12 #include <iostream>
14 #include "plugin.hxx"
15 #include "compat.hxx"
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.
23 namespace {
25 class FragileDestructor:
26 public loplugin::FilteringPlugin<FragileDestructor>
28 public:
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"))
39 return false;
40 if (loplugin::isSamePathname(fn, SRCDIR "/svx/source/svdraw/svdpntv.cxx")) // ~SdrPaintView calling ClearPageView
41 return false;
42 if (loplugin::isSamePathname(fn, SRCDIR "/svx/source/svdraw/svdobj.cxx")) // ~SdrObject calling GetLastBoundRect
43 return false;
44 if (loplugin::isSamePathname(fn, SRCDIR "/svx/source/svdraw/svdedxv.cxx")) // ~SdrObjEditView calling SdrEndTextEdit
45 return false;
46 if (loplugin::isSamePathname(fn, SRCDIR "/connectivity/source/drivers/file/FStatement.cxx")) // ~OStatement_Base calling disposing
47 return false;
48 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/core/CustomAnimationEffect.cxx")) // ~EffectSequenceHelper calling reset
49 return false;
50 if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/view/sdview.cxx")) // ~View calling DeleteWindowFromPaintView
51 return false;
52 if (loplugin::isSamePathname(fn, SRCDIR "/sw/source/core/layout/ssfrm.cxx")) // ~SwFrame calling IsDeleteForbidden
53 return false;
55 return true;
58 virtual void run() override
60 if (preRun())
61 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
64 bool PreTraverseCXXDestructorDecl(CXXDestructorDecl*);
65 bool PostTraverseCXXDestructorDecl(CXXDestructorDecl*, bool);
66 bool TraverseCXXDestructorDecl(CXXDestructorDecl*);
67 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *);
69 private:
70 std::vector<CXXDestructorDecl*> m_vDestructors;
73 bool FragileDestructor::PreTraverseCXXDestructorDecl(CXXDestructorDecl* cxxDestructorDecl)
75 if (ignoreLocation(cxxDestructorDecl))
76 return true;
77 if (!cxxDestructorDecl->isThisDeclarationADefinition())
78 return true;
79 if (cxxDestructorDecl->getParent()->hasAttr<FinalAttr>())
80 return true;
81 m_vDestructors.push_back(cxxDestructorDecl);
82 return true;
85 bool FragileDestructor::PostTraverseCXXDestructorDecl(CXXDestructorDecl* cxxDestructorDecl, bool)
87 if (!m_vDestructors.empty() && m_vDestructors.back() == cxxDestructorDecl)
88 m_vDestructors.pop_back();
89 return true;
92 bool FragileDestructor::TraverseCXXDestructorDecl(CXXDestructorDecl* cxxDestructorDecl)
94 PreTraverseCXXDestructorDecl(cxxDestructorDecl);
95 auto ret = FilteringPlugin::TraverseCXXDestructorDecl(cxxDestructorDecl);
96 PostTraverseCXXDestructorDecl(cxxDestructorDecl, ret);
97 return ret;
100 bool FragileDestructor::VisitCXXMemberCallExpr(const CXXMemberCallExpr* callExpr)
102 if (m_vDestructors.empty() || ignoreLocation(callExpr))
103 return true;
104 const CXXMethodDecl* methodDecl = callExpr->getMethodDecl();
105 if (!methodDecl->isVirtual() || methodDecl->hasAttr<FinalAttr>())
106 return true;
107 const CXXRecordDecl* parentRecordDecl = methodDecl->getParent();
108 if (parentRecordDecl->hasAttr<FinalAttr>())
109 return true;
110 if (!callExpr->getImplicitObjectArgument()->IgnoreImpCasts()->isImplicitCXXThis())
111 return true;
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)
118 return true;
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")
123 return true;
125 report(
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();
130 report(
131 DiagnosticsEngine::Note,
132 "callee method here",
133 compat::getBeginLoc(methodDecl))
134 << methodDecl->getSourceRange();
135 return true;
139 loplugin::Plugin::Registration<FragileDestructor> fragiledestructor("fragiledestructor");
143 #endif // LO_CLANG_SHARED_PLUGINS
145 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */