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

0001 /*
0002     SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef KDEVPLATFORM_DUCHAINREGISTER_H
0008 #define KDEVPLATFORM_DUCHAINREGISTER_H
0009 
0010 #include "duchainbase.h"
0011 
0012 namespace KDevelop {
0013 class DUChainBase;
0014 class DUChainBaseData;
0015 
0016 ///This class is purely internal and doesn't need to be documented. It brings a "fake" type-info
0017 ///to classes that don't have type-info in the normal C++ way.
0018 ///Never use this directly, use the REGISTER_DUCHAIN_ITEM macro instead.
0019 class KDEVPLATFORMLANGUAGE_EXPORT DUChainBaseFactory
0020 {
0021 public:
0022     virtual DUChainBase* create(DUChainBaseData* data) const = 0;
0023     virtual void callDestructor(DUChainBaseData* data) const = 0;
0024     virtual void freeDynamicData(DUChainBaseData* data) const = 0;
0025     virtual void deleteDynamicData(DUChainBaseData* data) const = 0;
0026     virtual void copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) const = 0;
0027     virtual DUChainBaseData* cloneData(const DUChainBaseData& data) const = 0;
0028     virtual uint dynamicSize(const DUChainBaseData& data) const = 0;
0029 
0030     virtual ~DUChainBaseFactory()
0031     {
0032     }
0033 };
0034 
0035 ///Never use this directly, use the REGISTER_DUCHAIN_ITEM macro instead.
0036 template <class T, class Data>
0037 class DUChainItemFactory
0038     : public DUChainBaseFactory
0039 {
0040 public:
0041     DUChainBase* create(DUChainBaseData* data) const override
0042     {
0043         return new T(*static_cast<Data*>(data));
0044     }
0045 
0046     void copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) const override
0047     {
0048         Q_ASSERT(from.classId == T::Identity);
0049 
0050         bool& isConstant = DUChainBaseData::shouldCreateConstantData();
0051         const bool previousConstant = isConstant;
0052         if (previousConstant != constant) {
0053             isConstant = constant;
0054         }
0055 
0056         new (&to) Data(static_cast<const Data&>(from)); //Call the copy constructor to initialize the target
0057 
0058         if (previousConstant != constant) {
0059             isConstant = previousConstant;
0060         }
0061     }
0062 
0063     void callDestructor(DUChainBaseData* data) const override
0064     {
0065         Q_ASSERT(data->classId == T::Identity);
0066         static_cast<Data*>(data)->~Data();
0067     }
0068 
0069     void freeDynamicData(DUChainBaseData* data) const override
0070     {
0071         Q_ASSERT(data->classId == T::Identity);
0072         static_cast<Data*>(data)->freeDynamicData();
0073     }
0074 
0075     void deleteDynamicData(DUChainBaseData* data) const override
0076     {
0077         Q_ASSERT(data->classId == T::Identity);
0078         delete static_cast<Data*>(data);
0079     }
0080 
0081     uint dynamicSize(const DUChainBaseData& data) const override
0082     {
0083         Q_ASSERT(data.classId == T::Identity);
0084         return static_cast<const Data&>(data).dynamicSize();
0085     }
0086 
0087     DUChainBaseData* cloneData(const DUChainBaseData& data) const override
0088     {
0089         Q_ASSERT(data.classId == T::Identity);
0090         return new Data(static_cast<const Data&>(data));
0091     }
0092 };
0093 
0094 /**
0095  * \short A class which registers data types and creates factories for them.
0096  *
0097  * DUChainItemSystem is a global static class which allows you to register new
0098  * DUChainBase subclasses for creation.
0099  */
0100 class KDEVPLATFORMLANGUAGE_EXPORT DUChainItemSystem
0101 {
0102 public:
0103     /**
0104      * Register a new DUChainBase subclass.
0105      */
0106     template <class T, class Data>
0107     void registerTypeClass()
0108     {
0109         if (m_factories.size() <= T::Identity) {
0110             m_factories.resize(T::Identity + 1);
0111             m_dataClassSizes.resize(T::Identity + 1);
0112         }
0113 
0114         Q_ASSERT_X(!m_factories[T::Identity], Q_FUNC_INFO, "This identity is already registered");
0115         m_factories[T::Identity] = new DUChainItemFactory<T, Data>();
0116         m_dataClassSizes[T::Identity] = sizeof(Data);
0117     }
0118 
0119     /**
0120      * Unregister an DUChainBase subclass.
0121      */
0122     template <class T, class Data>
0123     void unregisterTypeClass()
0124     {
0125         Q_ASSERT(m_factories.size() > T::Identity);
0126         Q_ASSERT(m_factories[T::Identity]);
0127         delete m_factories[T::Identity];
0128         m_factories[T::Identity] = nullptr;
0129         m_dataClassSizes[T::Identity] = 0;
0130     }
0131 
0132     /**
0133      * Create an DUChainBase for the given data. The returned type must be put into a DUChainBase::Ptr immediately.
0134      * Can return null if no type-factory is available for the given data (for example when a language-part is not loaded)
0135      */
0136     DUChainBase* create(DUChainBaseData* data) const;
0137 
0138     ///Creates a dynamic copy of the given data
0139     DUChainBaseData* cloneData(const DUChainBaseData& data) const;
0140 
0141     /**
0142      * This just calls the correct constructor on the target. The target must be big enough to hold all the data.
0143      * If constant is true, it must be as big as dynamicSize(from).
0144      */
0145     void copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) const;
0146 
0147     ///Calls the dynamicSize(..) member on the given data, in the most special class. Since we cannot use virtual functions, this is the only way.
0148     uint dynamicSize(const DUChainBaseData& data) const;
0149 
0150     ///Returns the size of the derived class, not including dynamic data.
0151     ///Returns zero if the class is not known.
0152     uint dataClassSize(const DUChainBaseData& data) const;
0153 
0154     ///Calls the destructor, but does not delete anything. This is needed because the data classes must not contain virtual members.
0155     ///This should only be called when a duchain data-pointer is semantically deleted, eg. when it does not persist on disk.
0156     void callDestructor(DUChainBaseData* data) const;
0157 
0158     ///Does not call the destructor, but frees all special data associated to dynamic data(the appendedlists stuff)
0159     ///This needs to be called whenever a dynamic duchain data-pointer is being deleted.
0160     void freeDynamicData(DUChainBaseData* data) const;
0161 
0162     /// Call delete on @p data
0163     void deleteDynamicData(DUChainBaseData* data) const;
0164 
0165     /// Access the static DUChainItemSystem instance.
0166     static DUChainItemSystem& self();
0167 
0168 private:
0169     Q_DISABLE_COPY(DUChainItemSystem)
0170     DUChainItemSystem() = default;
0171     ~DUChainItemSystem();
0172 
0173     QVector<DUChainBaseFactory*> m_factories;
0174     QVector<uint> m_dataClassSizes;
0175 };
0176 
0177 template <typename T>
0178 struct DUChainType {};
0179 
0180 /// Use this in the header to declare DUChainType<YourTypeClass>
0181 #define DUCHAIN_DECLARE_TYPE(Type) \
0182     namespace KDevelop { \
0183     template <> struct DUChainType<Type> { \
0184         static void registerType(); \
0185         static void unregisterType(); \
0186     }; \
0187     }
0188 /// Use this in the source file to define functions in DUChainType<YourTypeClass>
0189 #define DUCHAIN_DEFINE_TYPE_WITH_DATA(Type, Data) \
0190     void KDevelop::DUChainType<Type>::registerType() { DUChainItemSystem::self().registerTypeClass<Type, Data>(); } \
0191     void KDevelop::DUChainType<Type>::unregisterType() { DUChainItemSystem::self().unregisterTypeClass<Type, Data>(); }
0192 #define DUCHAIN_DEFINE_TYPE(Type) \
0193     DUCHAIN_DEFINE_TYPE_WITH_DATA(Type, Type ## Data)
0194 
0195 /// Register @p T to DUChainItemSystem
0196 template <typename T>
0197 void duchainRegisterType() { DUChainType<T>::registerType(); }
0198 /// Unregister @p T to DUChainItemSystem
0199 template <typename T>
0200 void duchainUnregisterType() { DUChainType<T>::unregisterType(); }
0201 
0202 /// Helper class to register an DUChainBase subclass.
0203 ///
0204 /// Just use the REGISTER_TYPE(YourTypeClass) macro in your code, and you're done.
0205 template <class T, class Data>
0206 struct DUChainItemRegistrator
0207 {
0208     DUChainItemRegistrator()
0209     {
0210         DUChainItemSystem::self().registerTypeClass<T, Data>();
0211     }
0212     ~DUChainItemRegistrator()
0213     {
0214         DUChainItemSystem::self().unregisterTypeClass<T, Data>();
0215     }
0216 private:
0217     Q_DISABLE_COPY(DUChainItemRegistrator)
0218 };
0219 
0220 ///You must add this into your source-files for every DUChainBase based class
0221 ///For this to work, the class must have an "Identity" enumerator.
0222 ///It should be a unique value, but as small as possible, because a buffer at least as big as that number is created internally.
0223 #define REGISTER_DUCHAIN_ITEM(Class) KDevelop::DUChainItemRegistrator<Class, Class ## Data> register ## Class
0224 #define REGISTER_DUCHAIN_ITEM_WITH_DATA(Class, Data) KDevelop::DUChainItemRegistrator<Class, Data> register ## Class
0225 }
0226 
0227 #endif