diff --git a/language/duchain/duchainregister.cpp b/language/duchain/duchainregister.cpp index 8e92ddfa7..09d8a2f0f 100644 --- a/language/duchain/duchainregister.cpp +++ b/language/duchain/duchainregister.cpp @@ -1,80 +1,87 @@ /* This file is part of KDevelop Copyright 2008 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "duchainregister.h" #include "duchainbase.h" #include #define ENSURE_VALID_CLASSID(id) \ qFatal("Invalid class id: %i", id); namespace KDevelop { + +DUChainItemSystem::~DUChainItemSystem() +{ + qDeleteAll(m_factories); +} + DUChainBase* DUChainItemSystem::create(DUChainBaseData* data) const { if(uint(m_factories.size()) <= data->classId || m_factories[data->classId] == 0) return 0; return m_factories[data->classId]->create(data); } DUChainBaseData* DUChainItemSystem::cloneData(const DUChainBaseData& data) const { if(uint(m_factories.size()) <= data.classId || m_factories[data.classId] == 0) { ENSURE_VALID_CLASSID(data.classId) return 0; } return m_factories[data.classId]->cloneData(data); } void DUChainItemSystem::callDestructor(DUChainBaseData* data) const { if(uint(m_factories.size()) <= data->classId || m_factories[data->classId] == 0) return; return m_factories[data->classId]->callDestructor(data); } void DUChainItemSystem::freeDynamicData(KDevelop::DUChainBaseData* data) const { if(uint(m_factories.size()) <= data->classId || m_factories[data->classId] == 0) return; return m_factories[data->classId]->freeDynamicData(data); } uint DUChainItemSystem::dynamicSize(const DUChainBaseData& data) const { if(uint(m_factories.size()) <= data.classId || m_factories[data.classId] == 0) return 0; return m_factories[data.classId]->dynamicSize(data); } uint DUChainItemSystem::dataClassSize(const DUChainBaseData& data) const { if(uint(m_dataClassSizes.size()) <= data.classId || m_dataClassSizes[data.classId] == 0) return 0; return m_dataClassSizes[data.classId]; } void DUChainItemSystem::copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) const { if(uint(m_factories.size()) <= from.classId || m_factories[from.classId] == 0) { ENSURE_VALID_CLASSID(from.classId) return; } return m_factories[from.classId]->copy(from, to, constant); } DUChainItemSystem& DUChainItemSystem::self() { static DUChainItemSystem system; return system; } + } diff --git a/language/duchain/duchainregister.h b/language/duchain/duchainregister.h index f6ff9890e..8b3dfa741 100644 --- a/language/duchain/duchainregister.h +++ b/language/duchain/duchainregister.h @@ -1,208 +1,210 @@ /* This file is part of KDevelop Copyright 2008 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_DUCHAINREGISTER_H #define KDEVPLATFORM_DUCHAINREGISTER_H #include "duchainbase.h" namespace KDevelop { class DUChainBase; class DUChainBaseData; ///This class is purely internal and doesn't need to be documented. It brings a "fake" type-info ///to classes that don't have type-info in the normal C++ way. ///Never use this directly, use the REGISTER_DUCHAIN_ITEM macro instead. class KDEVPLATFORMLANGUAGE_EXPORT DUChainBaseFactory { public: virtual DUChainBase* create(DUChainBaseData* data) const = 0; virtual void callDestructor(DUChainBaseData* data) const = 0; virtual void freeDynamicData(DUChainBaseData* data) const = 0; virtual void copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) const = 0; virtual DUChainBaseData* cloneData(const DUChainBaseData& data) const = 0; virtual uint dynamicSize(const DUChainBaseData& data) const = 0; virtual ~DUChainBaseFactory() { } }; ///Never use this directly, use the REGISTER_DUCHAIN_ITEM macro instead. template class DUChainItemFactory : public DUChainBaseFactory { public: DUChainBase* create(DUChainBaseData* data) const override { return new T(*static_cast(data)); } void copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) const override { Q_ASSERT(from.classId == T::Identity); bool& isConstant = DUChainBaseData::shouldCreateConstantData(); const bool previousConstant = isConstant; if (previousConstant != constant) { isConstant = constant; } new (&to) Data(static_cast(from)); //Call the copy constructor to initialize the target if (previousConstant != constant) { isConstant = previousConstant; } } void callDestructor(DUChainBaseData* data) const override { Q_ASSERT(data->classId == T::Identity); static_cast(data)->~Data(); } void freeDynamicData(DUChainBaseData* data) const override { Q_ASSERT(data->classId == T::Identity); static_cast(data)->freeDynamicData(); } uint dynamicSize(const DUChainBaseData& data) const override { Q_ASSERT(data.classId == T::Identity); return static_cast(data).dynamicSize(); } DUChainBaseData* cloneData(const DUChainBaseData& data) const override { Q_ASSERT(data.classId == T::Identity); return new Data(static_cast(data)); } }; /** * \short A class which registers data types and creates factories for them. * * DUChainItemSystem is a global static class which allows you to register new * DUChainBase subclasses for creation. */ class KDEVPLATFORMLANGUAGE_EXPORT DUChainItemSystem { public: /** * Register a new DUChainBase subclass. */ template void registerTypeClass() { if(m_factories.size() <= T::Identity) { m_factories.resize(T::Identity+1); m_dataClassSizes.resize(T::Identity+1); } Q_ASSERT_X(!m_factories[T::Identity], Q_FUNC_INFO, "This identity is already registered"); m_factories[T::Identity] = new DUChainItemFactory(); m_dataClassSizes[T::Identity] = sizeof(Data); } /** * Unregister an DUChainBase subclass. */ template void unregisterTypeClass() { Q_ASSERT(m_factories.size() > T::Identity); Q_ASSERT(m_factories[T::Identity]); delete m_factories[T::Identity]; m_factories[T::Identity] = 0; m_dataClassSizes[T::Identity] = 0; } /** * Create an DUChainBase for the given data. The returned type must be put into a DUChainBase::Ptr immediately. * Can return null if no type-factory is available for the given data (for example when a language-part is not loaded) */ DUChainBase* create(DUChainBaseData* data) const; ///Creates a dynamic copy of the given data DUChainBaseData* cloneData(const DUChainBaseData& data) const; /** * This just calls the correct constructor on the target. The target must be big enough to hold all the data. * If constant is true, it must be as big as dynamicSize(from). */ void copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) const; ///Calls the dynamicSize(..) member on the given data, in the most special class. Since we cannot use virtual functions, this is the only way. uint dynamicSize(const DUChainBaseData& data) const; ///Returns the size of the derived class, not including dynamic data. ///Returns zero if the class is not known. uint dataClassSize(const DUChainBaseData& data) const; ///Calls the destructor, but does not delete anything. This is needed because the data classes must not contain virtual members. ///This should only be called when a duchain data-pointer is semantically deleted, eg. when it does not persist on disk. void callDestructor(DUChainBaseData* data) const; ///Does not call the destructor, but frees all special data associated to dynamic data(the appendedlists stuff) ///This needs to be called whenever a dynamic duchain data-pointer is being deleted. void freeDynamicData(DUChainBaseData* data) const; /// Access the static DUChainItemSystem instance. static DUChainItemSystem& self(); private: + ~DUChainItemSystem(); + QVector m_factories; QVector m_dataClassSizes; }; template struct DUChainType {}; /// Use this in the header to declare DUChainType #define DUCHAIN_DECLARE_TYPE(Type) \ namespace KDevelop { \ template<> struct DUChainType { \ static void registerType(); \ static void unregisterType(); \ }; \ } /// Use this in the source file to define functions in DUChainType #define DUCHAIN_DEFINE_TYPE_WITH_DATA(Type, Data) \ void KDevelop::DUChainType::registerType() { DUChainItemSystem::self().registerTypeClass(); } \ void KDevelop::DUChainType::unregisterType() { DUChainItemSystem::self().unregisterTypeClass(); } #define DUCHAIN_DEFINE_TYPE(Type) \ DUCHAIN_DEFINE_TYPE_WITH_DATA(Type, Type##Data) /// Register @param T to DUChainItemSystem template void duchainRegisterType() { DUChainType::registerType(); } /// Unregister @param T to DUChainItemSystem template void duchainUnregisterType() { DUChainType::unregisterType(); } /// Helper class to register an DUChainBase subclass. /// /// Just use the REGISTER_TYPE(YourTypeClass) macro in your code, and you're done. template struct DUChainItemRegistrator { DUChainItemRegistrator() { DUChainItemSystem::self().registerTypeClass(); } ~DUChainItemRegistrator() { DUChainItemSystem::self().unregisterTypeClass(); } }; ///You must add this into your source-files for every DUChainBase based class ///For this to work, the class must have an "Identity" enumerator. ///It should be a unique value, but as small as possible, because a buffer at least as big as that number is created internally. #define REGISTER_DUCHAIN_ITEM(Class) KDevelop::DUChainItemRegistrator register ## Class #define REGISTER_DUCHAIN_ITEM_WITH_DATA(Class, Data) KDevelop::DUChainItemRegistrator register ## Class } #endif