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