Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/misc/compbase.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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
10
#include <comphelper/compbase.hxx>
11
#include <cppuhelper/queryinterface.hxx>
12
#include <sal/log.hxx>
13
#include <osl/diagnose.h>
14
15
namespace comphelper
16
{
17
561k
WeakComponentImplHelperBase::~WeakComponentImplHelperBase() {}
18
19
// css::lang::XComponent
20
void SAL_CALL WeakComponentImplHelperBase::dispose()
21
102k
{
22
102k
    std::unique_lock aGuard(m_aMutex);
23
102k
    if (m_bDisposed)
24
0
        return;
25
102k
    m_bDisposed = true;
26
102k
    disposing(aGuard);
27
102k
    if (!aGuard.owns_lock())
28
0
        aGuard.lock();
29
102k
    css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
30
102k
    maEventListeners.disposeAndClear(aGuard, aEvt);
31
102k
}
32
33
// This is only called from the destructor to do cleanup that
34
// might not have occurred
35
void WeakComponentImplHelperBase::disposeOnDestruct()
36
0
{
37
0
    std::unique_lock aGuard(m_aMutex);
38
0
    assert(m_refCount == 0 && "only supposed to be called from the destructor");
39
0
    if (m_bDisposed)
40
0
        return;
41
0
    m_bDisposed = true;
42
    // bump the ref-count so we don't accidentally do a double delete
43
    // if something else increases and then decreases our ref-count
44
0
    cppu::OWeakObject::acquire();
45
0
    disposing(aGuard);
46
0
}
47
48
22.5k
void WeakComponentImplHelperBase::disposing(std::unique_lock<std::mutex>&) {}
49
50
void SAL_CALL WeakComponentImplHelperBase::addEventListener(
51
    css::uno::Reference<css::lang::XEventListener> const& rxListener)
52
98.0k
{
53
98.0k
    std::unique_lock aGuard(m_aMutex);
54
98.0k
    if (m_bDisposed)
55
0
        return;
56
98.0k
    maEventListeners.addInterface(aGuard, rxListener);
57
98.0k
}
58
59
void SAL_CALL WeakComponentImplHelperBase::removeEventListener(
60
    css::uno::Reference<css::lang::XEventListener> const& rxListener)
61
84.6k
{
62
84.6k
    std::unique_lock aGuard(m_aMutex);
63
84.6k
    maEventListeners.removeInterface(aGuard, rxListener);
64
84.6k
}
65
66
css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
67
112k
{
68
112k
    css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
69
112k
                                                   static_cast<css::lang::XComponent*>(this));
70
112k
    if (aReturn.hasValue())
71
82.3k
        return aReturn;
72
30.1k
    return OWeakObject::queryInterface(rType);
73
112k
}
74
75
static void checkInterface(css::uno::Type const& rType)
76
2.38M
{
77
2.38M
    if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
78
0
    {
79
0
        OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
80
0
        SAL_WARN("cppuhelper", msg);
81
0
        throw css::uno::RuntimeException(msg);
82
0
    }
83
2.38M
}
84
85
static bool isXInterface(typelib_TypeDescriptionReference const* pTypeLibType)
86
2.38M
{
87
2.38M
    return OUString::unacquired(&pTypeLibType->pTypeName) == "com.sun.star.uno.XInterface";
88
2.38M
}
89
90
static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
91
                      typelib_TypeDescriptionReference const* pTDR2)
92
8.63M
{
93
8.63M
    return ((pTDR1 == pTDR2)
94
6.82M
            || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
95
8.63M
}
96
97
static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
98
1.91M
{
99
1.91M
    cppu::type_entry* pEntries = cd->m_typeEntries;
100
1.91M
    if (!cd->m_storedTypeRefs) // not inited?
101
97
    {
102
97
        static std::mutex aMutex;
103
97
        std::scoped_lock guard(aMutex);
104
97
        if (!cd->m_storedTypeRefs) // not inited?
105
97
        {
106
            // get all types
107
625
            for (sal_Int32 n = cd->m_nTypes; n--;)
108
528
            {
109
528
                cppu::type_entry* pEntry = &pEntries[n];
110
528
                css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
111
528
                OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
112
528
                           "### wrong helper init: expected interface!");
113
528
                OSL_ENSURE(
114
528
                    !isXInterface(rType.getTypeLibType()),
115
528
                    "### want to implement XInterface: template argument is XInterface?!?!?!");
116
528
                if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
117
0
                {
118
0
                    OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
119
0
                    SAL_WARN("cppuhelper", msg);
120
0
                    throw css::uno::RuntimeException(msg);
121
0
                }
122
                // ref is statically held by getCppuType()
123
528
                pEntry->m_type.typeRef = rType.getTypeLibType();
124
528
            }
125
97
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
126
97
            cd->m_storedTypeRefs = true;
127
97
        }
128
97
    }
129
1.91M
    else
130
1.91M
    {
131
1.91M
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
132
1.91M
    }
133
1.91M
    return pEntries;
134
1.91M
}
135
136
static void* makeInterface(sal_IntPtr nOffset, void* that)
137
1.80M
{
138
1.80M
    return (static_cast<char*>(that) + nOffset);
139
1.80M
}
140
141
static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
142
                                typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
