/* This file is part of KDevelop Copyright 2007-2009 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 TEMPLATEDECLARATION_H #define TEMPLATEDECLARATION_H #include #include #include #include #include #include "cppduchainexport.h" #include using namespace KDevelop; namespace KTextEditor { class Range; } namespace KDevelop { class DUContext; class Declaration; class DeclarationId; class DelayedType; class TopDUContext; } namespace Cpp { using KDevelop::InstantiationInformation; using KDevelop::IndexedInstantiationInformation; template class CppDUContext; struct KDEVCPPDUCHAIN_EXPORT TemplateDeclarationData { TemplateDeclarationData() { } TemplateDeclarationData(const TemplateDeclarationData& rhs) : m_parameterContext(rhs.m_parameterContext) { } //The context in which the template-parameters are declared KDevelop::IndexedDUContext m_parameterContext; }; //Represents the template-part of a template-class'es or template-function's template-part class KDEVCPPDUCHAIN_EXPORT TemplateDeclaration { public: typedef QHash InstantiationsHash; ///Copy-constructor for cloning TemplateDeclaration(const TemplateDeclaration& rhs); TemplateDeclaration(); virtual ~TemplateDeclaration(); void setTemplateParameterContext(KDevelop::DUContext* context); KDevelop::DUContext* templateParameterContext() const; TemplateDeclaration* instantiatedFrom() const; ///Marks this template-declaration as a instantiation of the given one. This also means that this declaration will be deleted when the here given is deleted. ///from can also be zero, then the declaration will just be marked as a specialization(instantiatedWith is set) void setInstantiatedFrom(TemplateDeclaration* from, const InstantiationInformation& instantiatedWith); /** * Either finds the existing instance instantiated with the given template-arguments, or creates a new one. * The template-arguments must chained up with the template-arguments of the parent, if the parent is a template class. * @param source the top-context from which ones perspective the instantiation should happen. If @p topContext is zero, only existing specializations are returned * @param forceLocal if this is true, it is this exact declaration that is instantiated. Else, this declaration is instantiated again. * */ KDevelop::Declaration* instantiate(const InstantiationInformation& templateArguments, const KDevelop::TopDUContext* source, bool forceLocal = false ); ///Returns true if this class is a direct instantiation of the given class. Not if it is an instantiation of a specialization of the given class. bool isInstantiatedFrom(const TemplateDeclaration* other) const; void setSpecializedFrom(TemplateDeclaration* other); IndexedInstantiationInformation instantiatedWith() const; ///Marks that a declaration is currently instantiated with the given instantiation-information. ///A zero instantiation is inserted into the cache to make sure that we don't instantiate the same declaration again in the meantime. void reserveInstantiation(const IndexedInstantiationInformation& info); ///An instantiation is an additional temporary version of this declaration that was created given some template-parameters. ///Opposed to that a specialization is a real declaration that was created by the user, that specializes this declaration. ///Returns all current instantiations of this declaration ///@warning Some instantiations may have the value zero when an instantiation is currently happening. InstantiationsHash instantiations() const; IndexedInstantiationInformation specialization() const; DeclarationId id(bool forceDirect) const; Declaration* specialize(const IndexedInstantiationInformation& specialization, const TopDUContext* topContext, int upDistance); //Duchain must be write-locked void deleteAllInstantiations(); ///Returns the template-context that belongs to this template declaration, or zero DUContext* templateContext(const TopDUContext* source) const; ///@return The declaration this one was explicitly specialized from. ///Zero, or a non-specialized (thus also non-instantiated) template-class, which this was explicitly specialized from. virtual IndexedDeclaration specializedFrom() = 0; virtual const IndexedDeclaration* specializations() const = 0; virtual uint specializationsSize() const = 0; ///These are internal, do not use them. They have to be public so they are visible from SpecialTemplateDeclaration. virtual void setSpecializedFromInternal(const IndexedDeclaration& decl) = 0; virtual void addSpecializationInternal(const IndexedDeclaration& decl) = 0; virtual void removeSpecializationInternal(const IndexedDeclaration& decl) = 0; virtual void setSpecializedWith(const IndexedInstantiationInformation& info) = 0; virtual IndexedInstantiationInformation specializedWith() const = 0; protected: //If the given info matches a specialization, returns the instantiated specialization TemplateDeclaration *instantiateSpecialization(const InstantiationInformation& info, const TopDUContext *source); //Matches the given instantiation-information to this declaration's specialization information and returns a score uint matchInstantiation(IndexedInstantiationInformation indexedInfo, const TopDUContext* topCtxt, InstantiationInformation& instantiateWith, bool& instantiationRequired) const; virtual TemplateDeclarationData* dynamicTemplateData() = 0; virtual const TemplateDeclarationData* templateData() const = 0; TemplateDeclaration* m_instantiatedFrom; IndexedInstantiationInformation m_instantiatedWith; static QMutex instantiationsMutex; ///Every access to m_instantiations must be serialized through instantiationsMutex! typedef QHash DefaultParameterInstantiationHash; DefaultParameterInstantiationHash m_defaultParameterInstantiations; InstantiationsHash m_instantiations; ///Every declaration nested within a template declaration knows all its instantiations. // recursion counter int m_instantiationDepth; }; KDEVCPPDUCHAIN_EXPORT DECLARE_LIST_MEMBER_HASH(SpecialTemplateDeclarationData, m_specializations, IndexedDeclaration) template class SpecialTemplateDeclarationData : public Base, public TemplateDeclarationData { public: SpecialTemplateDeclarationData() { initializeAppendedLists(); } ~SpecialTemplateDeclarationData() { freeAppendedLists(); } SpecialTemplateDeclarationData(const SpecialTemplateDeclarationData& rhs) : Base(rhs), TemplateDeclarationData(rhs) { initializeAppendedLists(); copyListsFrom(rhs); m_specializedFrom = rhs.m_specializedFrom; m_specializedWith = rhs.m_specializedWith; } uint classSize() const { return Base::classSize(); } IndexedDeclaration m_specializedFrom; IndexedInstantiationInformation m_specializedWith; START_APPENDED_LISTS_BASE(SpecialTemplateDeclarationData, Base); APPENDED_LIST_FIRST(SpecialTemplateDeclarationData, IndexedDeclaration, m_specializations); END_APPENDED_LISTS(SpecialTemplateDeclarationData, m_specializations); //Just for visibility static bool appendedListDynamicDefault() { return Base::appendedListDynamicDefault(); } }; /** * Use this to merge any type of declaration with a TemplateDeclaration. * This allows wrapping template-declaration's over any kind of declaration, without changing the basic structure of types. * Necessary because we have at least 3 different declaration-classes that are not derived from each other, and that can * be TemplateDeclarations. */ template class KDEVCPPDUCHAIN_EXPORT SpecialTemplateDeclaration : public BaseDeclaration, public TemplateDeclaration { public: template SpecialTemplateDeclaration(Data& data) : BaseDeclaration(data) { } typedef SpecialTemplateDeclarationData Data; ///Copy-constructor for cloning SpecialTemplateDeclaration(const SpecialTemplateDeclaration& rhs) : BaseDeclaration(*new SpecialTemplateDeclarationData(*rhs.d_func())), TemplateDeclaration(rhs) { DUChainBaseData* data = static_cast(this)->d_func_dynamic(); data->setClassId(this); //To keep link-consistency these specialization links are cleared in copies/instantiations static_cast(data)->m_specializedFrom = IndexedDeclaration(); static_cast(data)->m_specializationsList().clear(); } ///Arguments are passed to the base SpecialTemplateDeclaration( const KDevelop::RangeInRevision& range, KDevelop::DUContext* context ) : BaseDeclaration(*new SpecialTemplateDeclarationData()) { static_cast(this)->d_func_dynamic()->setClassId(this); this->setRange(range); if(context) this->setContext(context); } ~SpecialTemplateDeclaration() { TopDUContext* top = this->topContext(); Q_ASSERT(top); //This actually belongs into ~TemplateDeclaration, but we do it here because here we do not need to go through virtual //functions or dynamic casts, because those are not guaranteed to work from within destructors. if(!top->deleting() || !top->isOnDisk()) { ///When the declaration is being deleted, disconnect the links on both sides Declaration* specializedFromDeclaration = static_cast(this->DUChainBase::d_func())->m_specializedFrom.data(); if(TemplateDeclaration* specializedFromTemplate = dynamic_cast(specializedFromDeclaration)) specializedFromTemplate->removeSpecializationInternal(IndexedDeclaration(this)); FOREACH_FUNCTION(IndexedDeclaration decl, static_cast(this->DUChainBase::d_func())->m_specializations) { TemplateDeclaration* tDecl = dynamic_cast(decl.data()); if(tDecl) tDecl->setSpecializedFrom(0); } } } virtual IndexedDeclaration specializedFrom() { return static_cast(this->DUChainBase::d_func())->m_specializedFrom; } virtual const IndexedDeclaration* specializations() const { return static_cast(this->DUChainBase::d_func())->m_specializations(); } virtual uint specializationsSize() const { return static_cast(this->DUChainBase::d_func())->m_specializationsSize(); } virtual IndexedInstantiationInformation specializedWith() const { return static_cast(this->DUChainBase::d_func())->m_specializedWith; } virtual bool inDUChain() const { return instantiatedFrom() || BaseDeclaration::inDUChain(); } virtual uint additionalIdentity() const { return BaseDeclaration::additionalIdentity() + 101; } virtual Declaration* specialize(const IndexedInstantiationInformation& specialization, const TopDUContext* topContext, int upDistance) { return TemplateDeclaration::specialize(specialization, topContext, upDistance); } virtual IndexedInstantiationInformation specialization() const { return TemplateDeclaration::specialization(); } virtual DeclarationId id(bool forceDirect) const { return TemplateDeclaration::id(forceDirect); } //Is specialized for ForwardDeclaration in templatedeclaration.cpp to actively instantiate template forward declarations virtual Declaration* resolve(const TopDUContext* /*topContext*/) const { Q_ASSERT(0); return 0; } enum { Identity = BaseDeclaration::Identity + 50 }; private: virtual void setSpecializedFromInternal(const IndexedDeclaration& decl) { static_cast(this->DUChainBase::d_func_dynamic())->m_specializedFrom = decl; } virtual void addSpecializationInternal(const IndexedDeclaration& decl) { static_cast(this->DUChainBase::d_func_dynamic())->m_specializationsList().append(decl); } virtual void removeSpecializationInternal(const IndexedDeclaration& decl) { bool result = static_cast(this->DUChainBase::d_func_dynamic())->m_specializationsList().removeOne(decl); Q_ASSERT(result); Q_UNUSED(result); } virtual void setSpecializedWith(const IndexedInstantiationInformation& info) { static_cast(this->DUChainBase::d_func_dynamic())->m_specializedWith = info; } virtual TemplateDeclarationData* dynamicTemplateData() { return d_func_dynamic(); } virtual const TemplateDeclarationData* templateData() const { return d_func(); } virtual void activateSpecialization() { BaseDeclaration::activateSpecialization(); if(specialization().index()) { //Also register parents DUContext* context = this->context(); if(context->owner() && context->owner()->specialization().index()) { context->owner()->activateSpecialization(); //will also add to the background-parser }else{ // context->topContext()->setHasUses(false); //Force re-building of the uses // ICore::self()->languageController()->backgroundParser()->addDocument( KUrl(this->url().str()) ); } } } inline SpecialTemplateDeclarationData* d_func_dynamic() { this->makeDynamic(); return reinterpret_cast*>(this->d_ptr); } inline const SpecialTemplateDeclarationData* d_func() const { return reinterpret_cast*>(this->d_ptr); } virtual KDevelop::Declaration* clonePrivate() const { return new SpecialTemplateDeclaration(*this); } }; bool KDEVCPPDUCHAIN_EXPORT isTemplateDeclaration(const KDevelop::Declaration*); /** * If this is used to instantiate a declaration, it should be called BEFORE the Declaration's types DelayedType's are resolved, * because those are needed to resolve missing base-classes. * * The given context should be one that, on some level, imports a template-parameter-declaration context. * The given declaration will be registered anonymously, the same for the created contexts. * @param parentContext he parent-context everything should be created in(instantiatedDeclaration will be moved into that context anonymously) * @param inclusionTrace a trace as used in findDeclarationsInternal(..) * @param context A du-context that will be copied and used as internal context for declaration. If this is zero, no context will be copied. * @param templateArguments The template-arguments that will be used to instantiate the input-context. If this is empty, the intersting context will be only copied without specialization. If it contains exactly one argument, and that argument is invalid, the context is instantiated without arguments(default-arguments are used). Default-arguments will be used if needed. * @param instantiatedDeclaration The copied declaration this should belong to. If this is set, the created context will be made the given declaration's internal-context, and its parent-context will be set to the given context's parent-context. Also delayed types in the declaration will be resolved(The declaration will be changed) * @param instantiatedFrom The declaration instantiatedDeclaration should be/is instantiated from. This is needed to eventually change the declaration of in IdentifiedType. The instantiation has to be reserved before calling instantiateDeclarationAndContext! * @param doNotRegister If this is true, the context will not be registered anywhere, and can be deleted at will. * * The DU-Context must be read-locked but not write-locked when this is called. * */ KDEVCPPDUCHAIN_EXPORT CppDUContext* instantiateDeclarationAndContext( KDevelop::DUContext* parentContext, const KDevelop::TopDUContext* source, KDevelop::DUContext* context, const InstantiationInformation& templateArguments, KDevelop::Declaration* instantiatedDeclaration, KDevelop::Declaration* instantiatedFrom, bool doNotRegister = false ); /** * Returns whether any count of reference/pointer-types are followed by a delayed type * */ KDEVCPPDUCHAIN_EXPORT TypePtr containsDelayedType(AbstractType::Ptr type); /** * Eventually creates a copy of the given type, where all DelayedTypes that can be resolved in the given context are resolved. * */ KDEVCPPDUCHAIN_EXPORT AbstractType::Ptr resolveDelayedTypes( AbstractType::Ptr type, const KDevelop::DUContext* context, const KDevelop::TopDUContext* source, KDevelop::DUContext::SearchFlags searchFlags = KDevelop::DUContext::NoUndefinedTemplateParams ); template<> Declaration* SpecialTemplateDeclaration::resolve(const TopDUContext* topContext) const; } #endif