Files
core/compilerplugins/clang/store/manualrefcount.cxx
Michael Weghorn 7503bb286f [API CHANGE] a11y: Drop UNO service to create a11y contexts
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
2024-12-17 22:57:26 +01:00

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: */