comphelper/source/misc/compbase.cxx |  181 ++++++++++++++++++++++++++++++++++++
 include/comphelper/compbase.hxx     |   23 +++-
 2 files changed, 197 insertions(+), 7 deletions(-)

New commits:
commit cc517c687de7205487936d40b64481107656f239
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Sun Dec 26 14:04:51 2021 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Sun Dec 26 20:18:15 2021 +0100

    fix comphelper::WeakComponentImplHelper::query
    
    Which was not hanling queries for sub-interfaces.
    
    We need to copy the complicated query function from cppuhelper,
    unfortunatly. It has a signature that includes the base class, so we
    cant re-use it.
    
    Change-Id: I3668abb67c6cb669086ce32505b383ac11d3c3ab
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127511
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/comphelper/source/misc/compbase.cxx 
b/comphelper/source/misc/compbase.cxx
index 6e2019a255ae..ff3c4778b2ba 100644
--- a/comphelper/source/misc/compbase.cxx
+++ b/comphelper/source/misc/compbase.cxx
@@ -8,6 +8,8 @@
  */
 
 #include <comphelper/compbase.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
 
 namespace comphelper
 {
@@ -45,6 +47,185 @@ void SAL_CALL 
WeakComponentImplHelperBase::removeEventListener(
     maEventListeners.removeInterface(rxListener);
 }
 
+css::uno::Any SAL_CALL 
WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
+{
+    css::uno::Any aReturn = ::cppu::queryInterface(rType, 
static_cast<css::uno::XWeak*>(this),
+                                                   
static_cast<css::lang::XComponent*>(this));
+    if (aReturn.hasValue())
+        return aReturn;
+    return OWeakObject::queryInterface(rType);
+}
+
+static void checkInterface(css::uno::Type const& rType)
+{
+    if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
+    {
+        OUString msg("querying for interface \"" + rType.getTypeName() + "\": 
no interface type!");
+        SAL_WARN("cppuhelper", msg);
+        throw css::uno::RuntimeException(msg);
+    }
+}
+
+static bool isXInterface(rtl_uString* pStr)
+{
+    return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
+}
+
+static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
+                      typelib_TypeDescriptionReference const* pTDR2)
+{
+    return ((pTDR1 == pTDR2)
+            || OUString::unacquired(&pTDR1->pTypeName) == 
OUString::unacquired(&pTDR2->pTypeName));
+}
+
+static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
+{
+    cppu::type_entry* pEntries = cd->m_typeEntries;
+    if (!cd->m_storedTypeRefs) // not inited?
+    {
+        static std::mutex aMutex;
+        std::scoped_lock guard(aMutex);
+        if (!cd->m_storedTypeRefs) // not inited?
+        {
+            // get all types
+            for (sal_Int32 n = cd->m_nTypes; n--;)
+            {
+                cppu::type_entry* pEntry = &pEntries[n];
+                css::uno::Type const& rType = 
(*pEntry->m_type.getCppuType)(nullptr);
+                OSL_ENSURE(rType.getTypeClass() == 
css::uno::TypeClass_INTERFACE,
+                           "### wrong helper init: expected interface!");
+                OSL_ENSURE(
+                    !isXInterface(rType.getTypeLibType()->pTypeName),
+                    "### want to implement XInterface: template argument is 
XInterface?!?!?!");
+                if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
+                {
+                    OUString msg("type \"" + rType.getTypeName() + "\" is no 
interface type!");
+                    SAL_WARN("cppuhelper", msg);
+                    throw css::uno::RuntimeException(msg);
+                }
+                // ref is statically held by getCppuType()
+                pEntry->m_type.typeRef = rType.getTypeLibType();
+            }
+            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+            cd->m_storedTypeRefs = true;
+        }
+    }
+    else
+    {
+        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
+    }
+    return pEntries;
+}
+
+static void* makeInterface(sal_IntPtr nOffset, void* that)
+{
+    return (static_cast<char*>(that) + nOffset);
+}
+
+static bool recursivelyFindType(typelib_TypeDescriptionReference const* 
demandedType,
+                                typelib_InterfaceTypeDescription const* type, 
sal_IntPtr* offset)
+{
+    // This code assumes that the vtables of a multiple-inheritance class (the
+    // offset amount by which to adjust the this pointer) follow one another in
+    // the object layout, and that they contain slots for the inherited classes
+    // in a specific order.  In theory, that need not hold for any given
+    // platform; in practice, it seems to work well on all supported platforms:
+next:
+    for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
+    {
+        if (i > 0)
+        {
+            *offset += sizeof(void*);
+        }
+        typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
+        // ignore XInterface:
+        if (base->nBaseTypes > 0)
+        {
+            if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference 
const*>(base),
+                          demandedType))
+            {
+                return true;
+            }
+            // Profiling showed that it is important to speed up the common 
case
+            // of only one base:
+            if (type->nBaseTypes == 1)
+            {
+                type = base;
+                goto next;
+            }
+            if (recursivelyFindType(demandedType, base, offset))
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* 
pDemandedTDR,
+                                   cppu::class_data* cd, void* that)
+{
+    cppu::type_entry* pEntries = getTypeEntries(cd);
+    sal_Int32 nTypes = cd->m_nTypes;
+    sal_Int32 n;
+
+    // try top interfaces without getting td
+    for (n = 0; n < nTypes; ++n)
+    {
+        if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
+        {
+            return makeInterface(pEntries[n].m_offset, that);
+        }
+    }
+    // query deep getting td
+    for (n = 0; n < nTypes; ++n)
+    {
+        typelib_TypeDescription* pTD = nullptr;
+        TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
+        if (pTD)
+        {
+            // exclude top (already tested) and bottom (XInterface) interface
+            
OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes 
> 0,
+                       "### want to implement XInterface:"
+                       " template argument is XInterface?!?!?!");
+            sal_IntPtr offset = pEntries[n].m_offset;
+            bool found = recursivelyFindType(
+                pDemandedTDR, 
reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
+            TYPELIB_DANGER_RELEASE(pTD);
+            if (found)
+            {
+                return makeInterface(offset, that);
+            }
+        }
+        else
+        {
+            OUString msg("cannot get type description for type \""
+                         + 
OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
+            SAL_WARN("cppuhelper", msg);
+            throw css::uno::RuntimeException(msg);
+        }
+    }
+    return nullptr;
+}
+
+css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, 
cppu::class_data* cd,
+                                            WeakComponentImplHelperBase* pBase)
+{
+    checkInterface(rType);
+    typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
+
+    // shortcut XInterface to WeakComponentImplHelperBase
+    if (!isXInterface(pTDR->pTypeName))
+    {
+        void* p = queryDeepNoXInterface(pTDR, cd, pBase);
+        if (p)
+        {
+            return css::uno::Any(&p, pTDR);
+        }
+    }
+    return 
pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
+}
+
 } // namespace comphelper
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/include/comphelper/compbase.hxx b/include/comphelper/compbase.hxx
index 5b7e1f7ba7a1..38380ede20d0 100644
--- a/include/comphelper/compbase.hxx
+++ b/include/comphelper/compbase.hxx
@@ -15,6 +15,7 @@
 #include <comphelper/interfacecontainer4.hxx>
 #include <cppuhelper/weak.hxx>
 #include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/implbase.hxx>
 #include <com/sun/star/lang/XComponent.hpp>
 #include <com/sun/star/lang/XTypeProvider.hpp>
 #include <mutex>
@@ -40,6 +41,8 @@ public:
     virtual void SAL_CALL
     removeEventListener(css::uno::Reference<css::lang::XEventListener> const& 
rxListener) override;
 
+    virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const& rType) 
override;
+
     /**
         Called by dispose for subclasses to do dispose() work.
         The mutex is held when called, and subclasses can unlock() the guard 
if necessary.
@@ -80,13 +83,7 @@ public:
 
     virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const& rType) 
override
     {
-        css::uno::Any aReturn = ::cppu::queryInterface(
-            rType, static_cast<css::uno::XWeak*>(this),
-            
static_cast<css::lang::XComponent*>(static_cast<WeakComponentImplHelperBase*>(this)),
-            static_cast<css::lang::XTypeProvider*>(this), 
static_cast<Ifc*>(this)...);
-        if (aReturn.hasValue())
-            return aReturn;
-        return OWeakObject::queryInterface(rType);
+        return WeakComponentImplHelper_query(rType, class_data_get(), this);
     }
 
     // css::lang::XTypeProvider
@@ -102,8 +99,20 @@ public:
     {
         return css::uno::Sequence<sal_Int8>();
     }
+
+private:
+    static cppu::class_data* class_data_get()
+    {
+        return cppu::detail::ImplClassData<WeakComponentImplHelper, 
Ifc...>{}();
+    }
 };
 
+/** WeakComponentImplHelper
+*/
+COMPHELPER_DLLPUBLIC css::uno::Any
+WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* 
cd,
+                              WeakComponentImplHelperBase* pBase);
+
 } //  namespace comphelper
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */

Reply via email to