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