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/.
16 #include <clang/AST/CXXInheritance.h>
22 Look for calls to the ref-counting methods acquire()/release(), which should only be called by classes like rtl::Reference.
28 public RecursiveASTVisitor
<ManualRefCount
>, public loplugin::Plugin
31 explicit ManualRefCount(InstantiationData
const & data
): Plugin(data
) {}
33 virtual void run() override
35 StringRef
fn( compiler
.getSourceManager().getFileEntryForID(
36 compiler
.getSourceManager().getMainFileID())->getName() );
38 // old code, no point in updating
39 if (loplugin::isSamePathname(fn
, SRCDIR
"/store/source/store.cxx"))
42 // TODO -----------------------------
43 if (loplugin::isSamePathname(fn
, SRCDIR
"/registry/source/registry.cxx"))
45 if (loplugin::isSamePathname(fn
, SRCDIR
"/registry/source/regimpl.cxx"))
47 if (loplugin::isSamePathname(fn
, SRCDIR
"/registry/source/reflread.cxx"))
49 // TODO MenuAttributes::CreateAttribute
50 if (loplugin::isSamePathname(fn
, SRCDIR
"/framework/source/fwe/xml/menuconfiguration.cxx"))
52 if (loplugin::isSamePathname(fn
, SRCDIR
"/sw/source/uibase/app/apphdl.cxx"))
54 if (loplugin::isSamePathname(fn
, SRCDIR
"/dbaccess/source/core/dataaccess/ModelImpl.cxx"))
56 // need a better replacement for vcl::EventPoster
57 if (loplugin::isSamePathname(fn
, SRCDIR
"/svtools/source/misc/acceleratorexecute.cxx"))
59 // PostUserEvent stuff
60 if (loplugin::isSamePathname(fn
, SRCDIR
"/toolkit/source/awt/vclxwindow.cxx"))
62 // playing games with pointers passed into combobox entries
63 if (loplugin::isSamePathname(fn
, SRCDIR
"/cui/source/customize/cfgutil.cxx"))
65 if (loplugin::isSamePathname(fn
, SRCDIR
"/cui/source/customize/cfg.cxx"))
67 // END TODO -----------------------------
69 // can't fix these without breaking stable ABI
70 if (fn
.startswith(SRCDIR
"/sal/"))
72 if (fn
.startswith(SRCDIR
"/salhelper/"))
74 if (fn
.startswith(SRCDIR
"/cppu/"))
76 if (fn
.startswith(SRCDIR
"/cppuhelper/"))
78 if (fn
.startswith(SRCDIR
"/bridges/"))
82 if (fn
.startswith(SRCDIR
"/stoc/"))
84 if (fn
.startswith(SRCDIR
"/testtools/"))
88 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/source/app/scheduler.cxx"))
91 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/source/app/svdata.cxx"))
94 // passing the pointer through PostUserEvent
95 if (loplugin::isSamePathname(fn
, SRCDIR
"/avmedia/source/gstreamer/gstplayer.cxx"))
97 if (loplugin::isSamePathname(fn
, SRCDIR
"/svx/source/form/fmscriptingenv.cxx"))
101 if (loplugin::isSamePathname(fn
, SRCDIR
"/io/source/stm/opump.cxx"))
104 // ??? no idea what this code is up to
105 if (loplugin::isSamePathname(fn
, SRCDIR
"/extensions/source/scanner/scanunx.cxx"))
107 if (loplugin::isSamePathname(fn
, SRCDIR
"/stoc/source/invocation_adapterfactory/iafactory.cxx"))
109 if (loplugin::isSamePathname(fn
, SRCDIR
"/fpicker/source/office/asyncfilepicker.cxx"))
111 if (loplugin::isSamePathname(fn
, SRCDIR
"/forms/source/component/FormComponent.cxx"))
113 if (loplugin::isSamePathname(fn
, SRCDIR
"/ucb/source/ucp/file/bc.cxx"))
115 if (loplugin::isSamePathname(fn
, SRCDIR
"/ucb/source/ucp/file/filprp.cxx"))
117 // calling release() ?
118 if (loplugin::isSamePathname(fn
, SRCDIR
"/toolkit/source/helper/accessibilityclient.cxx"))
120 if (loplugin::isSamePathname(fn
, SRCDIR
"/svtools/source/misc/svtaccessiblefactory.cxx"))
123 // implementing css::uno::XInterface
124 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/animations/motionpathtag.cxx"))
126 // UNO factory methods
127 if (fn
.startswith(SRCDIR
"/comphelper/"))
129 if (loplugin::isSamePathname(fn
, SRCDIR
"/linguistic/source/convdiclist.cxx"))
131 if (loplugin::isSamePathname(fn
, SRCDIR
"/linguistic/source/dlistimp.cxx"))
133 if (loplugin::isSamePathname(fn
, SRCDIR
"/linguistic/source/gciterator.cxx"))
135 if (loplugin::isSamePathname(fn
, SRCDIR
"/linguistic/source/lngsvcmgr.cxx"))
137 if (loplugin::isSamePathname(fn
, SRCDIR
"/linguistic/source/lngopt.cxx"))
139 if (loplugin::isSamePathname(fn
, SRCDIR
"/vcl/unx/generic/gdi/gcach_xpeer.cxx"))
141 if (loplugin::isSamePathname(fn
, SRCDIR
"/dbaccess/source/ui/dlg/dbwizsetup.cxx"))
143 if (loplugin::isSamePathname(fn
, SRCDIR
"/dbaccess/source/ui/dlg/dbwizsetup.cxx"))
145 if (loplugin::isSamePathname(fn
, SRCDIR
"/lingucomponent/source/hyphenator/hyphen/hyphenimp.cxx"))
147 if (loplugin::isSamePathname(fn
, SRCDIR
"/lingucomponent/source/spellcheck/spell/sspellimp.cxx"))
149 if (loplugin::isSamePathname(fn
, SRCDIR
"/lingucomponent/source/thesaurus/libnth/nthesimp.cxx"))
153 // some kind of complicated listener nonsense
154 if (loplugin::isSamePathname(fn
, SRCDIR
"/sd/source/ui/framework/tools/FrameworkHelper.cxx"))
156 // more listener nonsense
157 if (loplugin::isSamePathname(fn
, SRCDIR
"/sw/source/uibase/uno/unomailmerge.cxx"))
159 // playing games with it's listener list
160 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/unoobj/cellsuno.cxx"))
162 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/unoobj/chart2uno.cxx"))
164 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/unoobj/dapiuno.cxx"))
166 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/unoobj/datauno.cxx"))
168 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/unoobj/linkuno.cxx"))
171 if (loplugin::isSamePathname(fn
, SRCDIR
"/sc/source/ui/vba/vbaeventshelper.cxx"))
173 // thread holding itself
174 if (loplugin::isSamePathname(fn
, SRCDIR
"/forms/source/component/EventThread.cxx"))
178 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
181 bool shouldVisitTemplateInstantiations () const { return true; }
183 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr
*);
184 bool TraverseCXXRecordDecl(CXXRecordDecl
*);
185 bool TraverseCXXMethodDecl(CXXMethodDecl
*);
186 bool TraverseFunctionDecl(FunctionDecl
*);
187 bool TraverseCXXConstructorDecl(CXXConstructorDecl
*);
188 bool TraverseCXXDestructorDecl(CXXDestructorDecl
*);
189 bool TraverseCXXConversionDecl(CXXConversionDecl
*);
190 bool TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl
*);
191 bool TraverseLinkageSpecDecl(LinkageSpecDecl
*);
193 bool ignoreCallerClass(CXXRecordDecl
*);
196 bool ManualRefCount::TraverseCXXMethodDecl(CXXMethodDecl
* cxxMethodDecl
)
198 if (ignoreCallerClass(cxxMethodDecl
->getParent()))
200 // disambiguating forwarding methods for XInterface subclasses
201 if (cxxMethodDecl
->getIdentifier() && (cxxMethodDecl
->getName() == "acquire" || cxxMethodDecl
->getName() == "release"))
203 return RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl
);
206 bool ManualRefCount::TraverseFunctionDecl(FunctionDecl
* functionDecl
)
208 auto tc
= loplugin::DeclCheck(functionDecl
);
209 if (tc
.Function("make_shared_from_UNO").Namespace("comphelper").GlobalNamespace())
211 return RecursiveASTVisitor::TraverseFunctionDecl(functionDecl
);
214 bool ManualRefCount::TraverseCXXConstructorDecl(CXXConstructorDecl
* cxxMethodDecl
)
216 if (ignoreCallerClass(cxxMethodDecl
->getParent()))
218 return RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl
);
221 bool ManualRefCount::TraverseCXXDestructorDecl(CXXDestructorDecl
*)
223 // just ignore destructors, tons of places like to call acquire() on themselves in their destructor
224 // supposedly to prevent recursively calling the destructor
227 bool ManualRefCount::TraverseCXXConversionDecl(CXXConversionDecl
* cxxMethodDecl
)
229 if (ignoreCallerClass(cxxMethodDecl
->getParent()))
231 return RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl
);
233 bool ManualRefCount::TraverseCXXRecordDecl(CXXRecordDecl
* cxxRecordDecl
)
235 if (ignoreCallerClass(cxxRecordDecl
))
237 return RecursiveASTVisitor::TraverseCXXRecordDecl(cxxRecordDecl
);
240 bool ManualRefCount::TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl
* templateDecl
)
242 if (ignoreCallerClass(templateDecl
))
244 return RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(templateDecl
);
247 bool ManualRefCount::TraverseLinkageSpecDecl(LinkageSpecDecl
*)
249 // ignore methods inside "extern ""C""" blocks, these are normally UNO constructors, which
250 // are required to raise the reference count before returning
254 bool ManualRefCount::ignoreCallerClass(CXXRecordDecl
* cxxRecordDecl
)
256 auto tc
= loplugin::TypeCheck(cxxRecordDecl
);
258 tc
.Class("Reference").Namespace("rtl").GlobalNamespace()
259 || tc
.Class("cow_wrapper").Namespace("o3tl").GlobalNamespace()
260 || tc
.Class("Reference").Namespace("uno").Namespace("star").Namespace("sun").Namespace("com").GlobalNamespace()
261 || tc
.Class("ShareGuard").Namespace("framework").GlobalNamespace()
262 || tc
.Class("ControlModelLock").Namespace("frm").GlobalNamespace()
263 || tc
.Struct("ReleaseFunc").Namespace("detail").Namespace("comphelper").GlobalNamespace()
264 // TODO no idea what this is up to
265 || tc
.Class("SfxModelSubComponent").GlobalNamespace()
266 || tc
.Class("OSubComponent").Namespace("mysqlc").Namespace("connectivity").GlobalNamespace()
267 || tc
.Class("OSubComponent").Namespace("connectivity").GlobalNamespace()
268 // TODO do we really need this?
269 || tc
.Class("ShareableMutex").Namespace("framework").GlobalNamespace()
270 || tc
.Class("ObservableThread").GlobalNamespace()
274 bool ManualRefCount::VisitCXXMemberCallExpr(const CXXMemberCallExpr
* cxxMemberCallExpr
)
276 if (ignoreLocation(cxxMemberCallExpr
))
278 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(cxxMemberCallExpr
->getLocStart())))
281 // first, use some heuristics to find the right kind of acquire()/release() calls
282 CXXMethodDecl
const * calleeMethodDecl
= cxxMemberCallExpr
->getMethodDecl();
283 if (!calleeMethodDecl
|| !calleeMethodDecl
->getIdentifier())
285 if (calleeMethodDecl
->getName() != "acquire" && calleeMethodDecl
->getName() != "release")
287 if (calleeMethodDecl
->getNumParams() != 0)
289 // std::unique_ptr::release() and similar methods
290 if (calleeMethodDecl
->getName() == "release" && loplugin::TypeCheck(calleeMethodDecl
->getReturnType()).Pointer())
294 auto calleeRecordTC
= loplugin::TypeCheck(calleeMethodDecl
->getParent());
295 if (calleeRecordTC
.Struct("ResourceHolder").Namespace("store").GlobalNamespace())
297 if (calleeRecordTC
.Class("Module").Namespace("osl").GlobalNamespace())
299 if (calleeRecordTC
.Class("Mutex").Namespace("osl").GlobalNamespace())
301 if (calleeRecordTC
.Class("multi_type_vector").Namespace("mdds").GlobalNamespace())
304 // while (calleeMethodDecl->size_overridden_methods() > 0)
305 // calleeMethodDecl = *calleeMethodDecl->begin_overridden_methods();
306 // auto tc2 = loplugin::TypeCheck(calleeMethodDecl->getParent());
307 // if (tc2.Class("XInterface").Namespace("uno").Namespace("star").Namespace("sun").Namespace("com").GlobalNamespace())
310 std::cout
<< calleeMethodDecl
->getParent()->getQualifiedNameAsString() << std::endl
;
312 DiagnosticsEngine::Warning
, "call to acquire/release",
313 cxxMemberCallExpr
->getLocStart())
314 << cxxMemberCallExpr
->getSourceRange();
319 loplugin::Plugin::Registration
< ManualRefCount
> X("manualrefcount", true);
323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */