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