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