1 /* 2 SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de> 3 4 SPDX-License-Identifier: LGPL-2.0-only 5 */ 6 7 #ifndef KDEVPLATFORM_DUCHAINPOINTER_H 8 #define KDEVPLATFORM_DUCHAINPOINTER_H 9 10 #include <QMetaType> 11 #include <QList> 12 #include <QExplicitlySharedDataPointer> 13 #include <language/languageexport.h> 14 15 //krazy:excludeall=dpointer 16 17 namespace KDevelop { 18 class DUContext; 19 class TopDUContext; 20 class DUChainBase; 21 class Declaration; 22 class AbstractFunctionDeclaration; 23 24 /** 25 * Whenever the du-chain is unlocked and locked again, any du-chain item may have been deleted in between. 26 * For that reason, the following class should be used to make sure that no deleted objects are accessed. It contains a pointer 27 * that will be reset to zero once the pointed object is deleted. 28 * 29 * Access to the data must still be serialized through duchain-locking. Using this comes with no additional cost. 30 * 31 * In practice this means: 32 * Store an instance of DUChainPointer instead of a pointer to the du-chain object. 33 * Then, access the eventually still existing object by calling pointer->base(). 34 * 35 * To make it even more convenient see DUChainPointer 36 * */ 37 38 class KDEVPLATFORMLANGUAGE_EXPORT DUChainPointerData 39 : public QSharedData 40 { 41 public: 42 /** 43 * Will return zero once the pointed-to object was deleted 44 * */ 45 DUChainBase* base(); 46 47 /** 48 * Will return zero once the pointed-to object was deleted 49 * */ 50 DUChainBase* base() const; 51 52 ///Default-initialization of an invalid reference 53 DUChainPointerData(); 54 55 ~DUChainPointerData(); 56 57 private: 58 ///Should not be used from outside, but is needed sometimes to construct an invalid dummy-pointer 59 explicit DUChainPointerData(DUChainBase* base); 60 61 friend class DUChainBase; 62 DUChainBase* m_base = nullptr; 63 Q_DISABLE_COPY(DUChainPointerData) 64 }; 65 66 /** 67 * A smart-pointer similar class that conveniently wraps around DUChainPointerData without 68 * too many dynamic casts. 69 * 70 * It can be used like a normal pointer. In order to cast between pointer types, you should 71 * use the staticCast() and dynamicCast() functions as appropriate. 72 * 73 * Access must be serialized by holding the KDevelop::DUChain::lock() as appropriate for the 74 * function(s) being called. 75 **/ 76 77 template <class Type> 78 class DUChainPointer 79 { 80 template <class OtherType> 81 friend class DUChainPointer; 82 83 public: DUChainPointer()84 DUChainPointer() : d(QExplicitlySharedDataPointer<DUChainPointerData>(nullptr)) 85 { 86 } 87 88 DUChainPointer(const DUChainPointer&) = default; 89 DUChainPointer(DUChainPointer&&) = default; 90 91 ///This constructor includes dynamic casting. If the object cannot be casted to the type, the constructed DUChainPointer will have value zero. 92 template <class OtherType> DUChainPointer(OtherType * rhs)93 explicit DUChainPointer(OtherType* rhs) 94 { 95 if (dynamic_cast<Type*>(rhs)) 96 d = rhs->weakPointer(); 97 } 98 99 template <class OtherType> DUChainPointer(DUChainPointer<OtherType> rhs)100 explicit DUChainPointer(DUChainPointer<OtherType> rhs) 101 { 102 if (dynamic_cast<Type*>(rhs.data())) 103 d = rhs.d; 104 } 105 DUChainPointer(QExplicitlySharedDataPointer<DUChainPointerData> rhs)106 explicit DUChainPointer(QExplicitlySharedDataPointer<DUChainPointerData> rhs) 107 { 108 if (dynamic_cast<Type*>(rhs->base())) 109 d = rhs; 110 } 111 DUChainPointer(Type * rhs)112 explicit DUChainPointer(Type* rhs) 113 { 114 if (rhs) 115 d = rhs->weakPointer(); 116 } 117 118 ~DUChainPointer() = default; 119 120 bool operator ==(const DUChainPointer<Type>& rhs) const 121 { 122 return d.data() == rhs.d.data(); 123 } 124 125 bool operator !=(const DUChainPointer<Type>& rhs) const 126 { 127 return d.data() != rhs.d.data(); 128 } 129 130 ///Returns whether the pointed object is still existing 131 operator bool() const { 132 return d && d->base(); 133 } 134 135 Type& operator*() const 136 { 137 Q_ASSERT(d); 138 return *static_cast<Type*>(d->base()); 139 } 140 141 Type* operator->() const 142 { 143 Q_ASSERT(d); 144 return static_cast<Type*>(d->base()); 145 } 146 147 bool operator<(const DUChainPointer<Type>& rhs) const 148 { 149 return d.data() < rhs.d.data(); 150 } 151 152 template <class NewType> dynamicCast()153 DUChainPointer<NewType> dynamicCast() const 154 { 155 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 156 return DUChainPointer<NewType>(static_cast<NewType*>(d->base())); 157 else 158 return DUChainPointer<NewType>(); 159 } 160 data()161 Type* data() const 162 { 163 if (!d) 164 return nullptr; 165 return static_cast<Type*>(d->base()); 166 } 167 168 DUChainPointer<Type>& operator=(const DUChainPointer<Type>&) = default; 169 DUChainPointer<Type>& operator=(DUChainPointer<Type>&&) = default; 170 171 DUChainPointer<Type>& operator=(Type* rhs) 172 { 173 if (rhs) 174 d = rhs->weakPointer(); 175 else 176 d = nullptr; 177 178 return *this; 179 } 180 181 private: 182 QExplicitlySharedDataPointer<DUChainPointerData> d; 183 }; 184 185 using DUChainBasePointer = DUChainPointer<DUChainBase>; 186 using DUContextPointer = DUChainPointer<DUContext>; 187 using TopDUContextPointer = DUChainPointer<TopDUContext>; 188 using DeclarationPointer = DUChainPointer<Declaration>; 189 using FunctionDeclarationPointer = DUChainPointer<AbstractFunctionDeclaration>; 190 } 191 192 Q_DECLARE_METATYPE(KDevelop::DUChainBasePointer) 193 Q_DECLARE_METATYPE(KDevelop::DeclarationPointer) 194 Q_DECLARE_METATYPE(KDevelop::DUContextPointer) 195 Q_DECLARE_METATYPE(KDevelop::TopDUContextPointer) 196 197 #endif 198