143
1.81M
{
144
    // This code assumes that the vtables of a multiple-inheritance class (the
145
    // offset amount by which to adjust the this pointer) follow one another in
146
    // the object layout, and that they contain slots for the inherited classes
147
    // in a specific order.  In theory, that need not hold for any given
148
    // platform; in practice, it seems to work well on all supported platforms:
149
2.13M
next:
150
3.61M
    for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
151
2.14M
    {
152
2.14M
        if (i > 0)
153
5.33k
        {
154
5.33k
            *offset += sizeof(void*);
155
5.33k
        }
156
2.14M
        typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
157
        // ignore XInterface:
158
2.14M
        if (base->nBaseTypes > 0)
159
669k
        {
160
669k
            if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
161
669k
                          demandedType))
162
348k
            {
163
348k
                return true;
164
348k
            }
165
            // Profiling showed that it is important to speed up the common case
166
            // of only one base:
167
320k
            if (type->nBaseTypes == 1)
168
315k
            {
169
315k
                type = base;
170
315k
                goto next;
171
315k
            }
172
5.34k
            if (recursivelyFindType(demandedType, base, offset))
173
6
            {
174
6
                return true;
175
6
            }
176
5.34k
        }
177
2.14M
    }
178
1.47M
    return false;
179
2.13M
}
180
181
static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
182
                                   cppu::class_data* cd, void* that)
183
2.38M
{
184
2.38M
    if (isXInterface(pDemandedTDR))
185
470k
        return nullptr;
186
187
1.91M
    cppu::type_entry* pEntries = getTypeEntries(cd);
188
1.91M
    sal_Int32 nTypes = cd->m_nTypes;
189
1.91M
    sal_Int32 n;
190
191
    // try top interfaces without getting td
192
8.42M
    for (n = 0; n < nTypes; ++n)
193
7.96M
    {
194
7.96M
        if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
195
1.45M
        {
196
1.45M
            return makeInterface(pEntries[n].m_offset, that);
197
1.45M
        }
198
7.96M
    }
199
    // query deep getting td
200
1.93M
    for (n = 0; n < nTypes; ++n)
201
1.81M
    {
202
1.81M
        typelib_TypeDescription* pTD = nullptr;
203
1.81M
        TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
204
1.81M
        if (pTD)
205
1.81M
        {
206
            // exclude top (already tested) and bottom (XInterface) interface
207
1.81M
            OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
208
1.81M
                       "### want to implement XInterface:"
209
1.81M
                       " template argument is XInterface?!?!?!");
210
1.81M
            sal_IntPtr offset = pEntries[n].m_offset;
211
1.81M
            bool found = recursivelyFindType(
212
1.81M
                pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
213
1.81M
            TYPELIB_DANGER_RELEASE(pTD);
214
1.81M
            if (found)
215
348k
            {
216
348k
                return makeInterface(offset, that);
217
348k
            }
218
1.81M
        }
219
0
        else
220
0
        {
221
0
            OUString msg("cannot get type description for type \""
222
0
                         + OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
223
0
            SAL_WARN("cppuhelper", msg);
224
0
            throw css::uno::RuntimeException(msg);
225
0
        }
226
1.81M
    }
227
115k
    return nullptr;
228
464k
}
229
230
css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
231
                                            WeakComponentImplHelperBase* pBase)
232
908k
{
233
908k
    checkInterface(rType);
234
908k
    typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
235
236
    // shortcut XInterface to WeakComponentImplHelperBase
237
908k
    if (void* p = queryDeepNoXInterface(pTDR, cd, pBase))
238
796k
        return css::uno::Any(&p, pTDR);
239
112k
    return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
240
908k
}
241
242
300k
WeakImplHelperBase::~WeakImplHelperBase() {}
243
244
css::uno::Any WeakImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
245
                                   WeakImplHelperBase* pBase)
246
1.47M
{
247
1.47M
    checkInterface(rType);
248
1.47M
    typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
249
250
    // shortcut XInterface to WeakImplHelperBase
251
1.47M
    if (void* p = queryDeepNoXInterface(pTDR, cd, pBase))
252
1.00M
        return css::uno::Any(&p, pTDR);
253
474k
    return pBase->comphelper::WeakImplHelperBase::queryInterface(rType);
254
1.47M
}
255
256
} // namespace comphelper
257
258
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */