1 /*
2     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
3     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
4 
5     SPDX-License-Identifier: LGPL-2.0-only
6 */
7 
8 #ifndef KDEVPLATFORM_DUCHAINBASE_H
9 #define KDEVPLATFORM_DUCHAINBASE_H
10 
11 #include <language/languageexport.h>
12 #include "appendedlist.h"
13 #include "duchainpointer.h"
14 #include <language/editor/persistentmovingrange.h>
15 #include <language/editor/rangeinrevision.h>
16 
17 namespace KTextEditor {
18 class Cursor;
19 class Range;
20 }
21 
22 namespace KDevelop {
23 class DUContext;
24 class TopDUContext;
25 class DUChainBase;
26 class IndexedString;
27 
28 ///Use this to declare the data functions in your DUChainBase based class. @warning Behind this macro, the access will be "public".
29 #define DUCHAIN_DECLARE_DATA(Class) \
30     inline class Class ## Data * d_func_dynamic() { makeDynamic(); return reinterpret_cast<Class ## Data*>(d_ptr); } \
31     inline const class Class ## Data* d_func() const { return reinterpret_cast<const Class ## Data*>(d_ptr); } \
32 public: using Data = Class ## Data; \
33 private:
34 
35 #define DUCHAIN_D(Class) const Class ## Data * const d = d_func()
36 #define DUCHAIN_D_DYNAMIC(Class) Class ## Data * const d = d_func_dynamic()
37 
38 ///@note When a data-item is stored on disk, no destructors of contained items will be called while destruction.
39 ///DUChainBase assumes that each item that has constant data, is stored on disk.
40 ///However the destructor is called even on constant items, when they have been replaced with a dynamic item.
41 ///This tries to keep constructor/destructor count consistency persistently, which allows doing static reference-counting
42 ///using contained classes in their constructor/destructors(For example the class Utils::StorableSet).
43 ///This means that the data of all items that are stored to disk _MUST_ be made constant before their destruction.
44 ///This also means that every item that is "semantically" deleted, _MUST_ have dynamic data before its destruction.
45 ///This also means that DUChainBaseData based items should never be cloned using memcpy, but rather always using the copy-constructor,
46 ///even if both sides are constant.
47 class KDEVPLATFORMLANGUAGE_EXPORT DUChainBaseData
48 {
49 public:
DUChainBaseData()50     DUChainBaseData()
51     {
52         initializeAppendedLists();
53     }
54 
DUChainBaseData(const DUChainBaseData & rhs)55     DUChainBaseData(const DUChainBaseData& rhs) : m_range(rhs.m_range)
56         , classId(rhs.classId)
57     {
58         initializeAppendedLists();
59     }
60 
~DUChainBaseData()61     ~DUChainBaseData()
62     {
63         freeAppendedLists();
64     }
65 
66     DUChainBaseData& operator=(const DUChainBaseData& rhs) = delete;
67 
68     RangeInRevision m_range;
69 
70     APPENDED_LISTS_STUB(DUChainBaseData)
71 
72     quint16 classId = 0;
73 
isDynamic()74     bool isDynamic() const
75     {
76         return m_dynamic;
77     }
78 
79     /**
80      * Internal setup for the data structure.
81      *
82      * This must be called from actual class that belongs to this data(not parent classes), and the class must have the
83      * "Identity" enumerator with a unique identity. Do NOT call this in copy-constructors!
84      */
85     template <class T>
setClassId(T *)86     void setClassId(T*)
87     {
88         static_assert(T::Identity < std::numeric_limits<decltype(classId)>::max(), "Class ID out of bounds");
89         classId = T::Identity;
90     }
91 
92     uint classSize() const;
93 
94     ///This is called whenever the data-object is being deleted memory-wise, but not semantically(Which means it stays on disk)
95     ///Implementations of parent-classes must always be called
freeDynamicData()96     void freeDynamicData()
97     {
98     }
99 
100     ///Used to decide whether a constructed item should create constant data.
101     ///The default is "false", so dynamic data is created by default.
102     ///This is stored thread-locally.
103     static bool& shouldCreateConstantData();
104 
105     ///Returns whether initialized objects should be created as dynamic objects
appendedListDynamicDefault()106     static bool appendedListDynamicDefault()
107     {
108         return !shouldCreateConstantData();
109     }
110 };
111 
112 /**
113  * Base class for definition-use chain objects.
114  *
115  * This class provides a thread safe pointer type to reference duchain objects
116  * while the DUChain mutex is not held (\see DUChainPointer)
117  */
118 
119 class KDEVPLATFORMLANGUAGE_EXPORT DUChainBase
120 {
121 public:
122     /**
123      * Constructor.
124      *
125      * \param range range of the alias declaration's identifier
126      */
127     explicit DUChainBase(const RangeInRevision& range);
128     /// Destructor
129     virtual ~DUChainBase();
130 
131     /**
132      * Determine the top context to which this object belongs.
133      */
134     virtual TopDUContext* topContext() const;
135 
136     /**
137      * Returns a special pointer that can be used to track the existence of a du-chain object across locking-cycles.
138      * @see DUChainPointerData
139      * */
140     const QExplicitlySharedDataPointer<DUChainPointerData>& weakPointer() const;
141 
142     virtual IndexedString url() const;
143 
144     enum {
145         Identity = 1
146     };
147 
148     ///After this was called, the data-pointer is dynamic. It is cloned if needed.
149     void makeDynamic();
150 
151     explicit DUChainBase(DUChainBaseData& dd);
152 
153     DUChainBase& operator=(const DUChainBase& rhs) = delete;
154 
155     ///This must only be used to change the storage-location or storage-kind(dynamic/constant) of the data, but
156     ///the data must always be equal!
157     virtual void setData(DUChainBaseData*, bool constructorCalled = true);
158 
159     ///Returns the range assigned to this object, in the document revision when this document was last parsed.
160     RangeInRevision range() const;
161 
162     ///Changes the range assigned to this object, in the document revision when this document is parsed.
163     void setRange(const RangeInRevision& range);
164 
165     ///Returns the range assigned to this object, transformed into the current revision of the document.
166     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
167     KTextEditor::Range rangeInCurrentRevision() const;
168 
169     ///Returns the range assigned to this object, transformed into the current revision of the document.
170     ///The returned object is unique at each call, so you can use it and change it in whatever way you want.
171     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
172     PersistentMovingRange::Ptr createRangeMoving() const;
173 
174     ///Transforms the given cursor in the current document revision to its according position
175     ///in the parsed document containing this duchain object. The resulting cursor will be directly comparable to the non-translated
176     ///range() members in the duchain, but only for one duchain locking cycle.
177     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
178     CursorInRevision transformToLocalRevision(const KTextEditor::Cursor& cursor) const;
179 
180     ///Transforms the given range in the current document revision to its according position
181     ///in the parsed document containing this duchain object. The resulting cursor will be directly comparable to the non-translated
182     ///range() members in the duchain, but only for one duchain locking cycle.
183     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
184     RangeInRevision transformToLocalRevision(const KTextEditor::Range& range) const;
185 
186     KTextEditor::Cursor transformFromLocalRevision(const CursorInRevision& cursor) const;
187 
188     KTextEditor::Range transformFromLocalRevision(const RangeInRevision& range) const;
189 
190 protected:
191     /**
192      * Creates a duchain object that uses the data of the given one, and will not delete it on destruction.
193      * The data will be shared, and this object must be deleted before the given one is.
194      */
195     DUChainBase(DUChainBase& rhs);
196 
197     /**
198      * Constructor for copy constructors in subclasses.
199      *
200      * \param dd data to use.
201      * \param range text range which this object covers.
202      */
203     DUChainBase(DUChainBaseData& dd, const RangeInRevision& range);
204 
205     ///Called after loading to rebuild the dynamic data. If this is a context, this should recursively work on all sub-contexts.
206     virtual void rebuildDynamicData(DUContext* parent, uint ownIndex);
207 
208     /// Data pointer that is shared across all the inheritance hierarchy
209     DUChainBaseData* d_ptr;
210 
211 private:
212 
213     mutable QExplicitlySharedDataPointer<DUChainPointerData> m_ptr;
214 
215 public:
216     DUCHAIN_DECLARE_DATA(DUChainBase)
217 };
218 }
219 
220 #endif // KDEVPLATFORM_DUCHAINBASE_H
221