mirror of
https://github.com/LibreOffice/core.git
synced 2025-08-14 07:48:39 +00:00

Drop the com.sun.star.accessibility.GetStandardAccessibleFactoryService
UNO service that was used to create instances of
the a11y classes for (mainly vcl) widgets.
The service was needed to break a dependency cycle.
However, with
Change-Id: Ib46c87446dc9121d3b8e735e0e5a40594da73cc5
Author: Michael Weghorn <m.weghorn@posteo.de>
Date: Tue Dec 17 12:04:04 2024 +0100
a11y: Merge accessibility module into vcl
and all the preparatory commits in place, there
is no more dependency cycle, as the a11y classes
for vcl widgets no longer depend on any modules
"above" vcl.
Therefore, drop the UNO service and the abstract
vcl::IAccessibleFactory class and other related
classes.
Make all methods in the AccessibleFactory class
(that was previously subclassing the abstract
IAccessibleFactory) static helper methods,
and call them directly.
The UNO service dropped in this commit was
introduced in
commit 1af510e951
Date: Wed Feb 21 11:30:47 2024 +0200
Create an UNO service to do the symbol lookup in toolkit::AccessibilityClient
and its documentation was already clearly stating
that it's only meant for LibreOffice internal use:
> /**
> The toolkit module uses this to get a pointer to the AccessibleFactory from the acc module.
> Because we have a dependency in our modules that goes the "wrong" way.
>
> @since LibreOffice 24.8
>
> @internal
>
> ATTENTION: This is marked <em>internal</em> and does not
> have the <em>published</em> flag, which means it is subject to
> change without notice and should not be used outside the LibreOffice core.
> */
Change-Id: Ib97396a4bad486d9530361dd851ad3ee0f9681b8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178689
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Jenkins
319 lines
13 KiB
C++
319 lines
13 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <set>
|
|
|
|
#include <clang/AST/CXXInheritance.h>
|
|
#include "compat.hxx"
|
|
#include "plugin.hxx"
|
|
#include "check.hxx"
|
|
|
|
/**
|
|
Look for calls to the ref-counting methods acquire()/release(), which should only be called by classes like rtl::Reference.
|
|
*/
|
|
|
|
namespace {
|
|
|
|
class ManualRefCount:
|
|
public RecursiveASTVisitor<ManualRefCount>, public loplugin::Plugin
|
|
{
|
|
public:
|
|
explicit ManualRefCount(InstantiationData const & data): Plugin(data) {}
|
|
|
|
virtual void run() override
|
|
{
|
|
StringRef fn( compiler.getSourceManager().getFileEntryForID(
|
|
compiler.getSourceManager().getMainFileID())->getName() );
|
|
|
|
// old code, no point in updating
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/store/source/store.cxx"))
|
|
return;
|
|
|
|
// TODO -----------------------------
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/registry/source/registry.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/registry/source/regimpl.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/registry/source/reflread.cxx"))
|
|
return;
|
|
// TODO MenuAttributes::CreateAttribute
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/framework/source/fwe/xml/menuconfiguration.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sw/source/uibase/app/apphdl.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/dbaccess/source/core/dataaccess/ModelImpl.cxx"))
|
|
return;
|
|
// need a better replacement for vcl::EventPoster
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/svtools/source/misc/acceleratorexecute.cxx"))
|
|
return;
|
|
// PostUserEvent stuff
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/toolkit/source/awt/vclxwindow.cxx"))
|
|
return;
|
|
// playing games with pointers passed into combobox entries
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/cui/source/customize/cfgutil.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/cui/source/customize/cfg.cxx"))
|
|
return;
|
|
// END TODO -----------------------------
|
|
|
|
// can't fix these without breaking stable ABI
|
|
if (fn.startswith(SRCDIR "/sal/"))
|
|
return;
|
|
if (fn.startswith(SRCDIR "/salhelper/"))
|
|
return;
|
|
if (fn.startswith(SRCDIR "/cppu/"))
|
|
return;
|
|
if (fn.startswith(SRCDIR "/cppuhelper/"))
|
|
return;
|
|
if (fn.startswith(SRCDIR "/bridges/"))
|
|
return;
|
|
|
|
// lots of magic here
|
|
if (fn.startswith(SRCDIR "/stoc/"))
|
|
return;
|
|
if (fn.startswith(SRCDIR "/testtools/"))
|
|
return;
|
|
|
|
// mutex games
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/vcl/source/app/scheduler.cxx"))
|
|
return;
|
|
// opengl games
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/vcl/source/app/svdata.cxx"))
|
|
return;
|
|
|
|
// passing the pointer through PostUserEvent
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/avmedia/source/gstreamer/gstplayer.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/svx/source/form/fmscriptingenv.cxx"))
|
|
return;
|
|
|
|
// thread games
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/io/source/stm/opump.cxx"))
|
|
return;
|
|
|
|
// ??? no idea what this code is up to
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/extensions/source/scanner/scanunx.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/stoc/source/invocation_adapterfactory/iafactory.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/fpicker/source/office/asyncfilepicker.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/forms/source/component/FormComponent.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/ucb/source/ucp/file/bc.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/ucb/source/ucp/file/filprp.cxx"))
|
|
return;
|
|
|
|
// implementing css::uno::XInterface
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/animations/motionpathtag.cxx"))
|
|
return;
|
|
// UNO factory methods
|
|
if (fn.startswith(SRCDIR "/comphelper/"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/linguistic/source/convdiclist.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/linguistic/source/dlistimp.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/linguistic/source/gciterator.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/linguistic/source/lngsvcmgr.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/linguistic/source/lngopt.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/vcl/unx/generic/gdi/gcach_xpeer.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/dbaccess/source/ui/dlg/dbwizsetup.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/dbaccess/source/ui/dlg/dbwizsetup.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/lingucomponent/source/hyphenator/hyphen/hyphenimp.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/lingucomponent/source/spellcheck/spell/sspellimp.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/lingucomponent/source/thesaurus/libnth/nthesimp.cxx"))
|
|
return;
|
|
|
|
|
|
// some kind of complicated listener nonsense
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sd/source/ui/framework/tools/FrameworkHelper.cxx"))
|
|
return;
|
|
// more listener nonsense
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sw/source/uibase/uno/unomailmerge.cxx"))
|
|
return;
|
|
// playing games with it's listener list
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/ui/unoobj/cellsuno.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/ui/unoobj/chart2uno.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/ui/unoobj/dapiuno.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/ui/unoobj/datauno.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/ui/unoobj/linkuno.cxx"))
|
|
return;
|
|
// PostUserEvent
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/ui/vba/vbaeventshelper.cxx"))
|
|
return;
|
|
// thread holding itself
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/forms/source/component/EventThread.cxx"))
|
|
return;
|
|
|
|
|
|
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
|
|
}
|
|
|
|
bool shouldVisitTemplateInstantiations () const { return true; }
|
|
|
|
bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *);
|
|
bool TraverseCXXRecordDecl(CXXRecordDecl *);
|
|
bool TraverseCXXMethodDecl(CXXMethodDecl *);
|
|
bool TraverseFunctionDecl(FunctionDecl *);
|
|
bool TraverseCXXConstructorDecl(CXXConstructorDecl *);
|
|
bool TraverseCXXDestructorDecl(CXXDestructorDecl *);
|
|
bool TraverseCXXConversionDecl(CXXConversionDecl *);
|
|
bool TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *);
|
|
bool TraverseLinkageSpecDecl(LinkageSpecDecl *);
|
|
private:
|
|
bool ignoreCallerClass(CXXRecordDecl*);
|
|
};
|
|
|
|
bool ManualRefCount::TraverseCXXMethodDecl(CXXMethodDecl* cxxMethodDecl)
|
|
{
|
|
if (ignoreCallerClass(cxxMethodDecl->getParent()))
|
|
return true;
|
|
// disambiguating forwarding methods for XInterface subclasses
|
|
if (cxxMethodDecl->getIdentifier() && (cxxMethodDecl->getName() == "acquire" || cxxMethodDecl->getName() == "release"))
|
|
return true;
|
|
return RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl);
|
|
}
|
|
|
|
bool ManualRefCount::TraverseFunctionDecl(FunctionDecl* functionDecl)
|
|
{
|
|
auto tc = loplugin::DeclCheck(functionDecl);
|
|
if (tc.Function("make_shared_from_UNO").Namespace("comphelper").GlobalNamespace())
|
|
return true;
|
|
return RecursiveASTVisitor::TraverseFunctionDecl(functionDecl);
|
|
}
|
|
|
|
bool ManualRefCount::TraverseCXXConstructorDecl(CXXConstructorDecl* cxxMethodDecl)
|
|
{
|
|
if (ignoreCallerClass(cxxMethodDecl->getParent()))
|
|
return true;
|
|
return RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl);
|
|
}
|
|
|
|
bool ManualRefCount::TraverseCXXDestructorDecl(CXXDestructorDecl*)
|
|
{
|
|
// just ignore destructors, tons of places like to call acquire() on themselves in their destructor
|
|
// supposedly to prevent recursively calling the destructor
|
|
return true;
|
|
}
|
|
bool ManualRefCount::TraverseCXXConversionDecl(CXXConversionDecl* cxxMethodDecl)
|
|
{
|
|
if (ignoreCallerClass(cxxMethodDecl->getParent()))
|
|
return true;
|
|
return RecursiveASTVisitor::TraverseCXXMethodDecl(cxxMethodDecl);
|
|
}
|
|
bool ManualRefCount::TraverseCXXRecordDecl(CXXRecordDecl* cxxRecordDecl)
|
|
{
|
|
if (ignoreCallerClass(cxxRecordDecl))
|
|
return true;
|
|
return RecursiveASTVisitor::TraverseCXXRecordDecl(cxxRecordDecl);
|
|
}
|
|
|
|
bool ManualRefCount::TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl* templateDecl)
|
|
{
|
|
if (ignoreCallerClass(templateDecl))
|
|
return true;
|
|
return RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(templateDecl);
|
|
}
|
|
|
|
bool ManualRefCount::TraverseLinkageSpecDecl(LinkageSpecDecl *)
|
|
{
|
|
// ignore methods inside "extern ""C""" blocks, these are normally UNO constructors, which
|
|
// are required to raise the reference count before returning
|
|
return true;
|
|
}
|
|
|
|
bool ManualRefCount::ignoreCallerClass(CXXRecordDecl* cxxRecordDecl)
|
|
{
|
|
auto tc = loplugin::TypeCheck(cxxRecordDecl);
|
|
return
|
|
tc.Class("Reference").Namespace("rtl").GlobalNamespace()
|
|
|| tc.Class("cow_wrapper").Namespace("o3tl").GlobalNamespace()
|
|
|| tc.Class("Reference").Namespace("uno").Namespace("star").Namespace("sun").Namespace("com").GlobalNamespace()
|
|
|| tc.Class("ShareGuard").Namespace("framework").GlobalNamespace()
|
|
|| tc.Class("ControlModelLock").Namespace("frm").GlobalNamespace()
|
|
|| tc.Struct("ReleaseFunc").Namespace("detail").Namespace("comphelper").GlobalNamespace()
|
|
// TODO no idea what this is up to
|
|
|| tc.Class("SfxModelSubComponent").GlobalNamespace()
|
|
|| tc.Class("OSubComponent").Namespace("mysqlc").Namespace("connectivity").GlobalNamespace()
|
|
|| tc.Class("OSubComponent").Namespace("connectivity").GlobalNamespace()
|
|
// TODO do we really need this?
|
|
|| tc.Class("ShareableMutex").Namespace("framework").GlobalNamespace()
|
|
|| tc.Class("ObservableThread").GlobalNamespace()
|
|
;
|
|
}
|
|
|
|
bool ManualRefCount::VisitCXXMemberCallExpr(const CXXMemberCallExpr* cxxMemberCallExpr)
|
|
{
|
|
if (ignoreLocation(cxxMemberCallExpr))
|
|
return true;
|
|
if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(cxxMemberCallExpr->getLocStart())))
|
|
return true;
|
|
|
|
// first, use some heuristics to find the right kind of acquire()/release() calls
|
|
CXXMethodDecl const * calleeMethodDecl = cxxMemberCallExpr->getMethodDecl();
|
|
if (!calleeMethodDecl || !calleeMethodDecl->getIdentifier())
|
|
return true;
|
|
if (calleeMethodDecl->getName() != "acquire" && calleeMethodDecl->getName() != "release")
|
|
return true;
|
|
if (calleeMethodDecl->getNumParams() != 0)
|
|
return true;
|
|
// std::unique_ptr::release() and similar methods
|
|
if (calleeMethodDecl->getName() == "release" && loplugin::TypeCheck(calleeMethodDecl->getReturnType()).Pointer())
|
|
return true;
|
|
|
|
// these are OK
|
|
auto calleeRecordTC = loplugin::TypeCheck(calleeMethodDecl->getParent());
|
|
if (calleeRecordTC.Struct("ResourceHolder").Namespace("store").GlobalNamespace())
|
|
return true;
|
|
if (calleeRecordTC.Class("Module").Namespace("osl").GlobalNamespace())
|
|
return true;
|
|
if (calleeRecordTC.Class("Mutex").Namespace("osl").GlobalNamespace())
|
|
return true;
|
|
if (calleeRecordTC.Class("multi_type_vector").Namespace("mdds").GlobalNamespace())
|
|
return true;
|
|
|
|
// while (calleeMethodDecl->size_overridden_methods() > 0)
|
|
// calleeMethodDecl = *calleeMethodDecl->begin_overridden_methods();
|
|
// auto tc2 = loplugin::TypeCheck(calleeMethodDecl->getParent());
|
|
// if (tc2.Class("XInterface").Namespace("uno").Namespace("star").Namespace("sun").Namespace("com").GlobalNamespace())
|
|
// return true;
|
|
|
|
std::cout << calleeMethodDecl->getParent()->getQualifiedNameAsString() << std::endl;
|
|
report(
|
|
DiagnosticsEngine::Warning, "call to acquire/release",
|
|
cxxMemberCallExpr->getLocStart())
|
|
<< cxxMemberCallExpr->getSourceRange();
|
|
return true;
|
|
}
|
|
|
|
|
|
loplugin::Plugin::Registration< ManualRefCount > X("manualrefcount", true);
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|