File indexing completed on 2024-05-12 04:37:59

0001 /*
0002     SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef KDEVPLATFORM_DUCHAINPOINTER_H
0008 #define KDEVPLATFORM_DUCHAINPOINTER_H
0009 
0010 #include <QMetaType>
0011 #include <QList>
0012 #include <QExplicitlySharedDataPointer>
0013 #include <language/languageexport.h>
0014 
0015 //krazy:excludeall=dpointer
0016 
0017 namespace KDevelop {
0018 class DUContext;
0019 class TopDUContext;
0020 class DUChainBase;
0021 class Declaration;
0022 class AbstractFunctionDeclaration;
0023 
0024 /**
0025  * Whenever the du-chain is unlocked and locked again, any du-chain item may have been deleted in between.
0026  * For that reason, the following class should be used to make sure that no deleted objects are accessed. It contains a pointer
0027  * that will be reset to zero once the pointed object is deleted.
0028  *
0029  * Access to the data must still be serialized through duchain-locking. Using this comes with no additional cost.
0030  *
0031  * In practice this means:
0032  * Store an instance of DUChainPointer instead of a pointer to the du-chain object.
0033  * Then, access the eventually still existing object by calling pointer->base().
0034  *
0035  * To make it even more convenient see DUChainPointer
0036  * */
0037 
0038 class KDEVPLATFORMLANGUAGE_EXPORT DUChainPointerData
0039     : public QSharedData
0040 {
0041 public:
0042     /**
0043      * Will return zero once the pointed-to object was deleted
0044      * */
0045     DUChainBase* base();
0046 
0047     /**
0048      * Will return zero once the pointed-to object was deleted
0049      * */
0050     DUChainBase* base() const;
0051 
0052     ///Default-initialization of an invalid reference
0053     DUChainPointerData();
0054 
0055     ~DUChainPointerData();
0056 
0057 private:
0058     ///Should not be used from outside, but is needed sometimes to construct an invalid dummy-pointer
0059     explicit DUChainPointerData(DUChainBase* base);
0060 
0061     friend class DUChainBase;
0062     DUChainBase* m_base = nullptr;
0063     Q_DISABLE_COPY(DUChainPointerData)
0064 };
0065 
0066 /**
0067  * A smart-pointer similar class that conveniently wraps around DUChainPointerData without
0068  * too many dynamic casts.
0069  *
0070  * It can be used like a normal pointer.  In order to cast between pointer types, you should
0071  * use the staticCast() and dynamicCast() functions as appropriate.
0072  *
0073  * Access must be serialized by holding the KDevelop::DUChain::lock() as appropriate for the
0074  * function(s) being called.
0075  **/
0076 
0077 template <class Type>
0078 class DUChainPointer
0079 {
0080     template <class OtherType>
0081     friend class DUChainPointer;
0082 
0083 public:
0084     DUChainPointer() : d(QExplicitlySharedDataPointer<DUChainPointerData>(nullptr))
0085     {
0086     }
0087 
0088     DUChainPointer(const DUChainPointer&) = default;
0089     DUChainPointer(DUChainPointer&&) = default;
0090 
0091     ///This constructor includes dynamic casting. If the object cannot be casted to the type, the constructed DUChainPointer will have value zero.
0092     template <class OtherType>
0093     explicit DUChainPointer(OtherType* rhs)
0094     {
0095         if (dynamic_cast<Type*>(rhs))
0096             d = rhs->weakPointer();
0097     }
0098 
0099     template <class OtherType>
0100     explicit DUChainPointer(DUChainPointer<OtherType> rhs)
0101     {
0102         if (dynamic_cast<Type*>(rhs.data()))
0103             d = rhs.d;
0104     }
0105 
0106     explicit DUChainPointer(QExplicitlySharedDataPointer<DUChainPointerData> rhs)
0107     {
0108         if (dynamic_cast<Type*>(rhs->base()))
0109             d = rhs;
0110     }
0111 
0112     explicit DUChainPointer(Type* rhs)
0113     {
0114         if (rhs)
0115             d = rhs->weakPointer();
0116     }
0117 
0118     ~DUChainPointer() = default;
0119 
0120     bool operator ==(const DUChainPointer<Type>& rhs) const
0121     {
0122         return d.data() == rhs.d.data();
0123     }
0124 
0125     bool operator !=(const DUChainPointer<Type>& rhs) const
0126     {
0127         return d.data() != rhs.d.data();
0128     }
0129 
0130     ///Returns whether the pointed object is still existing
0131     operator bool() const {
0132         return d && d->base();
0133     }
0134 
0135     Type& operator*() const
0136     {
0137         Q_ASSERT(d);
0138         return *static_cast<Type*>(d->base());
0139     }
0140 
0141     Type* operator->() const
0142     {
0143         Q_ASSERT(d);
0144         return static_cast<Type*>(d->base());
0145     }
0146 
0147     bool operator<(const DUChainPointer<Type>& rhs) const
0148     {
0149         return d.data() < rhs.d.data();
0150     }
0151 
0152     template <class NewType>
0153     DUChainPointer<NewType> dynamicCast() const
0154     {
0155         if (d && dynamic_cast<NewType*>(d->base()))  //When the reference to the pointer is constant that doesn't mean that the pointed object needs to be constant
0156             return DUChainPointer<NewType>(static_cast<NewType*>(d->base()));
0157         else
0158             return DUChainPointer<NewType>();
0159     }
0160 
0161     Type* data() const
0162     {
0163         if (!d)
0164             return nullptr;
0165         return static_cast<Type*>(d->base());
0166     }
0167 
0168     DUChainPointer<Type>& operator=(const DUChainPointer<Type>&) = default;
0169     DUChainPointer<Type>& operator=(DUChainPointer<Type>&&) = default;
0170 
0171     DUChainPointer<Type>& operator=(Type* rhs)
0172     {
0173         if (rhs)
0174             d = rhs->weakPointer();
0175         else
0176             d = nullptr;
0177 
0178         return *this;
0179     }
0180 
0181 private:
0182     QExplicitlySharedDataPointer<DUChainPointerData> d;
0183 };
0184 
0185 using DUChainBasePointer = DUChainPointer<DUChainBase>;
0186 using DUContextPointer = DUChainPointer<DUContext>;
0187 using TopDUContextPointer = DUChainPointer<TopDUContext>;
0188 using DeclarationPointer = DUChainPointer<Declaration>;
0189 using FunctionDeclarationPointer = DUChainPointer<AbstractFunctionDeclaration>;
0190 }
0191 
0192 Q_DECLARE_METATYPE(KDevelop::DUChainBasePointer)
0193 Q_DECLARE_METATYPE(KDevelop::DeclarationPointer)
0194 Q_DECLARE_METATYPE(KDevelop::DUContextPointer)
0195 Q_DECLARE_METATYPE(KDevelop::TopDUContextPointer)
0196 
0197 #endif