File indexing completed on 2024-05-12 04:37:59

0001 /*
0002     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #ifndef KDEVPLATFORM_DUCHAINBASE_H
0009 #define KDEVPLATFORM_DUCHAINBASE_H
0010 
0011 #include <language/languageexport.h>
0012 #include "appendedlist.h"
0013 #include "duchainpointer.h"
0014 #include <language/editor/persistentmovingrange.h>
0015 #include <language/editor/rangeinrevision.h>
0016 
0017 namespace KTextEditor {
0018 class Cursor;
0019 class Range;
0020 }
0021 
0022 namespace KDevelop {
0023 class DUContext;
0024 class TopDUContext;
0025 class DUChainBase;
0026 class IndexedString;
0027 
0028 ///Use this to declare the data functions in your DUChainBase based class. @warning Behind this macro, the access will be "public".
0029 #define DUCHAIN_DECLARE_DATA(Class) \
0030     inline class Class ## Data * d_func_dynamic() { makeDynamic(); return reinterpret_cast<Class ## Data*>(d_ptr); } \
0031     inline const class Class ## Data* d_func() const { return reinterpret_cast<const Class ## Data*>(d_ptr); } \
0032 public: using Data = Class ## Data; \
0033 private:
0034 
0035 #define DUCHAIN_D(Class) const Class ## Data * const d = d_func()
0036 #define DUCHAIN_D_DYNAMIC(Class) Class ## Data * const d = d_func_dynamic()
0037 
0038 ///@note When a data-item is stored on disk, no destructors of contained items will be called while destruction.
0039 ///DUChainBase assumes that each item that has constant data, is stored on disk.
0040 ///However the destructor is called even on constant items, when they have been replaced with a dynamic item.
0041 ///This tries to keep constructor/destructor count consistency persistently, which allows doing static reference-counting
0042 ///using contained classes in their constructor/destructors(For example the class Utils::StorableSet).
0043 ///This means that the data of all items that are stored to disk _MUST_ be made constant before their destruction.
0044 ///This also means that every item that is "semantically" deleted, _MUST_ have dynamic data before its destruction.
0045 ///This also means that DUChainBaseData based items should never be cloned using memcpy, but rather always using the copy-constructor,
0046 ///even if both sides are constant.
0047 class KDEVPLATFORMLANGUAGE_EXPORT DUChainBaseData
0048 {
0049 public:
0050     DUChainBaseData()
0051     {
0052         initializeAppendedLists();
0053     }
0054 
0055     DUChainBaseData(const DUChainBaseData& rhs) : m_range(rhs.m_range)
0056         , classId(rhs.classId)
0057     {
0058         initializeAppendedLists();
0059     }
0060 
0061     ~DUChainBaseData()
0062     {
0063         freeAppendedLists();
0064     }
0065 
0066     DUChainBaseData& operator=(const DUChainBaseData& rhs) = delete;
0067 
0068     RangeInRevision m_range;
0069 
0070     APPENDED_LISTS_STUB(DUChainBaseData)
0071 
0072     quint16 classId = 0;
0073 
0074     bool isDynamic() const
0075     {
0076         return m_dynamic;
0077     }
0078 
0079     /**
0080      * Internal setup for the data structure.
0081      *
0082      * This must be called from actual class that belongs to this data(not parent classes), and the class must have the
0083      * "Identity" enumerator with a unique identity. Do NOT call this in copy-constructors!
0084      */
0085     template <class T>
0086     void setClassId(T*)
0087     {
0088         static_assert(T::Identity < std::numeric_limits<decltype(classId)>::max(), "Class ID out of bounds");
0089         classId = T::Identity;
0090     }
0091 
0092     uint classSize() const;
0093 
0094     ///This is called whenever the data-object is being deleted memory-wise, but not semantically(Which means it stays on disk)
0095     ///Implementations of parent-classes must always be called
0096     void freeDynamicData()
0097     {
0098     }
0099 
0100     ///Used to decide whether a constructed item should create constant data.
0101     ///The default is "false", so dynamic data is created by default.
0102     ///This is stored thread-locally.
0103     static bool& shouldCreateConstantData();
0104 
0105     ///Returns whether initialized objects should be created as dynamic objects
0106     static bool appendedListDynamicDefault()
0107     {
0108         return !shouldCreateConstantData();
0109     }
0110 };
0111 
0112 /**
0113  * Base class for definition-use chain objects.
0114  *
0115  * This class provides a thread safe pointer type to reference duchain objects
0116  * while the DUChain mutex is not held (\see DUChainPointer)
0117  */
0118 
0119 class KDEVPLATFORMLANGUAGE_EXPORT DUChainBase
0120 {
0121 public:
0122     /**
0123      * Constructor.
0124      *
0125      * \param range range of the alias declaration's identifier
0126      */
0127     explicit DUChainBase(const RangeInRevision& range);
0128     /// Destructor
0129     virtual ~DUChainBase();
0130 
0131     /**
0132      * Determine the top context to which this object belongs.
0133      */
0134     virtual TopDUContext* topContext() const;
0135 
0136     /**
0137      * Returns a special pointer that can be used to track the existence of a du-chain object across locking-cycles.
0138      * @see DUChainPointerData
0139      * */
0140     const QExplicitlySharedDataPointer<DUChainPointerData>& weakPointer() const;
0141 
0142     virtual IndexedString url() const;
0143 
0144     enum {
0145         Identity = 1
0146     };
0147 
0148     ///After this was called, the data-pointer is dynamic. It is cloned if needed.
0149     void makeDynamic();
0150 
0151     explicit DUChainBase(DUChainBaseData& dd);
0152 
0153     DUChainBase& operator=(const DUChainBase& rhs) = delete;
0154 
0155     ///This must only be used to change the storage-location or storage-kind(dynamic/constant) of the data, but
0156     ///the data must always be equal!
0157     virtual void setData(DUChainBaseData*, bool constructorCalled = true);
0158 
0159     ///Returns the range assigned to this object, in the document revision when this document was last parsed.
0160     RangeInRevision range() const;
0161 
0162     ///Changes the range assigned to this object, in the document revision when this document is parsed.
0163     void setRange(const RangeInRevision& range);
0164 
0165     ///Returns the range assigned to this object, transformed into the current revision of the document.
0166     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
0167     KTextEditor::Range rangeInCurrentRevision() const;
0168 
0169     ///Returns the range assigned to this object, transformed into the current revision of the document.
0170     ///The returned object is unique at each call, so you can use it and change it in whatever way you want.
0171     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
0172     PersistentMovingRange::Ptr createRangeMoving() const;
0173 
0174     ///Transforms the given cursor in the current document revision to its according position
0175     ///in the parsed document containing this duchain object. The resulting cursor will be directly comparable to the non-translated
0176     ///range() members in the duchain, but only for one duchain locking cycle.
0177     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
0178     CursorInRevision transformToLocalRevision(const KTextEditor::Cursor& cursor) const;
0179 
0180     ///Transforms the given range in the current document revision to its according position
0181     ///in the parsed document containing this duchain object. The resulting cursor will be directly comparable to the non-translated
0182     ///range() members in the duchain, but only for one duchain locking cycle.
0183     ///@warning This must only be called from the foreground thread, or with the foreground lock acquired.
0184     RangeInRevision transformToLocalRevision(const KTextEditor::Range& range) const;
0185 
0186     KTextEditor::Cursor transformFromLocalRevision(const CursorInRevision& cursor) const;
0187 
0188     KTextEditor::Range transformFromLocalRevision(const RangeInRevision& range) const;
0189 
0190 protected:
0191     /**
0192      * Creates a duchain object that uses the data of the given one, and will not delete it on destruction.
0193      * The data will be shared, and this object must be deleted before the given one is.
0194      */
0195     DUChainBase(DUChainBase& rhs);
0196 
0197     /**
0198      * Constructor for copy constructors in subclasses.
0199      *
0200      * \param dd data to use.
0201      * \param range text range which this object covers.
0202      */
0203     DUChainBase(DUChainBaseData& dd, const RangeInRevision& range);
0204 
0205     ///Called after loading to rebuild the dynamic data. If this is a context, this should recursively work on all sub-contexts.
0206     virtual void rebuildDynamicData(DUContext* parent, uint ownIndex);
0207 
0208     /// Data pointer that is shared across all the inheritance hierarchy
0209     DUChainBaseData* d_ptr;
0210 
0211 private:
0212 
0213     mutable QExplicitlySharedDataPointer<DUChainPointerData> m_ptr;
0214 
0215 public:
0216     DUCHAIN_DECLARE_DATA(DUChainBase)
0217 };
0218 }
0219 
0220 #endif // KDEVPLATFORM_DUCHAINBASE_H