diff --git a/language/duchain/declaration.h b/language/duchain/declaration.h index 23ae9c2c9..27270bdb7 100644 --- a/language/duchain/declaration.h +++ b/language/duchain/declaration.h @@ -1,572 +1,572 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda Copyright 2007-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_DECLARATION_H #define KDEVPLATFORM_DECLARATION_H #include #include #include "types/abstracttype.h" #include "duchainbase.h" #include "instantiationinformation.h" #include "identifier.h" #include "indexeddeclaration.h" class QByteArray; namespace KDevelop { class AbstractType; class DUContext; class IndexedString; class DeclarationData; class DeclarationId; class Declaration; class IndexedTopDUContext; class TopDUContext; /** * \short Represents a single declaration in a definition-use chain. * * \note A du-context can be freely edited as long as it's parent-context is zero. * In the moment the parent-context is set, the context may only be edited when it * is allowed to edited it's top-level context (@see TopLevelContext::inDUChain()) */ class KDEVPLATFORMLANGUAGE_EXPORT Declaration : public DUChainBase { public: /// Access types - enum AccessPolicy { + enum AccessPolicy : quint8 { Public /**< a public declaration */, Protected /**< a protected declaration */, Private /**< a private declaration */, DefaultAccess /** TypePtr type() const { return TypePtr::dynamicCast(abstractType()); } /** * Access this declaration's type. * * \note You should not compare or permanently store instances of AbstractType::Ptr. Use IndexedType instead. * \returns this declaration's type, or null if none has been assigned. */ AbstractType::Ptr abstractType() const; /** * Set this declaration's type. * * \param type the type to assign. */ template void setType(TypePtr type) { setAbstractType(AbstractType::Ptr::staticCast(type)); } /** * Set this declaration's \a type. * * \param type this declaration's new type. */ virtual void setAbstractType(AbstractType::Ptr type); /** * Return an indexed form of this declaration's type. * Should be preferred, this is the fastest way, and the correct way for doing equality-comparsion. * * \returns the declaration's type. */ IndexedType indexedType() const; /** * Set this declaration's \a identifier. * * \param identifier this declaration's new identifier */ void setIdentifier(const Identifier& identifier); /** * Access this declaration's \a identifier. * * \returns this declaration's identifier. */ Identifier identifier() const; /** * Access this declaration's \a identifier. * * \return this declaration's identifier in indexed form. This is faster than identifier(), because it * equals the internal representation. Use this for example to do equality-comparison. */ const IndexedIdentifier& indexedIdentifier() const; /** * Determine the global qualified identifier of this declaration. * * \note This function is expensive, equalQualifiedIdentifier() is preferred if you * just want to compare equality. */ QualifiedIdentifier qualifiedIdentifier() const; /** * Compares the qualified identifier of this declaration with the other one, without needing to compute it. * This is more efficient than comparing the results of qualifiedIdentifier(). * * \param rhs declaration to compare identifiers with * \returns true if the identifiers are equal, otherwise false. */ bool equalQualifiedIdentifier(const Declaration* rhs) const; /** * Returns the kind of this declaration. @see Kind */ Kind kind() const; /** * Set the kind. * * \param kind new kind */ void setKind(Kind kind); /** * Returns the comment associated to this declaration in the source-code, * or an invalid string if there is none. * * Stored in utf-8 encoding. */ QByteArray comment() const; /** * Sets the comment for this declaration. * * @note Should be utf-8 encoded. */ void setComment(const QByteArray& str); /** * Sets the comment for this declaration. */ void setComment(const QString& str); /** * Access whether this declaration is in the symbol table. * * \returns true if this declaration is in the symbol table, otherwise false. */ bool inSymbolTable() const; /** * Adds or removes this declaration to/from the symbol table. * * \param inSymbolTable true to add this declaration to the symbol table, false to remove it. */ virtual void setInSymbolTable(bool inSymbolTable); /** * Equivalence operator. * * \param other Other declaration to compare. * \returns true if the declarations are equal, otherwise false. */ bool operator==(const Declaration& other) const; /** * Determine this declaration as a string. \returns this declaration as a string. */ virtual QString toString() const; /** * Returns a map of files to use-ranges. * * The key of the returned map is an url of a file. The value * is a list with all use-ranges of this declaration in that file. * * \note The ranges are in the documents local revision, * use \c DUChainUtils::transformFromRevision or \c usesCurrentRevision() * * \note The uses are unique, no 2 uses are returend that have the same range within the same file. * * \note This is a non-trivial operation and hence expensive. */ QMap > uses() const; /** * Determines whether the declaration has any uses or not. * * Cheaper than calling uses(). */ bool hasUses() const; /** * Returns a map of files to use-ranges. * * The key of the returned map is an url of a file. The value * is a list with all use-ranges of this declaration in that file. * * \note The uses are unique, no 2 uses are returend that have the same range within the same file. * * \warning This must be called only from within the foreground, or with the foreground lock locked. * * \note This is a non-trivial operation and hence expensive. */ QMap > usesCurrentRevision() const; /** * This hash-value should differentiate between multiple different * declarations that have the same qualifiedIdentifier, but should have a different * identity, and thus own Definitions and own Uses assigned. * * Affected by function-arguments, whether this is a template-declaration, etc.. */ virtual uint additionalIdentity() const; /** * TODO document * */ virtual IndexedInstantiationInformation specialization() const; /** * \see DeclarationId * * \param forceDirect When this is true, the DeclarationId is force to be direct, * and can be resolved without a symbol-table and top-context. * The same goes for Declarations that have \c alwaysForceDirect() * set to true. */ virtual DeclarationId id(bool forceDirect = false) const; /** * Returns an index that uniquely identifies this declaration within its surrounding top-context. * * That index can be passed to \c TopDUContext::declarationFromIndex(index) to get the declaration. * This is only valid when the declaration is not a specialization (\c specialization() returns 0), * and if it is not anonymous in its context. * * \note for this to be valid, allocateOwnIndex() must have been called first. * \note the highest big of the index is always zero! * \returns the index of the declaration within its TopDUContext. */ uint ownIndex() const; /** * Whether this declaration has been inserted anonymously into its parent-context */ bool isAnonymous() const; /** * Clear the index for this declaration in the top context that was allocated with allocateOwnIndex(). */ void clearOwnIndex(); /** * Create an index to this declaration from the topContext(). Needed to be able to retrieve ownIndex(). */ void allocateOwnIndex(); /** * Returns a clone of this declaration, with the difference that the returned declaration * has no context set, i.e. \c context() returns zero. * * The declaration will not be registered anywhere, so you must care about its deletion. * * This declaration's text-range will be referenced from the clone, so the clone must not * live longer than the original. */ Declaration* clone() const; /** * Signalized that among multiple possible specializations, this one should be used in the UI from now on. * * Currently mainly used in C++ for template support. The default-implementation registers the current * specialization of this declaration to SpecializationStore if it is nonzero. */ virtual void activateSpecialization(); enum { Identity = 7 }; protected: /** * Constructor for copy constructors in subclasses. * * \param dd data to copy. * \param url document url in which this object is located. * \param range text range which this object covers. */ Declaration( DeclarationData & dd, const RangeInRevision& range ); /** * Returns true if this declaration is being currently destroyed persistently, * which means that it should eventually deregister itself from persistent storage facilities. * * Only call this from destructors. */ bool persistentlyDestroying() const; DUCHAIN_DECLARE_DATA(Declaration) private: /** * Sub-classes should implement this and should copy as much information into the clone as possible without breaking the du-chain. * Sub-classes should also implement a public copy-constructor that can be used for cloning by sub-classes. * * \note You do not have to implement this for your language if you are not going to use it(the du-chain itself does not and should not depend on it). * */ virtual Declaration* clonePrivate() const; void updateCodeModel(); void rebuildDynamicData(DUContext* parent, uint ownIndex) override; friend class DUContext; friend class IndexedDeclaration; friend class LocalIndexedDeclaration; friend class TopDUContextDynamicData; DUContext* m_context; TopDUContext* m_topContext; int m_indexInTopContext; }; } #endif // KDEVPLATFORM_DECLARATION_H diff --git a/language/duchain/duchainbase.h b/language/duchain/duchainbase.h index 1480ba09a..c7cae377d 100644 --- a/language/duchain/duchainbase.h +++ b/language/duchain/duchainbase.h @@ -1,220 +1,221 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda Copyright 2007/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_DUCHAINBASE_H #define KDEVPLATFORM_DUCHAINBASE_H #include #include "appendedlist.h" #include "duchainpointer.h" #include #include namespace KTextEditor { class Cursor; class Range; } namespace KDevelop { class PersistentMovingRange; class DUContext; class TopDUContext; class DUChainBase; class IndexedString; ///Use this to declare the data functions in your DUChainBase based class. @warning Behind this macro, the access will be "public". #define DUCHAIN_DECLARE_DATA(Class) \ inline class Class##Data* d_func_dynamic() { makeDynamic(); return reinterpret_cast(d_ptr); } \ inline const class Class##Data* d_func() const { return reinterpret_cast(d_ptr); } \ public: typedef Class ## Data Data; private: #define DUCHAIN_D(Class) const Class##Data * const d = d_func() #define DUCHAIN_D_DYNAMIC(Class) Class##Data * const d = d_func_dynamic() ///@note When a data-item is stored on disk, no destructors of contained items will be called while destruction. ///DUChainBase assumes that each item that has constant data, is stored on disk. ///However the destructor is called even on constant items, when they have been replaced with a dynamic item. ///This tries to keep constructor/destructor count consistency persistently, which allows doing static reference-counting ///using contained classes in their constructor/destructors(For example the class Utils::StorableSet). ///This means that the data of all items that are stored to disk _MUST_ be made constant before their destruction. ///This also means that every item that is "semantically" deleted, _MUST_ have dynamic data before its destruction. ///This also means that DUChainBaseData based items should never be cloned using memcpy, but rather always using the copy-constructor, ///even if both sides are constant. class KDEVPLATFORMLANGUAGE_EXPORT DUChainBaseData { public: DUChainBaseData() : classId(0) { initializeAppendedLists(); } DUChainBaseData(const DUChainBaseData& rhs) : m_range(rhs.m_range), classId(rhs.classId) { initializeAppendedLists(); } ~DUChainBaseData() { freeAppendedLists(); } RangeInRevision m_range; APPENDED_LISTS_STUB(DUChainBaseData) - uint classId; + quint16 classId; bool isDynamic() const { return m_dynamic; } /** * Internal setup for the data structure. * * This must be called from actual class that belongs to this data(not parent classes), and the class must have the * "Identity" enumerator with a unique identity. Do NOT call this in copy-constructors! */ template void setClassId(T*) { + static_assert(T::Identity < std::numeric_limits::max(), "Class ID out of bounds"); classId = T::Identity; } uint classSize() const; ///This is called whenever the data-object is being deleted memory-wise, but not semantically(Which means it stays on disk) ///Implementations of parent-classes must always be called void freeDynamicData() { } ///Used to decide whether a constructed item should create constant data. ///The default is "false", so dynamic data is created by default. ///This is stored thread-locally. static bool& shouldCreateConstantData(); ///Returns whether initialized objects should be created as dynamic objects static bool appendedListDynamicDefault() { return !shouldCreateConstantData(); } }; /** * Base class for definition-use chain objects. * * This class provides a thread safe pointer type to reference duchain objects * while the DUChain mutex is not held (\see DUChainPointer) */ class KDEVPLATFORMLANGUAGE_EXPORT DUChainBase { public: /** * Constructor. * * \param url url of the document where this occurred * \param range range of the alias declaration's identifier */ explicit DUChainBase(const RangeInRevision& range); /// Destructor virtual ~DUChainBase(); /** * Determine the top context to which this object belongs. */ virtual TopDUContext* topContext() const; /** * Returns a special pointer that can be used to track the existence of a du-chain object across locking-cycles. * @see DUChainPointerData * */ const QExplicitlySharedDataPointer& weakPointer() const; virtual IndexedString url() const; enum { Identity = 1 }; ///After this was called, the data-pointer is dynamic. It is cloned if needed. void makeDynamic(); explicit DUChainBase( DUChainBaseData& dd ); ///This must only be used to change the storage-location or storage-kind(dynamic/constant) of the data, but ///the data must always be equal! virtual void setData(DUChainBaseData*, bool constructorCalled = true); ///Returns the range assigned to this object, in the document revision when this document was last parsed. RangeInRevision range() const; ///Changes the range assigned to this object, in the document revision when this document is parsed. void setRange(const RangeInRevision& range); ///Returns the range assigned to this object, transformed into the current revision of the document. ///@warning This must only be called from the foreground thread, or with the foreground lock acquired. KTextEditor::Range rangeInCurrentRevision() const; ///Returns the range assigned to this object, transformed into the current revision of the document. ///The returned object is unique at each call, so you can use it and change it in whatever way you want. ///@warning This must only be called from the foreground thread, or with the foreground lock acquired. PersistentMovingRange::Ptr createRangeMoving() const; ///Transforms the given cursor in the current document revision to its according position ///in the parsed document containing this duchain object. The resulting cursor will be directly comparable to the non-translated ///range() members in the duchain, but only for one duchain locking cycle. ///@warning This must only be called from the foreground thread, or with the foreground lock acquired. CursorInRevision transformToLocalRevision(const KTextEditor::Cursor& cursor) const; ///Transforms the given range in the current document revision to its according position ///in the parsed document containing this duchain object. The resulting cursor will be directly comparable to the non-translated ///range() members in the duchain, but only for one duchain locking cycle. ///@warning This must only be called from the foreground thread, or with the foreground lock acquired. RangeInRevision transformToLocalRevision(const KTextEditor::Range& range) const; KTextEditor::Cursor transformFromLocalRevision(const CursorInRevision& cursor) const; KTextEditor::Range transformFromLocalRevision(const RangeInRevision& range) const; protected: /** * Creates a duchain object that uses the data of the given one, and will not delete it on destruction. * The data will be shared, and this object must be deleted before the given one is. */ DUChainBase( DUChainBase& rhs ); /** * Constructor for copy constructors in subclasses. * * \param dd data to use. * \param url document url in which this object is located. * \param range text range which this object covers. */ DUChainBase( DUChainBaseData& dd, const RangeInRevision& range ); ///Called after loading to rebuild the dynamic data. If this is a context, this should recursively work on all sub-contexts. virtual void rebuildDynamicData(DUContext* parent, uint ownIndex); /// Data pointer that is shared across all the inheritance hierarchy DUChainBaseData* d_ptr; private: mutable QExplicitlySharedDataPointer m_ptr; public: DUCHAIN_DECLARE_DATA(DUChainBase) }; } #endif // KDEVPLATFORM_DUCHAINBASE_H diff --git a/language/duchain/ducontext.h b/language/duchain/ducontext.h index 9acab9ebb..d75fa46d4 100644 --- a/language/duchain/ducontext.h +++ b/language/duchain/ducontext.h @@ -1,933 +1,933 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda 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 KDEVPLATFORM_DUCONTEXT_H #define KDEVPLATFORM_DUCONTEXT_H #include #include #include #include #include #include "identifier.h" #include "duchainbase.h" #include "types/abstracttype.h" #include "duchainpointer.h" #include "declarationid.h" #include "indexedducontext.h" class QWidget; namespace KDevelop { class Declaration; class DUChain; class Use; class TopDUContext; class DUContext; class DUContextData; class KDEVPLATFORMLANGUAGE_EXPORT DUChainVisitor { public: virtual void visit(DUContext* context) = 0; virtual void visit(Declaration* declaration) = 0; virtual ~DUChainVisitor(); }; typedef DUChainPointer DUContextPointer; /** * A single context in source code, represented as a node in a * directed acyclic graph. * * Access to context objects must be serialised by holding the * chain lock, ie. DUChain::lock(). * * NOTE: A du-context can be freely edited as long as it's parent-context is zero. * In the moment the parent-context is set, the context may only be edited when it * is allowed to edited it's top-level context(@see TopLevelContext::inDUChain() * * @todo change child relationships to a linked list within the context? */ class KDEVPLATFORMLANGUAGE_EXPORT DUContext : public DUChainBase { friend class Use; friend class Declaration; friend class DeclarationData; friend class DUContextData; friend class DUContextDynamicData; friend class Definition; friend class VisibleDeclarationIterator; public: /** * Constructor. No convenience methods, as the initialisation order is important, * * @param anonymous Whether the context should be added as an anonymous context to the parent. That way the context can never be found through any of the parent's member-functions. * * If the parent is in the symbol table and the context is not anonymous, it will also be added to the symbol table. You nead a write-lock to the DUChain then */ explicit DUContext(const RangeInRevision& range, DUContext* parent = 0, bool anonymous = false); explicit DUContext(DUContextData&); /** * Destructor. Will delete all child contexts which are defined within * the same file as this context. */ virtual ~DUContext(); - enum ContextType { + enum ContextType : quint8 { Global /**< A context that declares functions, namespaces or classes */, Namespace /**< A context that declares namespace members */, Class /**< A context that declares class members */, Function /**< A context that declares function-arguments */, Template /**< A context that declares template-parameters */, Enum /**< A context that contains a list of enumerators */, Helper /**< A helper context. This context is treated specially during search: * when searching within the imports of a context, and that context's parent * is a context of type DUContext::Helper, then the upwards search is continued * into that helper(The decision happens in shouldSearchInParent) */, Other /**< Represents executable code, like for example within a compound-statement */ }; enum SearchFlag { NoSearchFlags = 0 /**< Searching for everything */, InImportedParentContext = 1 /**< Internal, do not use from outside */, OnlyContainerTypes = 2 /**< Not implemented yet */, DontSearchInParent = 4 /**< IF this flag is set, findDeclarations(..) will not search for the identifier in parent-contexts(which does not include imported parent-contexts) */, NoUndefinedTemplateParams = 8 /**< For languages that support templates(like C++). If this is set, the search should fail as soon as undefined template-parameters are involved. */, DirectQualifiedLookup = 16 /**< When this flag is used, the searched qualified identifier should NOT be split up into it's components and looked up one by one. Currently only plays a role in C++ specific parts. */, NoFiltering = 32 /**< Should be set when no filtering at all is wished, not even filtering that is natural for the underlying language(For example in C++, constructors are filtered out be default) */, OnlyFunctions = 64 /**< When this is given, only function-declarations are returned. In case of C++, this also means that constructors can be retrieved, while normally they are filtered out. */, NoImportsCheck = 128 /**< With this parameter, a global search will return all matching items, from all contexts, not only from imported ones. */, NoSelfLookUp = 256 /**< With this parameter, the special-treatment during search that allows finding the context-class by its name is disabled. */, DontResolveAliases = 512 /**< Disables the resolution of alias declarations in the returned list*/, LastSearchFlag = 1024 }; Q_DECLARE_FLAGS(SearchFlags, SearchFlag) ContextType type() const; void setType(ContextType type); /** * If this context was opened by a declaration or definition, this returns that item. * * The returned declaration/definition will have this context set as @c internalContext() */ Declaration* owner() const; /** * Sets the declaration/definition, and also updates it's internal context (they are strictly paired together). * * The declaration has to be part of the same top-context. */ void setOwner(Declaration* decl); /** * Calculate the depth of this context, from the top level context in the file. */ int depth() const; /** * Find the top context. */ virtual TopDUContext* topContext() const override; /** * Visits all duchain objects in the whole duchain. * * Classes that hold a unique link to duchain objects like instantiations * have to pass the visitor over to those classes. * */ virtual void visit(DUChainVisitor& visitor); /** * Find the context which most specifically covers @a position. * * The search is recursive, so the most specific context is found. * * @param includeRightBorder When this is true, contexts will also be found that * have the position on their right border. * * @warning This uses the ranges in the local revision of the document (at last parsing time). * Use DUChainBase::transformToLocalRevision to transform the cursor into that revision first. */ DUContext* findContextAt(const CursorInRevision& position, bool includeBorders = false) const; /** * Find a child declaration that has a rang that covers the given @a position. * * The search is local, not recursive. * * @warning This uses the ranges in the local revision of the document (at last parsing time). * Use DUChainBase::transformToLocalRevision to transform the cursor into that revision first. */ Declaration* findDeclarationAt(const CursorInRevision& position) const; /** * Find the context which most specifically covers @a range. * * @warning This uses the ranges in the local revision of the document (at last parsing time). * Use DUChainBase::transformToLocalRevision to transform the cursor into that revision first. */ DUContext* findContextIncluding(const RangeInRevision& range) const; /** * Calculate the fully qualified scope identifier. */ QualifiedIdentifier scopeIdentifier(bool includeClasses = false) const; /** * Returns true if this context has the same scope identifier as the given one. * * @note This is much more efficient than computing the identifiers through @c scopeIdentifier(..) * and comparing them */ bool equalScopeIdentifier(const DUContext* rhs) const; /** * Scope identifier, used to qualify the identifiers occurring in each context. * * This is the part relative to the parent context. */ QualifiedIdentifier localScopeIdentifier() const; /** * Same as @c localScopeIdentifier(), but faster. */ IndexedQualifiedIdentifier indexedLocalScopeIdentifier() const; /** * Scope identifier, used to qualify the identifiers occurring in each context * This must not be called once this context has children. */ void setLocalScopeIdentifier(const QualifiedIdentifier& identifier); /** * Returns whether this context is listed in the symbol table (Namespaces and classes) */ bool inSymbolTable() const; /** * Move this object into/out of the symbol table. * * @note You need to have a duchain write lock, unless this is a TopDUContext. */ void setInSymbolTable(bool inSymbolTable); /** * Returns the immediate parent context of this context. */ DUContext* parentContext() const; /** * Represents an imported parent context. */ struct KDEVPLATFORMLANGUAGE_EXPORT Import { /** * @note DUChain must be read-locked when this is called */ Import(DUContext* context, const DUContext* importer, const CursorInRevision& position = CursorInRevision::invalid()); Import() : position(CursorInRevision::invalid()) { } Import(const DeclarationId& id, const CursorInRevision& position = CursorInRevision::invalid()); bool operator==(const Import& rhs) const { return m_context == rhs.m_context && m_declaration == rhs.m_declaration; } /** * @param topContext The top-context from where to start searching. * This is important to find the correct imports * in the case of templates or similar structures. */ DUContext* context(const TopDUContext* topContext, bool instantiateIfRequired = true) const; /** * Returns the top-context index, if this import is not a specialization import. */ uint topContextIndex() const { return m_context.topContextIndex(); } IndexedDUContext indexedContext() const { return m_context; } /** * Returns true if this import is direct. * * That is, the import is not referred to by its identifier, * but rather directly by its index. */ bool isDirect() const; /** * If this import is indirect, returns the imported declaration-id */ DeclarationId indirectDeclarationId() const { return m_declaration; } CursorInRevision position; private: //Either we store m_declaration, or m_context. That way we can resolve specialized contexts. ///@todo Compress using union DeclarationId m_declaration; IndexedDUContext m_context; }; /** * Returns the list of imported parent contexts for this context. * * @warning The list may contain objects that are not valid any more, * i.e. data() returns zero, @see addImportedParentContext) * @warning The import structure may contain loops if this is a TopDUContext, * so be careful when traversing the tree. * @note This is expensive. */ virtual QVector importedParentContexts() const; /** * If the given context is directly imported into this one, and * @c addImportedParentContext(..) was called with a valid cursor, * this will return that position. Otherwise an invalid cursor is returned. */ virtual CursorInRevision importPosition(const DUContext* target) const; /** * Returns true if this context imports @param origin at any depth, else false. */ virtual bool imports(const DUContext* origin, const CursorInRevision& position = CursorInRevision::invalid()) const; /** * Adds an imported context. * * @param anonymous If this is true, the import will not be registered at the imported context. * This allows du-chain contexts importing without having a write-lock. * @param position Position where the context is imported. This is mainly important in C++ with included files. * * If the context is already imported, only the position is updated. * * @note Be sure to have set the text location first, so that the chain is sorted correctly. */ virtual void addImportedParentContext(DUContext* context, const CursorInRevision& position = CursorInRevision::invalid(), bool anonymous = false, bool temporary = false); /** * Adds an imported context, which may be indirect. * * @warning This is only allowed if this context is _NOT_ a top-context. * @warning When using this mechanism, this context will not be registered as importer to the other one. * @warning The given import _must_ be indirect. * * @return true if the import was already imported before, else false. */ bool addIndirectImport(const DUContext::Import& import); /** * Removes a child context. */ virtual void removeImportedParentContext(DUContext* context); /** * Clear all imported parent contexts. */ virtual void clearImportedParentContexts(); /** * If this is set to true, all declarations that are added to this context * will also be visible in the parent-context. * * They will be visible in the parent using @c findDeclarations(...) and * @c findLocalDeclarations(...), but will not be in the list of @c localDeclarations(...). */ void setPropagateDeclarations(bool propagate); bool isPropagateDeclarations() const; /** * Returns the list of contexts importing this context. * * @note Very expensive, since the importers top-contexts need to be loaded. */ virtual QVector importers() const; /** * Returns the list of indexed importers. * * Cheap, because nothing needs to be loaded. */ KDevVarLengthArray indexedImporters() const; /** * Returns the list of immediate child contexts for this context. * * @note This is expensive. */ QVector childContexts() const; /** * Clears and deletes all child contexts recursively. * * This will not cross file boundaries. */ void deleteChildContextsRecursively(); /** * Returns true if this declaration is accessible through the du-chain, * and thus cannot be edited without a du-chain write lock */ virtual bool inDUChain() const; /** * Retrieve the context which is specialized with the given * @a specialization as seen from the given @a topContext. * * @param specialization the specialization index (see DeclarationId) * @param topContext the top context representing the perspective from which to specialize. * if @p topContext is zero, only already existing specializations are returned, * and if none exists, zero is returned. * @param upDistance upwards distance in the context-structure of the * given specialization-info. This allows specializing children. */ virtual DUContext* specialize(const IndexedInstantiationInformation& specialization, const TopDUContext* topContext, int upDistance = 0); /** * Searches for and returns a declaration with a given @a identifier in this context, which * is currently active at the given text @a position, with the given type @a dataType. * In fact, only items are returned that are declared BEFORE that position. * * @param identifier the identifier of the definition to search for * @param location the text position to search for * @param topContext the top-context from where a completion is triggered. * This is needed so delayed types (templates in C++) can be resolved in the correct context. * @param type the type to match, or null for no type matching. * * @returns the requested declaration if one was found, otherwise null. * * @warning this may return declarations which are not in this tree, you may need to lock them too... */ QList findDeclarations(const QualifiedIdentifier& identifier, const CursorInRevision& position = CursorInRevision::invalid(), const AbstractType::Ptr& dataType = AbstractType::Ptr(), const TopDUContext* topContext = 0, SearchFlags flags = NoSearchFlags) const; /** * Searches for and returns a declaration with a given @a identifier in this context, which * is currently active at the given text @a position. * * @param identifier the identifier of the definition to search for * @param topContext the top-context from where a completion is triggered. * This is needed so delayed types(templates in C++) can be resolved in the correct context. * @param location the text position to search for * * @returns the requested declaration if one was found, otherwise null. * * @warning this may return declarations which are not in this tree, you may need to lock them too... * * @overload */ QList findDeclarations(const IndexedIdentifier& identifier, const CursorInRevision& position = CursorInRevision::invalid(), const TopDUContext* topContext = 0, SearchFlags flags = NoSearchFlags) const; /** * Prefer the version above for speed reasons. */ QList findDeclarations(const Identifier& identifier, const CursorInRevision& position = CursorInRevision::invalid(), const TopDUContext* topContext = 0, SearchFlags flags = NoSearchFlags) const; /** * Returns the type of any @a identifier defined in this context, or * null if one is not found. * * Does not search imported parent-contexts(like base-classes). */ QList findLocalDeclarations(const IndexedIdentifier& identifier, const CursorInRevision& position = CursorInRevision::invalid(), const TopDUContext* topContext = 0, const AbstractType::Ptr& dataType = AbstractType::Ptr(), SearchFlags flags = NoSearchFlags) const; /** * Prefer the version above for speed reasons. */ QList findLocalDeclarations(const Identifier& identifier, const CursorInRevision& position = CursorInRevision::invalid(), const TopDUContext* topContext = 0, const AbstractType::Ptr& dataType = AbstractType::Ptr(), SearchFlags flags = NoSearchFlags) const; /** * Clears all local declarations. * * Does not delete the declaration; the caller assumes ownership. */ QVector clearLocalDeclarations(); /** * Clears all local declarations. * * Deletes these declarations, as the context has ownership. */ void deleteLocalDeclarations(); /** * Returns all local declarations * * @param source A source-context that is needed to instantiate template-declarations in some cases. * If it is zero, that signalizes that missing members should not be instantiated. */ virtual QVector localDeclarations(const TopDUContext* source = 0) const; /** * Searches for the most specific context for the given cursor @a position in the given @a url. * * @param location the text position to search for * @param parent the parent context to search from (this is mostly an internal detail, but if you only * want to search in a subbranch of the chain, you may specify the parent here) * * @returns the requested context if one was found, otherwise null. */ DUContext* findContext(const CursorInRevision& position, DUContext* parent = 0) const; /** * Iterates the tree to see if the provided @a context is a subcontext of this context. * * @returns true if @a context is a subcontext, otherwise false. */ bool parentContextOf(DUContext* context) const; /** * Return a list of all reachable declarations for a given cursor @a position in a given @a url. * * @param location the text position to search for * @param topContext the top-context from where a completion is triggered. * This is needed so delayed types(templates in C++) can be resolved * in the correct context. * @param searchInParents should declarations from parent-contexts be listed? * If false, only declarations from this and imported contexts will be returned. * * The returned declarations are paired together with their inheritance-depth, * which is the count of steps to into other contexts that were needed to find the declaration. * Declarations reached through a namespace- or global-context are offsetted by 1000. * * This also includes Declarations from sub-contexts that were propagated upwards * using @c setPropagateDeclarations(true). * * @returns the requested declarations, if any were active at that location. * Declarations propagated into this context(@c setPropagateDeclarations) are included. */ QList< QPair > allDeclarations(const CursorInRevision& position, const TopDUContext* topContext, bool searchInParents = true) const; /** * Delete and remove all slaves (uses, declarations, definitions, contexts) that are not in the given set. */ void cleanIfNotEncountered(const QSet& encountered); /** * Uses: * A "Use" represents any position in a document where a Declaration is used literally. * For efficiency, since there can be many many uses, they are managed efficiently by * TopDUContext and DUContext. In TopDUContext, the used declarations are registered * and assigned a "Declaration-Index" while calling TopDUContext::indexForUsedDeclaration. * From such a declaration-index, the declaration can be retrieved back by calling * @c TopDUContext::usedDeclarationForIndex. * * The actual uses are stored within DUContext, where each use consists of a range and * the declaration-index of the used declaration. * */ /** * Return a vector of all uses which occur in this context. * * To get the actual declarations, use @c TopDUContext::usedDeclarationForIndex(..) * with the declarationIndex. */ const Use* uses() const; /** * Returns the count of uses that can be accessed through @c uses() */ int usesCount() const; /** * Determines whether the given declaration has uses or not */ static bool declarationHasUses(Declaration* decl); /** * Find the use which encompasses @a position, if one exists. * @return The local index of the use, or -1 */ int findUseAt(const CursorInRevision& position) const; /** * @note The change must not break the ordering */ void changeUseRange(int useIndex, const RangeInRevision& range); /** * Assigns the declaration represented by @param declarationIndex * to the use with index @param useIndex. */ void setUseDeclaration(int useIndex, int declarationIndex); /** * Creates a new use of the declaration given through @param declarationIndex. * The index must be retrieved through @c TopDUContext::indexForUsedDeclaration(..). * * @param range The range of the use * @param insertBefore A hint where in the vector of uses to insert the use. * Must be correct so the order is preserved(ordered by position), * or -1 to automatically choose the position. * * @return Local index of the created use */ int createUse(int declarationIndex, const RangeInRevision& range, int insertBefore = -1); /** * Deletes the use number @param index. * * @param index is the position in the vector of uses, not a used declaration index. */ void deleteUse(int index); /** * Clear and delete all uses in this context. */ virtual void deleteUses(); /** * Recursively delete all uses in this context and all its child-contexts */ virtual void deleteUsesRecursively(); /** * Can be specialized by languages to create a navigation/information-widget. * * Ideally, the widget would be based on @c KDevelop::QuickOpenEmbeddedWidgetInterface * for user-interaction within the quickopen list. * * The returned widget will be owned by the caller. * * @param decl A member-declaration of this context the navigation-widget should be created for. * Zero to create a widget for this context. * @param topContext Top-context from where the navigation-widget is triggered. * In C++, this is needed to resolve forward-declarations. * @param htmlPrefix Html-formatted text that should be prepended before any information shown by this widget * @param htmlSuffix Html-formatted text that should be appended to any information shown by this widget * * Can return zero which disables the navigation widget. * * If you setProperty("DoNotCloseOnCursorMove", true) on the widget returned, * then the widget will not close when the cursor moves in the document, which * enables you to change the document contents from the widget without immediately closing the widget. */ virtual QWidget* createNavigationWidget(Declaration* decl = 0, TopDUContext* topContext = 0, const QString& htmlPrefix = QString(), const QString& htmlSuffix = QString()) const; enum { Identity = 2 }; /** * Represents multiple qualified identifiers in a way that is better * to manipulate and allows applying namespace-aliases or -imports easily. * * A SearchItem generally represents a tree of identifiers, and represents * all the qualified identifiers that can be constructed by walking * along the tree starting at an arbitrary root-node into the depth using the "next" pointers. * * The insertion order in the hierarchy determines the order of the represented list. */ struct KDEVPLATFORMLANGUAGE_EXPORT SearchItem : public QSharedData { typedef QExplicitlySharedDataPointer Ptr; typedef KDevVarLengthArray PtrList; /** * Constructs a representation of the given @param id qualified identifier, * starting at its index @param start. * * @param nextItem is set as next item to the last item in the chain */ SearchItem(const QualifiedIdentifier& id, const Ptr& nextItem = Ptr(), int start = 0); /** * Constructs a representation of the given @param id qualified identifier, * starting at its index @param start. * * @param nextItem is set as next item to the last item in the chain */ SearchItem(const QualifiedIdentifier& id, const PtrList& nextItems, int start = 0); SearchItem(bool explicitlyGlobal, const IndexedIdentifier& id, const PtrList& nextItems); SearchItem(bool explicitlyGlobal, const IndexedIdentifier& id, const Ptr& nextItem); bool isEmpty() const; bool hasNext() const; /** * Appends the given item to every item that can be reached from this item, * and not only to the end items. * * The effect to search is that the given item is searched with all prefixes * contained in this earch-item prepended. * * @warning This changes all contained sub-nodes, but they can be shared with * other SearchItem trees. You should not use this on SearchItem trees * that have shared nodes with other trees. * * @note These functions ignore explicitly global items. */ void addToEachNode(const Ptr& item); void addToEachNode(const PtrList& items); /** * Returns true if the given identifier matches one of the identifiers * represented by this SearchItem. Does not respect the explicitlyGlobal flag */ bool match(const QualifiedIdentifier& id, int offset = 0) const; /** * @note expensive */ QList toList(const QualifiedIdentifier& prefix = QualifiedIdentifier()) const; void addNext(const Ptr& other); bool isExplicitlyGlobal; IndexedIdentifier identifier; PtrList next; }; ///@todo Should be protected, moved here temporarily until I have figured ///out why the gcc 4.1.3 fails in cppducontext.h:212, which should work (within kdevelop) /// Declaration search implementation /** * This is a more complex interface to the declaration search engine. * * Always prefer @c findDeclarations(..) when possible. * * Advantage of this interface: * - You can search multiple identifiers at one time. * However, those should be aliased identifiers for one single item, because * search might stop as soon as one item is found. * - The source top-context is needed to correctly resolve template-parameters * * @param position A valid position, if in doubt use textRange().end() * * @warning @p position must be valid! * * @param depth Depth of the search in parents. This is used to prevent endless * recursions in endless import loops. * * * @return whether the search was successful. If it is false, it had to be stopped * for special reasons (like some flags) */ typedef QList DeclarationList; virtual bool findDeclarationsInternal(const SearchItem::PtrList& identifiers, const CursorInRevision& position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source, SearchFlags flags, uint depth ) const; /** * Returns the qualified identifier @p id with all aliases (for example namespace imports) applied * * @example: If the namespace 'Foo' is imported, and id is 'Bar', * then the returned list is 'Bar' and 'Foo::Bar' */ QList fullyApplyAliases(const QualifiedIdentifier& id, const TopDUContext* source) const; protected: /** * After one scope was searched, this function is asked whether more * results should be collected. Override it, for example to collect overloaded functions. * * The default-implementation returns true as soon as decls is not empty. */ virtual bool foundEnough( const DeclarationList& decls , SearchFlags flags ) const; /** * Merges definitions and their inheritance-depth up all branches of the * definition-use chain into one hash. * * This includes declarations propagated from sub-contexts. * * @param hadUrls is used to count together all contexts that already were * visited, so they are not visited again. */ virtual void mergeDeclarationsInternal(QList< QPair >& definitions, const CursorInRevision& position, QHash& hadContexts, const TopDUContext* source, bool searchInParents = true, int currentDepth = 0) const; void findLocalDeclarationsInternal(const Identifier& identifier, const CursorInRevision & position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source, SearchFlags flags ) const; virtual void findLocalDeclarationsInternal(const IndexedIdentifier& identifier, const CursorInRevision & position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source, SearchFlags flags ) const; /** * Applies namespace-imports and namespace-aliases and returns * possible absolute identifiers that need to be searched. * * @param targetIdentifiers will be filled with all identifiers that should * be searched for, instead of identifier. * @param onlyImports if this is true, namespace-aliases will not be respected, * but only imports. This is faster. */ void applyAliases(const SearchItem::PtrList& identifiers, SearchItem::PtrList& targetIdentifiers, const CursorInRevision& position, bool canBeNamespace, bool onlyImports = false) const; /** * Applies the aliases that need to be applied when moving the search * from this context up to the parent-context. * * The default-implementation adds a set of identifiers with the own local * identifier prefixed, if this is a namespace. * * For C++, this is needed when searching out of a namespace, so the item * can be found within that namespace in another place. */ virtual void applyUpwardsAliases(SearchItem::PtrList& identifiers, const TopDUContext* source) const; DUContext(DUContextData& dd, const RangeInRevision& range, DUContext* parent = 0, bool anonymous = false); /** * Just uses the data from the given context. Doesn't copy or change anything, * and the data will not be deleted on this contexts destruction. */ DUContext(DUContext& useDataFrom); /** * Whether this context, or any of its parent contexts, has been inserte * anonymously into the du-chain * * @see DUContext::DUContext */ bool isAnonymous() const; /** * This is called whenever the search needs to do the decision whether it * should be continued in the parent context. * * It is not called when the DontSearchInParent flag is set. Else this should * be overridden to do language-specific logic. * * The default implementation returns false if the flag InImportedParentContext is set. */ virtual bool shouldSearchInParent(SearchFlags flags) const; private: void rebuildDynamicData(DUContext* parent, uint ownIndex) override; friend class TopDUContext; friend class IndexedDUContext; friend class LocalIndexedDUContext; friend class TopDUContextDynamicData; DUCHAIN_DECLARE_DATA(DUContext) class DUContextDynamicData* m_dynamicData; }; /** * This is the identifier that can be used to search namespace-import declarations, * and should be used to store namespace-imports. * * It is stored statically for performance-reasons, so it doesn't need to be * constructed every time it is used. * * @see NamespaceAliasDeclaration. */ KDEVPLATFORMLANGUAGE_EXPORT const Identifier& globalImportIdentifier(); /** * This is the identifier that can be used to search namespace-alias declarations. * * It is stored statically for performance-reasons, so it doesn't need to be * constructed every time it is used. * * @see NamespaceAliasDeclaration. */ KDEVPLATFORMLANGUAGE_EXPORT const Identifier& globalAliasIdentifier(); /** * This is the identifier that can be used to search namespace-import declarations, * and should be used to store namespace-imports. * * It is stored statically for performance-reasons, so it doesn't need to be * constructed every time it is used. * * @see NamespaceAliasDeclaration. */ KDEVPLATFORMLANGUAGE_EXPORT const IndexedIdentifier& globalIndexedImportIdentifier(); /** * This is the identifier that can be used to search namespace-alias declarations. * * It is stored statically for performance-reasons, so it doesn't need to be * constructed every time it is used. * * @see NamespaceAliasDeclaration. */ KDEVPLATFORMLANGUAGE_EXPORT const IndexedIdentifier& globalIndexedAliasIdentifier(); /** * Collects all uses of the given @param declarationIndex */ KDEVPLATFORMLANGUAGE_EXPORT QList allUses(DUContext* context, int declarationIndex, bool noEmptyRanges = false); } Q_DECLARE_TYPEINFO(KDevelop::DUContext::Import, Q_MOVABLE_TYPE); #endif // KDEVPLATFORM_DUCONTEXT_H diff --git a/language/duchain/ducontextdata.h b/language/duchain/ducontextdata.h index 1d8e82c1b..feef2217a 100644 --- a/language/duchain/ducontextdata.h +++ b/language/duchain/ducontextdata.h @@ -1,84 +1,85 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2006 Hamish Rodda * * Copyright 2007-2008 David Nolden * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef DUCONTEXTDATA_H #define DUCONTEXTDATA_H #include "duchainbase.h" #include "ducontext.h" #include "duchainpointer.h" #include "declaration.h" #include "use.h" #include #include "localindexeddeclaration.h" #include "localindexedducontext.h" namespace KDevelop{ class DUContext; KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(DUContextData, m_childContexts, LocalIndexedDUContext) KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(DUContextData, m_importers, IndexedDUContext) KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(DUContextData, m_importedContexts, DUContext::Import) KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(DUContextData, m_localDeclarations, LocalIndexedDeclaration) KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(DUContextData, m_uses, Use) ///This class contains data that needs to be stored to disk class KDEVPLATFORMLANGUAGE_EXPORT DUContextData : public DUChainBaseData { public: DUContextData(); ~DUContextData(); DUContextData(const DUContextData& rhs); - DUContext::ContextType m_contextType; + IndexedQualifiedIdentifier m_scopeIdentifier; IndexedDeclaration m_owner; typedef DUContext::Import Import; START_APPENDED_LISTS_BASE(DUContextData, DUChainBaseData); APPENDED_LIST_FIRST(DUContextData, Import, m_importedContexts); APPENDED_LIST(DUContextData, LocalIndexedDUContext, m_childContexts, m_importedContexts); ///@todo Create an additional structure for importing to/from "temporary" contexts and classes in a way that it persists while saving/loading, /// and doesn't require changing a top-contexts data only because a class was derived from. APPENDED_LIST(DUContextData, IndexedDUContext, m_importers, m_childContexts); ///@warning: Whenever m_localDeclarations is read or written, the duchain must be locked APPENDED_LIST(DUContextData, LocalIndexedDeclaration, m_localDeclarations, m_importers); /** * Vector of all uses in this context * Mutable for range synchronization * */ APPENDED_LIST(DUContextData, Use, m_uses, m_localDeclarations); END_APPENDED_LISTS(DUContextData, m_uses); + DUContext::ContextType m_contextType; bool m_inSymbolTable : 1; bool m_anonymousInParent : 1; //Whether this context was added anonymously into the parent. This means that it cannot be found as child-context in the parent. bool m_propagateDeclarations : 1; private: DUContextData& operator=(const DUContextData&) { return *this; } }; } #endif diff --git a/language/duchain/topducontext.cpp b/language/duchain/topducontext.cpp index 9784e2dc1..bcdc2f6cd 100644 --- a/language/duchain/topducontext.cpp +++ b/language/duchain/topducontext.cpp @@ -1,1165 +1,1164 @@ /* This is part of KDevelop Copyright 2006 Hamish Rodda 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. */ #include "topducontext.h" #include "topducontextutils.h" #include #include #include "persistentsymboltable.h" #include "problem.h" #include "declaration.h" #include "duchain.h" #include "duchainlock.h" #include "parsingenvironment.h" #include "duchainpointer.h" #include "declarationid.h" #include "namespacealiasdeclaration.h" #include "aliasdeclaration.h" #include "uses.h" #include "topducontextdata.h" #include "duchainregister.h" #include "topducontextdynamicdata.h" #include "util/debug.h" // #define DEBUG_SEARCH const uint maxApplyAliasesRecursion = 100; namespace KDevelop { Utils::BasicSetRepository* RecursiveImportRepository::repository() { static Utils::BasicSetRepository recursiveImportRepositoryObject("Recursive Imports", &KDevelop::globalItemRepositoryRegistry()); return &recursiveImportRepositoryObject; } ReferencedTopDUContext::ReferencedTopDUContext(TopDUContext* context) : m_topContext(context) { if(m_topContext) DUChain::self()->refCountUp(m_topContext); } ReferencedTopDUContext::ReferencedTopDUContext(const ReferencedTopDUContext& rhs) : m_topContext(rhs.m_topContext) { if(m_topContext) DUChain::self()->refCountUp(m_topContext); } ReferencedTopDUContext::~ReferencedTopDUContext() { if(m_topContext && !DUChain::deleted()) DUChain::self()->refCountDown(m_topContext); } ReferencedTopDUContext& ReferencedTopDUContext::operator=(const ReferencedTopDUContext& rhs) { if(m_topContext == rhs.m_topContext) return *this; if(m_topContext) DUChain::self()->refCountDown(m_topContext); m_topContext = rhs.m_topContext; if(m_topContext) DUChain::self()->refCountUp(m_topContext); return *this; } DEFINE_LIST_MEMBER_HASH(TopDUContextData, m_usedDeclarationIds, DeclarationId) DEFINE_LIST_MEMBER_HASH(TopDUContextData, m_problems, LocalIndexedProblem) REGISTER_DUCHAIN_ITEM(TopDUContext); template void removeFromVector(QVector& vec, const T& t) { for(int a =0; a < vec.size(); ++a) { if(vec[a] == t) { vec.remove(a); removeFromVector(vec, t); return; } } } QMutex importStructureMutex(QMutex::Recursive); //Contains data that is not shared among top-contexts that share their duchain entries class TopDUContextLocalPrivate { public: TopDUContextLocalPrivate (TopDUContext* ctxt, uint index) : m_ctxt(ctxt), m_ownIndex(index), m_inDuChain(false) { m_indexedRecursiveImports.insert(index); } ~TopDUContextLocalPrivate() { //Either we use some other contexts data and have no users, or we own the data and have users that share it. QMutexLocker lock(&importStructureMutex); foreach(const DUContext::Import& import, m_importedContexts) if(DUChain::self()->isInMemory(import.topContextIndex()) && dynamic_cast(import.context(0))) dynamic_cast(import.context(0))->m_local->m_directImporters.remove(m_ctxt); } ///@todo Make all this work consistently together with import-caching //After loading, should rebuild the links void rebuildDynamicImportStructure() { //Currently we do not store the whole data in TopDUContextLocalPrivate, so we reconstruct it from what was stored by DUContext. Q_ASSERT(m_importedContexts.isEmpty()); FOREACH_FUNCTION(const DUContext::Import& import, m_ctxt->d_func()->m_importedContexts) { if(DUChain::self()->isInMemory(import.topContextIndex())) { Q_ASSERT(import.context(0)); TopDUContext* top = import.context(0)->topContext(); Q_ASSERT(top); addImportedContextRecursively(top, false, true); } } FOREACH_FUNCTION(const IndexedDUContext& importer, m_ctxt->d_func()->m_importers) { if(DUChain::self()->isInMemory(importer.topContextIndex())) { Q_ASSERT(importer.context()); TopDUContext* top = importer.context()->topContext(); Q_ASSERT(top); top->m_local->addImportedContextRecursively(m_ctxt, false, true); } } } //Index of this top-context within the duchain //Since the data of top-contexts can be shared among multiple, this can be used to add imports that are local to this top-context. QVector m_importedContexts; // mutable bool m_haveImportStructure : 1; TopDUContext* m_ctxt; QSet m_directImporters; ParsingEnvironmentFilePointer m_file; QExplicitlySharedDataPointer m_ast; uint m_ownIndex; bool m_inDuChain; void clearImportedContextsRecursively() { QMutexLocker lock(&importStructureMutex); // Q_ASSERT(m_recursiveImports.size() == m_indexedRecursiveImports.count()-1); QSet > rebuild; foreach(const DUContext::Import &import, m_importedContexts) { TopDUContext* top = dynamic_cast(import.context(0)); if(top) { top->m_local->m_directImporters.remove(m_ctxt); if(!m_ctxt->usingImportsCache()) { removeImportedContextRecursion(top, top, 1, rebuild); QHash > b = top->m_local->m_recursiveImports; for(RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it) { if(m_recursiveImports.contains(it.key()) && m_recursiveImports[it.key()].second == top) removeImportedContextRecursion(top, it.key(), it->first+1, rebuild); //Remove all contexts that are imported through the context } } } } m_importedContexts.clear(); rebuildImportStructureRecursion(rebuild); Q_ASSERT(m_recursiveImports.isEmpty()); // Q_ASSERT(m_recursiveImports.size() == m_indexedRecursiveImports.count()-1); } //Adds the context to this and all contexts that import this, and manages m_recursiveImports void addImportedContextRecursively(TopDUContext* context, bool temporary, bool local) { QMutexLocker lock(&importStructureMutex); context->m_local->m_directImporters.insert(m_ctxt); if(local) m_importedContexts << DUContext::Import(context, m_ctxt); if(!m_ctxt->usingImportsCache()) { addImportedContextRecursion(context, context, 1, temporary); QHash > b = context->m_local->m_recursiveImports; for(RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it) addImportedContextRecursion(context, it.key(), (*it).first+1, temporary); //Add contexts that were imported earlier into the given one } } //Removes the context from this and all contexts that import this, and manages m_recursiveImports void removeImportedContextRecursively(TopDUContext* context, bool local) { QMutexLocker lock(&importStructureMutex); context->m_local->m_directImporters.remove(m_ctxt); if(local) removeFromVector(m_importedContexts, DUContext::Import(context, m_ctxt)); QSet > rebuild; if(!m_ctxt->usingImportsCache()) { removeImportedContextRecursion(context, context, 1, rebuild); QHash > b = context->m_local->m_recursiveImports; for(RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it) { if(m_recursiveImports.contains(it.key()) && m_recursiveImports[it.key()].second == context) removeImportedContextRecursion(context, it.key(), it->first+1, rebuild); //Remove all contexts that are imported through the context } } rebuildImportStructureRecursion(rebuild); } void removeImportedContextsRecursively(const QList& contexts, bool local) { QMutexLocker lock(&importStructureMutex); QSet > rebuild; foreach(TopDUContext* context, contexts) { context->m_local->m_directImporters.remove(m_ctxt); if(local) removeFromVector(m_importedContexts, DUContext::Import(context, m_ctxt)); if(!m_ctxt->usingImportsCache()) { removeImportedContextRecursion(context, context, 1, rebuild); QHash > b = context->m_local->m_recursiveImports; for(RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it) { if(m_recursiveImports.contains(it.key()) && m_recursiveImports[it.key()].second == context) removeImportedContextRecursion(context, it.key(), it->first+1, rebuild); //Remove all contexts that are imported through the context } } } rebuildImportStructureRecursion(rebuild); } //Has an entry for every single recursively imported file, that contains the shortest path, and the next context on that path to the imported context. //This does not need to be stored to disk, because it is defined implicitly. //What makes this most complicated is the fact that loops are allowed in the import structure. typedef QHash > RecursiveImports; mutable RecursiveImports m_recursiveImports; mutable TopDUContext::IndexedRecursiveImports m_indexedRecursiveImports; private: void addImportedContextRecursion(const TopDUContext* traceNext, const TopDUContext* imported, int depth, bool temporary = false) { if(m_ctxt->usingImportsCache()) return; // if(!m_haveImportStructure) // return; if(imported == m_ctxt) return; const bool computeShortestPaths = false; ///@todo We do not compute the shortest path. Think what's right. // traceNext->m_local->needImportStructure(); // imported->m_local->needImportStructure(); RecursiveImports::iterator it = m_recursiveImports.find(imported); if(it == m_recursiveImports.end()) { //Insert new path to "imported" m_recursiveImports[imported] = qMakePair(depth, traceNext); m_indexedRecursiveImports.insert(imported->indexed()); // Q_ASSERT(m_indexedRecursiveImports.size() == m_recursiveImports.size()+1); Q_ASSERT(traceNext != m_ctxt); }else{ if(!computeShortestPaths) return; if(temporary) //For temporary imports, we don't record the best path. return; //It would be better if we would use the following code, but it creates too much cost in updateImportedContextRecursion when imports are removed again. //Check whether the new way to "imported" is shorter than the stored one if((*it).first > depth) { //Add a shorter path (*it).first = depth; Q_ASSERT(traceNext); (*it).second = traceNext; Q_ASSERT(traceNext == imported || (traceNext->m_local->m_recursiveImports.contains(imported) && traceNext->m_local->m_recursiveImports[imported].first < (*it).first)); }else{ //The imported context is already imported through a same/better path, so we can just stop processing. This saves us from endless recursion. return; } } if(temporary) return; for(QSet::const_iterator it = m_directImporters.constBegin(); it != m_directImporters.constEnd(); ++it) { TopDUContext* top = dynamic_cast(const_cast(*it)); //Avoid detaching, so use const_cast if(top) ///@todo also record this for local imports top->m_local->addImportedContextRecursion(m_ctxt, imported, depth+1); } } void removeImportedContextRecursion(const TopDUContext* traceNext, const TopDUContext* imported, int distance, QSet >& rebuild) { if(m_ctxt->usingImportsCache()) return; if(imported == m_ctxt) return; // if(!m_haveImportStructure) // return; RecursiveImports::iterator it = m_recursiveImports.find(imported); if(it == m_recursiveImports.end()) { //We don't import. Just return, this saves us from endless recursion. return; }else{ //Check whether we have imported "imported" through "traceNext". If not, return. Else find a new trace. if((*it).second == traceNext && (*it).first == distance) { //We need to remove the import through traceNext. Check whether there is another imported context that imports it. m_recursiveImports.erase(it); //In order to prevent problems, we completely remove everything, and re-add it. //Just updating these complex structures is very hard. Q_ASSERT(imported != m_ctxt); m_indexedRecursiveImports.remove(imported->indexed()); // Q_ASSERT(m_indexedRecursiveImports.size() == m_recursiveImports.size()); rebuild.insert(qMakePair(m_ctxt, imported)); //We MUST do this before finding another trace, because else we would create loops for(QSet::const_iterator childIt = m_directImporters.constBegin(); childIt != m_directImporters.constEnd(); ++childIt) { TopDUContext* top = dynamic_cast(const_cast(*childIt)); //Avoid detaching, so use const iterator if(top) top->m_local->removeImportedContextRecursion(m_ctxt, imported, distance+1, rebuild); //Don't use 'it' from here on, it may be invalid } } } } //Updates the trace to 'imported' void rebuildStructure(const TopDUContext* imported); void rebuildImportStructureRecursion(const QSet >& rebuild) { for(QSet >::const_iterator it = rebuild.constBegin(); it != rebuild.constEnd(); ++it) { //for(int a = rebuild.size()-1; a >= 0; --a) { //Find the best imported parent it->first->m_local->rebuildStructure(it->second); } } }; const TopDUContext::IndexedRecursiveImports& TopDUContext::recursiveImportIndices() const { // No lock-check for performance reasons QMutexLocker lock(&importStructureMutex); if(!d_func()->m_importsCache.isEmpty()) return d_func()->m_importsCache; return m_local->m_indexedRecursiveImports; } void TopDUContextData::updateImportCacheRecursion(uint baseIndex, IndexedTopDUContext currentContext, TopDUContext::IndexedRecursiveImports& visited) { if(visited.contains(currentContext.index())) return; Q_ASSERT(currentContext.index()); //The top-context must be in the repository when this is called if(!currentContext.data()) { qCDebug(LANGUAGE) << "importing invalid context"; return; } visited.insert(currentContext.index()); const TopDUContextData* currentData = currentContext.data()->topContext()->d_func(); if(currentData->m_importsCache.contains(baseIndex) || currentData->m_importsCache.isEmpty()) { //If we have a loop or no imports-cache is used, we have to look at each import separately. const KDevelop::DUContext::Import* imports = currentData->m_importedContexts(); uint importsSize = currentData->m_importedContextsSize(); for(uint a = 0; a < importsSize; ++a) { IndexedTopDUContext next(imports[a].topContextIndex()); if(next.isValid()) updateImportCacheRecursion(baseIndex, next, visited); } }else{ //If we don't have a loop with baseIndex, we can safely just merge with the imported importscache visited += currentData->m_importsCache; } } void TopDUContextData::updateImportCacheRecursion(IndexedTopDUContext currentContext, std::set& visited) { if(visited.find(currentContext.index()) != visited.end()) return; Q_ASSERT(currentContext.index()); //The top-context must be in the repository when this is called if(!currentContext.data()) { qCDebug(LANGUAGE) << "importing invalid context"; return; } visited.insert(currentContext.index()); const TopDUContextData* currentData = currentContext.data()->topContext()->d_func(); const KDevelop::DUContext::Import* imports = currentData->m_importedContexts(); uint importsSize = currentData->m_importedContextsSize(); for(uint a = 0; a < importsSize; ++a) { IndexedTopDUContext next(imports[a].topContextIndex()); if(next.isValid()) updateImportCacheRecursion(next, visited); } } void TopDUContext::updateImportsCache() { QMutexLocker lock(&importStructureMutex); const bool use_fully_recursive_import_cache_computation = false; if(use_fully_recursive_import_cache_computation) { std::set visited; TopDUContextData::updateImportCacheRecursion(this, visited); Q_ASSERT(visited.find(ownIndex()) != visited.end()); d_func_dynamic()->m_importsCache = IndexedRecursiveImports(visited); }else{ d_func_dynamic()->m_importsCache = IndexedRecursiveImports(); TopDUContextData::updateImportCacheRecursion(ownIndex(), this, d_func_dynamic()->m_importsCache); } Q_ASSERT(d_func_dynamic()->m_importsCache.contains(IndexedTopDUContext(this))); Q_ASSERT(usingImportsCache()); Q_ASSERT(imports(this, CursorInRevision::invalid())); if(parsingEnvironmentFile()) parsingEnvironmentFile()->setImportsCache(d_func()->m_importsCache); } bool TopDUContext::usingImportsCache() const { return !d_func()->m_importsCache.isEmpty(); } CursorInRevision TopDUContext::importPosition(const DUContext* target) const { ENSURE_CAN_READ DUCHAIN_D(DUContext); Import import(const_cast(target), const_cast(this), CursorInRevision::invalid()); for(unsigned int a = 0; a < d->m_importedContextsSize(); ++a) if(d->m_importedContexts()[a] == import) return d->m_importedContexts()[a].position; return DUContext::importPosition(target); } void TopDUContextLocalPrivate::rebuildStructure(const TopDUContext* imported) { if(m_ctxt == imported) return; for(QVector::const_iterator parentIt = m_importedContexts.constBegin(); parentIt != m_importedContexts.constEnd(); ++parentIt) { TopDUContext* top = dynamic_cast(const_cast(parentIt->context(0))); //To avoid detaching, use const iterator if(top) { // top->m_local->needImportStructure(); if(top == imported) { addImportedContextRecursion(top, imported, 1); }else{ RecursiveImports::const_iterator it2 = top->m_local->m_recursiveImports.constFind(imported); if(it2 != top->m_local->m_recursiveImports.constEnd()) { addImportedContextRecursion(top, imported, (*it2).first + 1); } } } } for(unsigned int a = 0; a < m_ctxt->d_func()->m_importedContextsSize(); ++a) { TopDUContext* top = dynamic_cast(const_cast(m_ctxt->d_func()->m_importedContexts()[a].context(0))); //To avoid detaching, use const iterator if(top) { // top->m_local->needImportStructure(); if(top == imported) { addImportedContextRecursion(top, imported, 1); }else{ RecursiveImports::const_iterator it2 = top->m_local->m_recursiveImports.constFind(imported); if(it2 != top->m_local->m_recursiveImports.constEnd()) { addImportedContextRecursion(top, imported, (*it2).first + 1); } } } } } void TopDUContext::rebuildDynamicImportStructure() { m_local->rebuildDynamicImportStructure(); } void TopDUContext::rebuildDynamicData(DUContext* parent, uint ownIndex) { Q_ASSERT(parent == 0 && ownIndex != 0); m_local->m_ownIndex = ownIndex; DUContext::rebuildDynamicData(parent, 0); } IndexedTopDUContext TopDUContext::indexed() const { return IndexedTopDUContext(m_local->m_ownIndex); } uint TopDUContext::ownIndex() const { return m_local->m_ownIndex; } TopDUContext::TopDUContext(TopDUContextData& data) : DUContext(data), m_local(new TopDUContextLocalPrivate(this, data.m_ownIndex)), m_dynamicData(new TopDUContextDynamicData(this)) { } TopDUContext::TopDUContext(const IndexedString& url, const RangeInRevision& range, ParsingEnvironmentFile* file) : DUContext(*new TopDUContextData(url), range) , m_local(new TopDUContextLocalPrivate(this, DUChain::newTopContextIndex())) , m_dynamicData(new TopDUContextDynamicData(this)) { Q_ASSERT(url.toUrl().isValid() && !url.toUrl().isRelative()); d_func_dynamic()->setClassId(this); setType(Global); DUCHAIN_D_DYNAMIC(TopDUContext); d->m_features = VisibleDeclarationsAndContexts; d->m_ownIndex = m_local->m_ownIndex; setParsingEnvironmentFile(file); setInSymbolTable(true); } QExplicitlySharedDataPointer TopDUContext::parsingEnvironmentFile() const { return m_local->m_file; } TopDUContext::~TopDUContext( ) { m_dynamicData->m_deleting = true; //Clear the AST, so that the 'feature satisfaction' cache is eventually updated clearAst(); if(!isOnDisk()) { //Clear the 'feature satisfaction' cache which is managed in ParsingEnvironmentFile setFeatures(Empty); clearUsedDeclarationIndices(); } deleteChildContextsRecursively(); deleteLocalDeclarations(); m_dynamicData->clear(); } void TopDUContext::deleteSelf() { //We've got to make sure that m_dynamicData and m_local are still valid while all the sub-contexts are destroyed TopDUContextLocalPrivate* local = m_local; TopDUContextDynamicData* dynamicData = m_dynamicData; m_dynamicData->m_deleting = true; delete this; delete local; delete dynamicData; } TopDUContext::Features TopDUContext::features() const { uint ret = d_func()->m_features; if(ast()) ret |= TopDUContext::AST; return (TopDUContext::Features)ret; } void TopDUContext::setFeatures(Features features) { features = (TopDUContext::Features)(features & (~Recursive)); //Remove the "Recursive" flag since that's only for searching features = (TopDUContext::Features)(features & (~ForceUpdateRecursive)); //Remove the update flags features = (TopDUContext::Features)(features & (~AST)); //Remove the AST flag, it's only used while updating d_func_dynamic()->m_features = features; //Replicate features to ParsingEnvironmentFile if(parsingEnvironmentFile()) parsingEnvironmentFile()->setFeatures(this->features()); } void TopDUContext::setAst(QExplicitlySharedDataPointer ast) { ENSURE_CAN_WRITE m_local->m_ast = ast; if(parsingEnvironmentFile()) parsingEnvironmentFile()->setFeatures(features()); } void TopDUContext::setParsingEnvironmentFile(ParsingEnvironmentFile* file) { if(m_local->m_file) //Clear the "feature satisfaction" cache m_local->m_file->setFeatures(Empty); //We do not enforce a duchain lock here, since this is also used while loading a top-context m_local->m_file = QExplicitlySharedDataPointer(file); //Replicate features to ParsingEnvironmentFile if(file) { file->setTopContext(IndexedTopDUContext(ownIndex())); Q_ASSERT(file->indexedTopContext().isValid()); file->setFeatures(d_func()->m_features); file->setImportsCache(d_func()->m_importsCache); } } struct TopDUContext::FindDeclarationsAcceptor { FindDeclarationsAcceptor(const TopDUContext* _top, DeclarationList& _target, const DeclarationChecker& _check, SearchFlags _flags) : top(_top), target(_target), check(_check) { flags = _flags; } bool operator() (const QualifiedIdentifier& id) { #ifdef DEBUG_SEARCH qCDebug(LANGUAGE) << "accepting" << id.toString(); #endif PersistentSymbolTable::Declarations allDecls; //This iterator efficiently filters the visible declarations out of all declarations PersistentSymbolTable::FilteredDeclarationIterator filter; //This is used if filtering is disabled PersistentSymbolTable::Declarations::Iterator unchecked; if(check.flags & DUContext::NoImportsCheck) { allDecls = PersistentSymbolTable::self().getDeclarations(id); unchecked = allDecls.iterator(); } else filter = PersistentSymbolTable::self().getFilteredDeclarations(id, top->recursiveImportIndices()); while(filter || unchecked) { IndexedDeclaration iDecl; if(filter) { iDecl = *filter; ++filter; } else { iDecl = *unchecked; ++unchecked; } Declaration* decl = iDecl.data(); if(!decl) continue; if(!check(decl)) continue; if( ! (flags & DontResolveAliases) && decl->kind() == Declaration::Alias ) { //Apply alias declarations AliasDeclaration* alias = static_cast(decl); if(alias->aliasedDeclaration().isValid()) { decl = alias->aliasedDeclaration().declaration(); } else { qCDebug(LANGUAGE) << "lost aliased declaration"; } } target.append(decl); } check.createVisibleCache = 0; return !top->foundEnough(target, flags); } const TopDUContext* top; DeclarationList& target; const DeclarationChecker& check; QFlags< KDevelop::DUContext::SearchFlag > flags; }; bool TopDUContext::findDeclarationsInternal(const SearchItem::PtrList& identifiers, const CursorInRevision& position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* /*source*/, SearchFlags flags, uint /*depth*/) const { ENSURE_CAN_READ #ifdef DEBUG_SEARCH for (const SearchItem::Ptr& idTree : identifiers) foreach(const QualifiedIdentifier &id, idTree->toList()) qCDebug(LANGUAGE) << "searching item" << id.toString(); #endif DeclarationChecker check(this, position, dataType, flags); FindDeclarationsAcceptor storer(this, ret, check, flags); ///The actual scopes are found within applyAliases, and each complete qualified identifier is given to FindDeclarationsAcceptor. ///That stores the found declaration to the output. applyAliases(identifiers, storer, position, false); return true; } //This is used to prevent endless recursion due to "using namespace .." declarations, by storing all imports that are already being used. struct TopDUContext::ApplyAliasesBuddyInfo { ApplyAliasesBuddyInfo(uint importChainType, ApplyAliasesBuddyInfo* predecessor, IndexedQualifiedIdentifier importId) : m_importChainType(importChainType), m_predecessor(predecessor), m_importId(importId) { if(m_predecessor && m_predecessor->m_importChainType != importChainType) m_predecessor = 0; } //May also be called when this is zero. bool alreadyImporting(IndexedQualifiedIdentifier id) { ApplyAliasesBuddyInfo* current = this; while(current) { if(current->m_importId == id) return true; current = current->m_predecessor; } return false; } uint m_importChainType; ApplyAliasesBuddyInfo* m_predecessor; IndexedQualifiedIdentifier m_importId; }; ///@todo Implement a cache so at least the global import checks don't need to be done repeatedly. The cache should be thread-local, using DUChainPointer for the hashed items, and when an item was deleted, it should be discarded template bool TopDUContext::applyAliases( const QualifiedIdentifier& previous, const SearchItem::Ptr& identifier, Acceptor& accept, const CursorInRevision& position, bool canBeNamespace, ApplyAliasesBuddyInfo* buddy, uint recursionDepth ) const { if(recursionDepth > maxApplyAliasesRecursion) { QList searches = identifier->toList(); QualifiedIdentifier id; if(!searches.isEmpty()) id = searches.first(); qCDebug(LANGUAGE) << "maximum apply-aliases recursion reached while searching" << id; } bool foundAlias = false; QualifiedIdentifier id(previous); id.push(identifier->identifier); if(!id.inRepository()) return true; //If the qualified identifier is not in the identifier repository, it cannot be registered anywhere, so there's nothing we need to do if( !identifier->next.isEmpty() || canBeNamespace ) { //If it cannot be a namespace, the last part of the scope will be ignored //Search for namespace-aliases, by using globalAliasIdentifier, which is inserted into the symbol-table by NamespaceAliasDeclaration QualifiedIdentifier aliasId(id); aliasId.push(globalIndexedAliasIdentifier()); #ifdef DEBUG_SEARCH qCDebug(LANGUAGE) << "checking" << id.toString(); #endif if(aliasId.inRepository()) { //This iterator efficiently filters the visible declarations out of all declarations PersistentSymbolTable::FilteredDeclarationIterator filter = PersistentSymbolTable::self().getFilteredDeclarations(aliasId, recursiveImportIndices()); if(filter) { DeclarationChecker check(this, position, AbstractType::Ptr(), NoSearchFlags, 0); //The first part of the identifier has been found as a namespace-alias. //In c++, we only need the first alias. However, just to be correct, follow them all for now. for(; filter; ++filter) { Declaration* aliasDecl = filter->data(); if(!aliasDecl) continue; if(!check(aliasDecl)) continue; if(aliasDecl->kind() != Declaration::NamespaceAlias) continue; if(foundAlias) break; Q_ASSERT(dynamic_cast(aliasDecl)); NamespaceAliasDeclaration* alias = static_cast(aliasDecl); foundAlias = true; QualifiedIdentifier importIdentifier = alias->importIdentifier(); if(importIdentifier.isEmpty()) { qCDebug(LANGUAGE) << "found empty import"; continue; } if(buddy->alreadyImporting( importIdentifier )) continue; //This import has already been applied to this search ApplyAliasesBuddyInfo info(1, buddy, importIdentifier); if(identifier->next.isEmpty()) { //Just insert the aliased namespace identifier if(!accept(importIdentifier)) return false; }else{ //Create an identifiers where namespace-alias part is replaced with the alias target for (const SearchItem::Ptr& item : identifier->next) if(!applyAliases(importIdentifier, item, accept, position, canBeNamespace, &info, recursionDepth+1)) return false; } } } } } if(!foundAlias) { //If we haven't found an alias, put the current versions into the result list. Additionally we will compute the identifiers transformed through "using". if(identifier->next.isEmpty()) { if(!accept(id)) //We're at the end of a qualified identifier, accept it return false; } else { for (const SearchItem::Ptr& next : identifier->next) if(!applyAliases(id, next, accept, position, canBeNamespace, 0, recursionDepth+1)) return false; } } /*if( !prefix.explicitlyGlobal() || !prefix.isEmpty() ) {*/ ///@todo check iso c++ if using-directives should be respected on top-level when explicitly global ///@todo this is bad for a very big repository(the chains should be walked for the top-context instead) //Find all namespace-imports at given scope { QualifiedIdentifier importId(previous); importId.push(globalIndexedImportIdentifier()); #ifdef DEBUG_SEARCH // qCDebug(LANGUAGE) << "checking imports in" << (backPointer ? id.toString() : QStringLiteral("global")); #endif if(importId.inRepository()) { //This iterator efficiently filters the visible declarations out of all declarations PersistentSymbolTable::FilteredDeclarationIterator filter = PersistentSymbolTable::self().getFilteredDeclarations(importId, recursiveImportIndices()); if(filter) { DeclarationChecker check(this, position, AbstractType::Ptr(), NoSearchFlags, 0); for(; filter; ++filter) { Declaration* importDecl = filter->data(); if(!importDecl) continue; //We must never break or return from this loop, because else we might be creating a bad cache if(!check(importDecl)) continue; //Search for the identifier with the import-identifier prepended Q_ASSERT(dynamic_cast(importDecl)); NamespaceAliasDeclaration* alias = static_cast(importDecl); #ifdef DEBUG_SEARCH qCDebug(LANGUAGE) << "found import of" << alias->importIdentifier().toString(); #endif QualifiedIdentifier importIdentifier = alias->importIdentifier(); if(importIdentifier.isEmpty()) { qCDebug(LANGUAGE) << "found empty import"; continue; } if(buddy->alreadyImporting( importIdentifier )) continue; //This import has already been applied to this search ApplyAliasesBuddyInfo info(2, buddy, importIdentifier); if(previous != importIdentifier) if(!applyAliases(importIdentifier, identifier, accept, importDecl->topContext() == this ? importDecl->range().start : position, canBeNamespace, &info, recursionDepth+1)) return false; } } } } return true; } template void TopDUContext::applyAliases( const SearchItem::PtrList& identifiers, Acceptor& acceptor, const CursorInRevision& position, bool canBeNamespace ) const { QualifiedIdentifier emptyId; for (const SearchItem::Ptr& item : identifiers) applyAliases(emptyId, item, acceptor, position, canBeNamespace, 0, 0); } TopDUContext * TopDUContext::topContext() const { return const_cast(this); } bool TopDUContext::deleting() const { - ///@todo remove d_func()->m_deleting, not used any more return m_dynamicData->m_deleting; } QList TopDUContext::problems() const { ENSURE_CAN_READ const auto data = d_func(); QList ret; ret.reserve(data->m_problemsSize()); for (uint i = 0; i < data->m_problemsSize(); ++i) { ret << ProblemPointer(data->m_problems()[i].data(this)); } return ret; } void TopDUContext::setProblems(const QList& problems) { ENSURE_CAN_WRITE clearProblems(); for (const auto& problem : problems) { addProblem(problem); } } void TopDUContext::addProblem(const ProblemPointer& problem) { ENSURE_CAN_WRITE Q_ASSERT(problem); auto data = d_func_dynamic(); // store for indexing LocalIndexedProblem indexedProblem(problem, this); Q_ASSERT(indexedProblem.isValid()); data->m_problemsList().append(indexedProblem); Q_ASSERT(indexedProblem.data(this)); } void TopDUContext::clearProblems() { ENSURE_CAN_WRITE d_func_dynamic()->m_problemsList().clear(); m_dynamicData->clearProblems(); } QVector TopDUContext::importers() const { ENSURE_CAN_READ return QVector::fromList( m_local->m_directImporters.toList() ); } QList TopDUContext::loadedImporters() const { ENSURE_CAN_READ return m_local->m_directImporters.toList(); } QVector TopDUContext::importedParentContexts() const { ENSURE_CAN_READ return DUContext::importedParentContexts(); } bool TopDUContext::imports(const DUContext * origin, const CursorInRevision& position) const { return importsPrivate(origin, position); } bool TopDUContext::importsPrivate(const DUContext * origin, const CursorInRevision& position) const { Q_UNUSED(position); if( const TopDUContext* top = dynamic_cast(origin) ) { QMutexLocker lock(&importStructureMutex); bool ret = recursiveImportIndices().contains(IndexedTopDUContext(const_cast(top))); if(top == this) Q_ASSERT(ret); return ret; } else { //Cannot import a non top-context return false; } } void TopDUContext::clearImportedParentContexts() { if(usingImportsCache()) { d_func_dynamic()->m_importsCache = IndexedRecursiveImports(); d_func_dynamic()->m_importsCache.insert(IndexedTopDUContext(this)); } DUContext::clearImportedParentContexts(); m_local->clearImportedContextsRecursively(); Q_ASSERT(m_local->m_recursiveImports.count() == 0); Q_ASSERT(m_local->m_indexedRecursiveImports.count() == 1); Q_ASSERT(imports(this, CursorInRevision::invalid())); } void TopDUContext::addImportedParentContext(DUContext* context, const CursorInRevision& position, bool anonymous, bool temporary) { if(context == this) return; if(!dynamic_cast(context)) { //We cannot do this, because of the extended way we treat top-context imports. qCDebug(LANGUAGE) << "tried to import a non top-context into a top-context. This is not possible."; return; } //Always make the contexts anonymous, because we care about importers in TopDUContextLocalPrivate DUContext::addImportedParentContext(context, position, anonymous, temporary); m_local->addImportedContextRecursively(static_cast(context), temporary, true); } void TopDUContext::removeImportedParentContext(DUContext* context) { DUContext::removeImportedParentContext(context); m_local->removeImportedContextRecursively(static_cast(context), true); } void TopDUContext::addImportedParentContexts(const QList >& contexts, bool temporary) { typedef QPair Pair; foreach(const Pair &pair, contexts) addImportedParentContext(pair.first, pair.second, false, temporary); } void TopDUContext::removeImportedParentContexts(const QList& contexts) { foreach(TopDUContext* context, contexts) DUContext::removeImportedParentContext(context); m_local->removeImportedContextsRecursively(contexts, true); } /// Returns true if this object is registered in the du-chain. If it is not, all sub-objects(context, declarations, etc.) bool TopDUContext::inDUChain() const { return m_local->m_inDuChain; } /// This flag is only used by DUChain, never change it from outside. void TopDUContext::setInDuChain(bool b) { m_local->m_inDuChain = b; } bool TopDUContext::isOnDisk() const { ///@todo Change this to releasingToDisk, and only enable it while saving a top-context to disk. return m_dynamicData->isOnDisk(); } void TopDUContext::clearUsedDeclarationIndices() { ENSURE_CAN_WRITE for(unsigned int a = 0; a < d_func()->m_usedDeclarationIdsSize(); ++a) DUChain::uses()->removeUse(d_func()->m_usedDeclarationIds()[a], this); d_func_dynamic()->m_usedDeclarationIdsList().clear(); } void TopDUContext::deleteUsesRecursively() { clearUsedDeclarationIndices(); KDevelop::DUContext::deleteUsesRecursively(); } Declaration* TopDUContext::usedDeclarationForIndex(unsigned int declarationIndex) const { ENSURE_CAN_READ if(declarationIndex & (1<<31)) { //We use the highest bit to mark direct indices into the local declarations declarationIndex &= (0xffffffff - (1<<31)); //unset the highest bit return m_dynamicData->getDeclarationForIndex(declarationIndex); }else if(declarationIndex < d_func()->m_usedDeclarationIdsSize()) return d_func()->m_usedDeclarationIds()[declarationIndex].getDeclaration(this); else return 0; } int TopDUContext::indexForUsedDeclaration(Declaration* declaration, bool create) { if(create) { ENSURE_CAN_WRITE }else{ ENSURE_CAN_READ } if(!declaration) { return std::numeric_limits::max(); } if(declaration->topContext() == this && !declaration->inSymbolTable() && !m_dynamicData->isTemporaryDeclarationIndex(declaration->ownIndex())) { uint index = declaration->ownIndex(); Q_ASSERT(!(index & (1<<31))); return (int)(index | (1<<31)); //We don't put context-local declarations into the list, that's a waste. We just use the mark them with the highest bit. } DeclarationId id(declaration->id()); int index = -1; uint size = d_func()->m_usedDeclarationIdsSize(); const DeclarationId* ids = d_func()->m_usedDeclarationIds(); ///@todo Make m_usedDeclarationIds sorted, and find the decl. using binary search for(unsigned int a = 0; a < size; ++a) if(ids[a] == id) { index = a; break; } if(index != -1) return index; if(!create) return std::numeric_limits::max(); d_func_dynamic()->m_usedDeclarationIdsList().append(id); if(declaration->topContext() != this) DUChain::uses()->addUse(id, this); return d_func()->m_usedDeclarationIdsSize()-1; } QList allUses(TopDUContext* context, Declaration* declaration, bool noEmptyRanges) { QList ret; int declarationIndex = context->indexForUsedDeclaration(declaration, false); if(declarationIndex == std::numeric_limits::max()) return ret; return allUses(context, declarationIndex, noEmptyRanges); } QExplicitlySharedDataPointer TopDUContext::ast() const { return m_local->m_ast; } void TopDUContext::clearAst() { setAst(QExplicitlySharedDataPointer(0)); } IndexedString TopDUContext::url() const { return d_func()->m_url; } } diff --git a/language/duchain/topducontext.h b/language/duchain/topducontext.h index 347924c11..2e5016472 100644 --- a/language/duchain/topducontext.h +++ b/language/duchain/topducontext.h @@ -1,376 +1,376 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda 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 KDEVPLATFORM_TOPDUCONTEXT_H #define KDEVPLATFORM_TOPDUCONTEXT_H #include "ducontext.h" #include #include template< class T > class QExplicitlySharedDataPointer; namespace KDevelop { class IAstContainer; class QualifiedIdentifier; class DUChain; class ParsingEnvironmentFile; class TopDUContextData; class TopDUContextLocalPrivate; class IndexedTopDUContext; // class TopDUContextDynamicData; class Problem; class DeclarationChecker; class TopDUContext; struct KDEVPLATFORMLANGUAGE_EXPORT RecursiveImportRepository { static Utils::BasicSetRepository* repository(); }; ///Maps an imported top-context to a pair: ///1. The distance to the top-context, and 2. The next step towards the top-context ///in the chain. typedef QHash > RecursiveImports; typedef DUChainPointer TopDUContextPointer; typedef QExplicitlySharedDataPointer ProblemPointer; ///KDevelop can unload unused top-context at any time. To prevent unloading, ///keep a ReferencedTopDUContext. class KDEVPLATFORMLANGUAGE_EXPORT ReferencedTopDUContext { public: ReferencedTopDUContext(TopDUContext* context = 0); ReferencedTopDUContext(const ReferencedTopDUContext& rhs); ~ReferencedTopDUContext(); ReferencedTopDUContext& operator=(const ReferencedTopDUContext& rhs); inline TopDUContext* data() const { return m_topContext; } inline operator TopDUContext*() const { return m_topContext; } inline bool operator==(const ReferencedTopDUContext& rhs) const { return m_topContext == rhs.m_topContext; } inline bool operator!=(const ReferencedTopDUContext& rhs) const { return m_topContext != rhs.m_topContext; } inline TopDUContext* operator->() const { return m_topContext; } inline uint hash() const { return (uint)(((quint64)m_topContext) * 37); } private: TopDUContext* m_topContext; }; /** * The top context in a definition-use chain for one source file. * * Implements SymbolTable lookups and locking for the chain. * * Contexts and Classes can only be found through TopDUContext if they are in the symbol table. * @see DUContext::setInSymbolTable, Declaration::setInSymbolTable * * \todo move the registration with DUChain here * * @warning Do not delete top-contexts directly, use DUChain::removeDocumentChain instead. */ class KDEVPLATFORMLANGUAGE_EXPORT TopDUContext : public DUContext { public: explicit TopDUContext(const IndexedString& url, const RangeInRevision& range, ParsingEnvironmentFile* file = 0); explicit TopDUContext(TopDUContextData& data); TopDUContext* topContext() const override; ///Returns an indexed representation of this top-context. Indexed representations stay valid even if the top-context is unloaded. IndexedTopDUContext indexed() const; uint ownIndex() const; IndexedString url() const override; /** * @see ParsingEnvironmentFile * May return zero if no file was set. * */ QExplicitlySharedDataPointer parsingEnvironmentFile() const; /// Returns true if this object is being deleted, otherwise false. bool deleting() const; /// Returns true if this object is registered in the du-chain. If it is not, all sub-objects(context, declarations, etc.) can be changed virtual bool inDUChain() const override; /// This flag is only used by DUChain, never change it from outside. void setInDuChain(bool); /// Whether this top-context has a stored version on disk bool isOnDisk() const; /** * Returns a list of all problems encountered while parsing this top-context. * Does not include the problems of imported contexts. * */ QList problems() const; /** * Add a parsing-problem to this context. * * \note you must be holding a write lock when you access this function. * */ void addProblem(const ProblemPointer& problem); /** * Clear the list of problems * * \note you must be holding a write lock when you access this function. */ void clearProblems(); /** * Set the list of problems, replacing all existing ones. * * \note you must be holding a write lock when you access this function. */ void setProblems(const QList& pointers); /** * Determine if this chain imports another chain recursively. * * This uses the imports-cache for speedup if it is available, thus it is not necessarily 100% correct * if the cache is not up-to-date. * * \note you must be holding a read but not a write chain lock when you access this function. */ virtual bool imports(const DUContext* origin, const CursorInRevision& position) const override; enum { Identity = 4 }; - enum Features { + enum Features : quint16 { ///Top-context features standard that can be requested from the duchain, and that are stored in the features() member. Empty = 0, //Only the top-context structure (imports etc.) is built, but no declarations and no contexts SimplifiedVisibleDeclarationsAndContexts = 2, //The top-context should only contain publically simplified accessible declarations and contexts, without doing type look-up, //without extended information like function-argument declarations, etc., imported contexts can be parsed with 'Empty' features //This flag essentially leads to a ctags-like processing level. VisibleDeclarationsAndContexts = SimplifiedVisibleDeclarationsAndContexts + 4, //Default: The top-context should only contain publically accessible declarations and contexts AllDeclarationsAndContexts = VisibleDeclarationsAndContexts + 8, //The top-context should also contain non-public declarations and contexts, but no uses AllDeclarationsContextsAndUses = 16 + AllDeclarationsAndContexts, //The top-context should contain uses and all declarations + contexts AST = 32, //Signalizes that the ast() should be filled AllDeclarationsContextsUsesAndAST = AST | AllDeclarationsContextsAndUses, //Convenience flag, combining AST and AllDeclarationsContextsAndUses ///Additional update-flags that have a special meaning during updating, but are not set stored into a top-context Recursive = 64, //Request the given features on all recursively imported contexts. Only the features are applied recursively (including AST) ForceUpdate = 128, //Enforce updating the top-context ForceUpdateRecursive = ForceUpdate | 256, //Enforce updating the top-context and all its imports ///You can define own language-dependent features behind this flag LastFeature = 512 }; ///Returns the currently active features of this top-context. The features will include AST if ast() is valid. Features features() const; ///Set the features of this top-context. These features are ignored: AST, ForceUpdate, and ForceUpdateRecursive. void setFeatures(Features); /** * Retrieves or creates a local index that is to be used for referencing the given @param declaration * in local uses. Also registers this context as a user of the declaration. * @param create If this is false, only already registered indices will be returned. * If the declaration is not registered, std::numeric_limits::max() is returned * * The duchain must be write-locked if create is true, else it must at least be read-locked. * */ int indexForUsedDeclaration(Declaration* declaration, bool create = true); /** * Tries to retrieve the used declaration @param declarationIndex * @param context must be the context where the use happened * */ Declaration* usedDeclarationForIndex(unsigned int declarationIndex) const; /** * You can use this before you rebuild all uses. This does not affect any uses directly, * it only invalidates the mapping of declarationIndices to Declarations. * * usedDeclarationForIndex(..) must not be called until the use has gotten a new index through * indexForUsedDeclaration(..). * */ void clearUsedDeclarationIndices(); /** * Recursively deletes all contained uses, declaration-indices, etc. */ virtual void deleteUsesRecursively() override; /** * Returns the AST Container, that contains the AST created during parsing. * This is only created if you request the AST feature for parsing. * It may be discarded at any time. Every update without the AST feature will discard it. * The actual contents is language-specific. * * @todo Figure out logic to get rid of AST when it is not needed/useful */ QExplicitlySharedDataPointer ast() const; /** * Sets the AST Container. */ void setAst(QExplicitlySharedDataPointer ast); /** * Utility function to clear the AST Container */ void clearAst(); ///@param temporary If this is true, importers of this context will not be notified of the new imports. This greatly increases performance while removing the context, ///but creates in inconsistent import-structure. Therefore it is only suitable for temporary imports. These imports will not be visible from contexts that import this one. ///When this top-context does not own its private data, the import is added locally only to this context, not into the shared data. virtual void addImportedParentContext(DUContext* context, const CursorInRevision& position = CursorInRevision(), bool anonymous=false, bool temporary=false) override; ///Use this for mass-adding of imported contexts, it is faster than adding them individually. ///@param temporary If this is true, importers of this context will not be notified of the new imports. This greatly increases performance while removing the context, ///but creates in inconsistent import-structure. Therefore it is only suitable for temporary imports. These imports will not be visible from contexts that import this one. ///When this top-context does not own its private data, the import is added locally only to this context, not into the shared data. virtual void addImportedParentContexts(const QList >& contexts, bool temporary=false); ///When this top-context does not own its private data, the import is removed locally only from this context, not from the shared data. virtual void removeImportedParentContext(DUContext* context) override; ///Use this for mass-removing of imported contexts, it is faster than removing them individually. ///When this top-context does not own its private data, the import is removed locally only from this context, not from the shared data. virtual void removeImportedParentContexts(const QList& contexts); ///When this top-context does not own its private data, only the local imports of this context are removed, not those from the shared data. virtual void clearImportedParentContexts() override; typedef Utils::StorableSet IndexedRecursiveImports; virtual QVector importedParentContexts() const override; virtual QVector importers() const override; ///Returns all currently loade importers virtual QList loadedImporters() const; virtual CursorInRevision importPosition(const DUContext* target) const override; ///Returns the set of all recursively imported top-contexts. If import-caching is used, this returns the cached set. ///The list also contains this context itself. This set is used to determine declaration-visibility from within this top-context. const IndexedRecursiveImports& recursiveImportIndices() const; /** * Updates the cache of recursive imports. When you call this, from that moment on the set returned by recursiveImportIndices() is fixed, until * you call it again to update them. If your language has a very complex often-changing import-structure, * like for example in the case of C++, it is recommended to call this during while parsing, instead of using * the expensive builtin implicit mechanism. * Note that if you use caching, you _must_ call this before you see any visibility-effect after adding imports. * * Using import-caching has another big advantage: A top-context can be loaded without loading all its imports. * * Note: This is relatively expensive since it requires loading all imported contexts. * * When this is called, the top-context must already be registered in the duchain. */ void updateImportsCache(); bool usingImportsCache() const; virtual bool findDeclarationsInternal(const SearchItem::PtrList& identifiers, const CursorInRevision& position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source, SearchFlags flags, uint depth) const override; protected: void setParsingEnvironmentFile(ParsingEnvironmentFile*); /** * Does the same as DUContext::updateAliases, except that it uses the symbol-store, and processes the whole identifier. * @param canBeNamespace whether the searched identifier may be a namespace. * If this is true, namespace-aliasing is applied to the last elements of the identifiers. * */ template void applyAliases( const SearchItem::PtrList& identifiers, Acceptor& accept, const CursorInRevision& position, bool canBeNamespace ) const; protected: virtual ~TopDUContext(); void clearFeaturesSatisfied(); void rebuildDynamicData(DUContext* parent, uint ownIndex) override; //Must be called after all imported top-contexts were loaded into the du-chain void rebuildDynamicImportStructure(); struct AliasChainElement; struct FindDeclarationsAcceptor; struct DeclarationChecker; struct ApplyAliasesBuddyInfo; template bool applyAliases( const QualifiedIdentifier& previous, const SearchItem::Ptr& identifier, Acceptor& acceptor, const CursorInRevision& position, bool canBeNamespace, ApplyAliasesBuddyInfo* buddy, uint recursionDepth ) const; //Same as imports, without the slow access-check, for internal usage bool importsPrivate(const DUContext * origin, const CursorInRevision& position) const; DUCHAIN_DECLARE_DATA(TopDUContext) ///Called by DUChain::removeDocumentChain to destroy this top-context. void deleteSelf(); //Most of these classes need access to m_dynamicData friend class DUChain; friend class DUChainPrivate; friend class TopDUContextData; friend class TopDUContextLocalPrivate; friend class TopDUContextDynamicData; friend class Declaration; friend class DUContext; friend class Problem; friend class IndexedDeclaration; friend class IndexedDUContext; friend class LocalIndexedDeclaration; friend class LocalIndexedDUContext; friend class LocalIndexedProblem; friend class DeclarationId; friend class ParsingEnvironmentFile; TopDUContextLocalPrivate* m_local; class TopDUContextDynamicData* m_dynamicData; }; /** * Returns all uses of the given declaration within this top-context and all sub-contexts * */ KDEVPLATFORMLANGUAGE_EXPORT QList allUses(TopDUContext* context, Declaration* declaration, bool noEmptyRanges = false); inline uint qHash(const ReferencedTopDUContext& ctx) { return ctx.hash(); } } Q_DECLARE_METATYPE(KDevelop::ReferencedTopDUContext) #endif // KDEVPLATFORM_TOPDUCONTEXT_H diff --git a/language/duchain/topducontextdata.h b/language/duchain/topducontextdata.h index 55d924659..c601a67f5 100644 --- a/language/duchain/topducontextdata.h +++ b/language/duchain/topducontextdata.h @@ -1,92 +1,88 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2008 David Nolden * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef KDEVPLATFORM_TOPDUCONTEXTDATA_H #define KDEVPLATFORM_TOPDUCONTEXTDATA_H #include "ducontextdata.h" #include "topducontext.h" #include "declarationid.h" #include "problem.h" #include namespace KDevelop { KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(TopDUContextData, m_usedDeclarationIds, DeclarationId) KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(TopDUContextData, m_problems, LocalIndexedProblem) class KDEVPLATFORMLANGUAGE_EXPORT TopDUContextData : public DUContextData { public: explicit TopDUContextData(IndexedString url) : DUContextData() - , m_deleting(false) , m_url(url) , m_ownIndex(0) , m_currentUsedDeclarationIndex(0) { initializeAppendedLists(); } TopDUContextData(const TopDUContextData& rhs) : DUContextData(rhs) - , m_deleting(false) { initializeAppendedLists(); copyListsFrom(rhs); m_features = rhs.m_features; m_url = rhs.m_url; m_currentUsedDeclarationIndex = rhs.m_currentUsedDeclarationIndex; m_ownIndex = rhs.m_ownIndex; m_importsCache = rhs.m_importsCache; } ~TopDUContextData() { freeAppendedLists(); } TopDUContext::Features m_features; - bool m_deleting : 1; ///@todo remove - IndexedString m_url; uint m_ownIndex; ///If this is not empty, it means that the cache is used instead of the implicit structure. TopDUContext::IndexedRecursiveImports m_importsCache; ///Is used to count up the used declarations while building uses uint m_currentUsedDeclarationIndex; START_APPENDED_LISTS_BASE(TopDUContextData, DUContextData); ///Maps a declarationIndex to a DeclarationId, which is used when the entry in m_usedDeclaration is zero. APPENDED_LIST_FIRST(TopDUContextData, DeclarationId, m_usedDeclarationIds); APPENDED_LIST(TopDUContextData, LocalIndexedProblem, m_problems, m_usedDeclarationIds); END_APPENDED_LISTS(TopDUContextData, m_problems); private: static void updateImportCacheRecursion(IndexedTopDUContext currentContext, std::set& visited); static void updateImportCacheRecursion(uint baseIndex, IndexedTopDUContext currentContext, TopDUContext::IndexedRecursiveImports& imports); friend class TopDUContext; }; } #endif diff --git a/language/duchain/types/abstracttype.cpp b/language/duchain/types/abstracttype.cpp index eab5ad05c..c764fc6ec 100644 --- a/language/duchain/types/abstracttype.cpp +++ b/language/duchain/types/abstracttype.cpp @@ -1,150 +1,150 @@ /* This file is part of KDevelop Copyright 2006 Roberto Raggi Copyright 2006-2008 Hamish Rodda Copyright 2007-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 "abstracttype.h" #include "typesystemdata.h" #include "typeregister.h" #include "typesystem.h" #include "typerepository.h" #include "util/debug.h" namespace KDevelop { //REGISTER_TYPE(AbstractType); void AbstractType::makeDynamic() { if(d_ptr->m_dynamic) return; AbstractType::Ptr newType(clone()); //While cloning, all the data is cloned as well. So we use that mechanism and steal the cloned data. Q_ASSERT(newType->equals(this)); AbstractTypeData* oldData = d_ptr; d_ptr = newType->d_ptr; newType->d_ptr = oldData; Q_ASSERT(d_ptr->m_dynamic); } AbstractType::AbstractType( AbstractTypeData& dd ) : d_ptr(&dd) { } -quint64 AbstractType::modifiers() const +quint32 AbstractType::modifiers() const { return d_func()->m_modifiers; } -void AbstractType::setModifiers(quint64 modifiers) +void AbstractType::setModifiers(quint32 modifiers) { d_func_dynamic()->m_modifiers = modifiers; } AbstractType::AbstractType() : d_ptr(&createData()) { } AbstractType::~AbstractType() { if(!d_ptr->inRepository) { TypeSystem::self().callDestructor(d_ptr); delete[] (char*)d_ptr; } } void AbstractType::accept(TypeVisitor *v) const { if (v->preVisit (this)) this->accept0 (v); v->postVisit (this); } void AbstractType::acceptType(AbstractType::Ptr type, TypeVisitor *v) { if (! type) return; type->accept (v); } AbstractType::WhichType AbstractType::whichType() const { return TypeAbstract; } void AbstractType::exchangeTypes( TypeExchanger* /*exchanger */) { } IndexedType AbstractType::indexed() const { return IndexedType(TypeRepository::indexForType(AbstractType::Ptr(const_cast(this)))); } bool AbstractType::equals(const AbstractType* rhs) const { //qCDebug(LANGUAGE) << this << rhs << modifiers() << rhs->modifiers(); return d_func()->typeClassId == rhs->d_func()->typeClassId && modifiers() == rhs->modifiers(); } uint AbstractType::hash() const { return KDevHash() << d_func()->typeClassId << d_func()->m_modifiers; } QString AbstractType::toString() const { return toString(false); } QString AbstractType::toString(bool spaceOnLeft) const { // TODO complete if(!spaceOnLeft) { if(modifiers() & ConstModifier) { if(modifiers() & VolatileModifier) { return "const volatile "; }else{ return "const "; } }else{ if(modifiers() & VolatileModifier) return "volatile "; else return QString(); } }else{ if(modifiers() & ConstModifier) { if(modifiers() & VolatileModifier) { return " const volatile"; }else{ return " const"; } }else{ if(modifiers() & VolatileModifier) return " volatile"; else return QString(); } } } } diff --git a/language/duchain/types/abstracttype.h b/language/duchain/types/abstracttype.h index a530963e0..8c75a9d8e 100644 --- a/language/duchain/types/abstracttype.h +++ b/language/duchain/types/abstracttype.h @@ -1,307 +1,309 @@ /* This file is part of KDevelop Copyright 2006 Roberto Raggi Copyright 2006-2008 Hamish Rodda Copyright 2007-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_ABSTRACTTYPE_H #define KDEVPLATFORM_ABSTRACTTYPE_H #include #include "typepointer.h" #include namespace KDevelop { class AbstractTypeData; class IndexedType; class TypeVisitor; class TypeExchanger; /// This macro is used to declare type-specific data-access functions within subclasses of AbstractType #define TYPE_DECLARE_DATA(Class) \ inline Class##Data* d_func_dynamic() { makeDynamic(); return reinterpret_cast(d_ptr); } \ inline const Class##Data* d_func() const { return reinterpret_cast(d_ptr); } /// This function creates a local variable named 'd' pointing to the data type (as shortcut) #define TYPE_D(Class) const Class##Data * const d = d_func() #define TYPE_D_DYNAMIC(Class) Class##Data * const d = d_func_dynamic() /** * \brief Base class for all types. * * The AbstractType class is a base class from which all types derive. It features: * - mechanisms for visiting types * - toString() feature * - equivalence feature * - cloning of types, and * - hashing and indexing * - efficient, persistent, and reference-counted storage of types using IndexedType * * Type classes are created in a way that allows storing them in memory or on disk * efficiently. They are classes which can store arbitrary lists immediately after their * private data structures in memory (thus enabling them to be mmapped or memcopied), * or being "dynamic" where you use exactly the same class and same access functions, * but the list data is stored in a temporary KDevVarLengthArray from a central repository, * until we save it back to the static memory-region again. * * When creating an own (sub-) type, you must: * - Override equals(..), hash(). * - The functions should _fully_ distinguish all types, * in regard to all stored information, and regarding their identity. * - This can be skipped if you're overriding a base-type which already incorporates * all of your own types status within its equals/hash functions (eg. you don't add own data). * - Implement a copy-constructor in which you copy the data from the source using copyData() * - Override the clone() function in which you use the copy-constructor to clone the type * - Add an enumerator "Identity" that contains an arbitrary unique identity value of the type * - Add a typedef "BaseType" that specifies the base type, which must be a type that also follows these rules * - Register your type in a source-file using REGISTER_TYPE(..), @see typeregister.h * - Add a typedef "Data", that contains the actual data of the type using the mechanisms described in appendedlist.h. * - That data type must follow the same inheritance chain as the type itself, so it must be based on BaseType::Data. * @see AbstractTypeData * - Use createData() to create the data-object in a constructor (which you then reach to the parent constructor) * - Use TYPE_DECLARE_DATA(YourType) to declare the data access functions d_func and d_func_dynamic, * and then use d_func()->.. and d_func_dynamic()->.. to access your type data * - Create a constructor that only takes a reference to the type data, and passes it to the parent type * * Every type can have only one other type as base-type, * but it can have additional base-classes that are not a direct part of the type-system(@see IdentifiedType). * * \sa appendedlist.h */ class KDEVPLATFORMLANGUAGE_EXPORT AbstractType : public QSharedData { public: typedef TypePtr Ptr; /** * An enumeration of common modifiers for data types. * If you have any language-specific modifiers that don't belong here, * you can add them at/after LanguageSpecificModifier * @warning Think twice what information you store into the type-system. * The type-system should store information that is shared among many declarations, * and attributes of specific Declarations like public/private should be stored in * the Declarations themselves, not in the type-system. */ - enum CommonModifiers { + enum CommonModifiers : quint32 { NoModifiers = 0, + ConstModifier = 1 << 0, VolatileModifier = 1 << 1, TransientModifier = 1 << 2, NewModifier = 1 << 3, SealedModifier = 1 << 4, UnsafeModifier = 1 << 5, FixedModifier = 1 << 6, ShortModifier = 1 << 7, LongModifier = 1 << 8, LongLongModifier = 1 << 9, SignedModifier = 1 << 10, UnsignedModifier = 1 << 11, - LanguageSpecificModifier = 1 << 12 //TODO make this support 64 bit values + + LanguageSpecificModifier = 1 << 12 }; /// Constructor. AbstractType(); /// Constructor from data. explicit AbstractType(AbstractTypeData& dd); /// Destructor. virtual ~AbstractType (); /** * Access the type modifiers * * \returns the type's modifiers. */ - quint64 modifiers() const; + quint32 modifiers() const; /** * Set the type's modifiers. * * \param modifiers modifiers of this type. */ - void setModifiers(quint64 modifiers); + void setModifiers(quint32 modifiers); /** * Visitor method. Called by TypeVisitor to visit the type heirachy. * Do not reimplement this, reimplement accept0 instead. * * \param v visitor which is calling this function. */ void accept(TypeVisitor *v) const; /** * Convenience visitor method which can be called with a null type. * * \param type type to visit, may be null. * \param v visitor which is visiting the given \a type */ static void acceptType(AbstractType::Ptr type, TypeVisitor *v); /** * Returns this type as a string, preferably the same as it is expressed in the code. * * \return this type as a string */ virtual QString toString() const; ///Must always be called before anything in the data pointer is changed! ///If it's not called beforehand, the type-repository gets corrupted void makeDynamic(); ///Should return whether this type's content equals the given one ///Since this is used by the type-repository, it must compare ALL members of the data type. virtual bool equals(const AbstractType* rhs) const; /** * Should create a clone of the source-type, with as much data copied as possible without breaking the du-chain. * */ virtual AbstractType* clone() const = 0; /** * A hash-value that should have the following properties: * - When two types match on equals(), it should be same. * - When two types don't match on equals(), it should be different with a high probability. * */ virtual uint hash() const; ///This can also be called on zero types, those can then be reconstructed from the zero index IndexedType indexed() const; /// Enumeration of major data types. - enum WhichType { + enum WhichType : quint8 { TypeAbstract /**< an abstract type */, TypeIntegral /**< an integral */, TypePointer /**< a pointer*/, TypeReference /**< a reference */, TypeFunction /**< a function */, TypeStructure /**< a structure */, TypeArray /**< an array */, TypeDelayed /**< a delayed type */, TypeEnumeration /**< an enumeration type */, TypeEnumerator /**< an enumerator type */, TypeAlias /**< a type-alias type */, TypeUnsure /**< may represent multiple different types */ }; /** * Determine which data type this abstract type represents. * * \returns the data type represented by this type. */ virtual WhichType whichType() const; enum { Identity = 1 }; /** * Should, like accept0, be implemented by all types that hold references to other types. * * If this is called on one type, that type should call exchangeTypes(..) with all its referenced sub-types. * The type itself does not recurse into the sub-types, that can be done by the exchanger itself if desired. * */ virtual void exchangeTypes( TypeExchanger* exchanger ); /** * Method to create copies of internal type data. You must use this to create the internal * data instances in copy constructors. It is needed, because it may need to allocate more memory * for appended lists. * * \param rhs data to copy * \returns copy of the data */ template static typename Type::Data& copyData(const typename Type::Data& rhs) { uint size; if(!rhs.m_dynamic) size = sizeof(typename Type::Data); //Create a dynamic data instance else size = rhs.dynamicSize(); //Create a constant data instance, that holds all the data embedded. typename Type::Data& ret(*new (new char[size]) typename Type::Data(rhs)); ret.template setTypeClassId(); return ret; } /** * As above, but does not support copying data into a lower class(Should not be used while cloning) */ template static DataType& copyDataDirectly(const DataType& rhs) { uint size; if(!rhs.m_dynamic) size = sizeof(DataType); //Create a dynamic data instance else size = rhs.dynamicSize(); //Create a constant data instance, that holds all the data embedded. return *new (new char[size]) DataType(rhs); } /** * Method to create internal data structures. Use this in normal constructors. * * \returns the internal data structure */ template static typename Type::Data& createData() { typename Type::Data& ret(*new (new char[sizeof(typename Type::Data)]) typename Type::Data()); ret.template setTypeClassId(); return ret; } typedef AbstractTypeData Data; protected: /** * Visitor method, reimplement to allow visiting of types. * * \param v visitor which is visiting. */ virtual void accept0 (TypeVisitor *v) const = 0; /// toString() function which can provide \a spaceOnLeft rather than on right if desired. QString toString(bool spaceOnLeft) const; AbstractTypeData* d_ptr; TYPE_DECLARE_DATA(AbstractType) friend class AbstractTypeDataRequest; private: AbstractType(const AbstractType& rhs); }; /** * You can use these instead of dynamic_cast, for basic types it has better performance because it checks the whichType() member */ template inline To fastCast(AbstractType* from) { return dynamic_cast(from); } template inline const To fastCast(const AbstractType* from) { return const_cast(fastCast(const_cast(from))); //Hack so we don't need to define the functions twice, once for const, and once for not const } } #endif diff --git a/language/duchain/types/delayedtype.h b/language/duchain/types/delayedtype.h index 482db2cc9..9097df19c 100644 --- a/language/duchain/types/delayedtype.h +++ b/language/duchain/types/delayedtype.h @@ -1,107 +1,107 @@ /* This file is part of KDevelop Copyright 2006 Roberto Raggi Copyright 2006-2008 Hamish Rodda Copyright 2007-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_DELAYEDTYPE_H #define KDEVPLATFORM_DELAYEDTYPE_H #include "abstracttype.h" #include "../identifier.h" namespace KDevelop { class DelayedTypeData; /** * \short A type which has not yet been resolved. * * Delayed types can be used for any types that cannot be resolved in the moment they are encountered. * They can be used for example in template-classes, or to store the names of unresolved types. * In a template-class, many types can not be evaluated at the time they are used, because they depend on unknown template-parameters. * Delayed types store the way the type would be searched, and can be used to find the type once the template-paremeters have values. * */ class KDEVPLATFORMLANGUAGE_EXPORT DelayedType : public KDevelop::AbstractType { public: typedef TypePtr Ptr; /// An enumeration of - enum Kind { + enum Kind : quint8 { Delayed /**< The type should be resolved later. This is the default. */, Unresolved /**< The type could not be resolved */ }; /// Default constructor DelayedType(); /// Copy constructor. \param rhs type to copy DelayedType(const DelayedType& rhs); /// Constructor using raw data. \param data internal data. explicit DelayedType(DelayedTypeData& data); /// Destructor virtual ~DelayedType(); /** * Access the type identifier which this type represents. * * \returns the type identifier. */ KDevelop::IndexedTypeIdentifier identifier() const; /** * Set the type identifier which this type represents. * * \param identifier the type identifier. */ void setIdentifier(const KDevelop::IndexedTypeIdentifier& identifier); virtual QString toString() const override; virtual AbstractType* clone() const override; virtual bool equals(const AbstractType* rhs) const override; Kind kind() const; void setKind(Kind kind); virtual uint hash() const override; virtual WhichType whichType() const override; enum { Identity = 8 }; typedef DelayedTypeData Data; protected: virtual void accept0 (KDevelop::TypeVisitor *v) const override ; TYPE_DECLARE_DATA(DelayedType) }; template<> inline DelayedType* fastCast(AbstractType* from) { if(!from || from->whichType() != AbstractType::TypeDelayed) return 0; else return static_cast(from); } } #endif diff --git a/language/duchain/types/typesystem.cpp b/language/duchain/types/typesystem.cpp index b234423d2..9db7c0bc5 100644 --- a/language/duchain/types/typesystem.cpp +++ b/language/duchain/types/typesystem.cpp @@ -1,226 +1,228 @@ /* This file is part of KDevelop Copyright 2006 Roberto Raggi Copyright 2006 Hamish Rodda Copyright 2007-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 "typesystem.h" #include "typerepository.h" #include "typesystemdata.h" #include "typeregister.h" #include "integraltype.h" #include "structuretype.h" #include namespace KDevelop { AbstractTypeData::AbstractTypeData() - : m_modifiers(AbstractType::NoModifiers) - , inRepository(false), refCount(0) + : refCount(0) + , m_modifiers(AbstractType::NoModifiers) + , inRepository(false) { initializeAppendedLists(true); } uint AbstractTypeData::classSize() const { return TypeSystem::self().dataClassSize(*this); } unsigned int AbstractTypeData::itemSize() const { return TypeSystem::self().dynamicSize(*this); } unsigned int AbstractTypeData::hash() const { AbstractType::Ptr type( TypeSystem::self().create(const_cast(this)) ); return type->hash(); } AbstractTypeData::AbstractTypeData( const AbstractTypeData& rhs ) - : m_modifiers(rhs.m_modifiers) - , inRepository(false), refCount(0) + : refCount(0) + , m_modifiers(rhs.m_modifiers) + , inRepository(false) { initializeAppendedLists(!rhs.m_dynamic); //This type will be dynamic exactly if the copied one is not. typeClassId = rhs.typeClassId; } AbstractTypeData::~AbstractTypeData() { freeAppendedLists(); } AbstractTypeData& AbstractTypeData::operator=(const AbstractTypeData&) { Q_ASSERT(0); return *this; } IntegralTypeData::IntegralTypeData() : m_dataType(IntegralType::TypeNone) { } IntegralTypeData::IntegralTypeData( const IntegralTypeData& rhs ) : AbstractTypeData(rhs), m_dataType(rhs.m_dataType) { } PointerTypeData::PointerTypeData() { } PointerTypeData::PointerTypeData( const PointerTypeData& rhs ) : AbstractTypeData(rhs), m_baseType( rhs.m_baseType ) { } ReferenceTypeData::ReferenceTypeData() : m_isRValue( false ) { } ReferenceTypeData::ReferenceTypeData( const ReferenceTypeData& rhs ) : AbstractTypeData( rhs ), m_baseType( rhs.m_baseType ), m_isRValue( rhs.m_isRValue ) { } FunctionTypeData::FunctionTypeData() { initializeAppendedLists(m_dynamic); } FunctionTypeData::~FunctionTypeData() { freeAppendedLists(); } FunctionTypeData::FunctionTypeData( const FunctionTypeData& rhs ) : AbstractTypeData( rhs ), m_returnType( rhs.m_returnType) { initializeAppendedLists(m_dynamic); copyListsFrom(rhs); } void FunctionTypeData::operator=(const FunctionTypeData& rhs) { Q_UNUSED(rhs) } StructureTypeData::StructureTypeData() { } StructureTypeData::StructureTypeData( const StructureTypeData& rhs ) : MergeIdentifiedType::Data( rhs ) { } ConstantIntegralTypeData::ConstantIntegralTypeData() : m_value(0) { } ArrayTypeData::ArrayTypeData() : m_dimension(0) { } ArrayTypeData::ArrayTypeData( const ArrayTypeData& rhs ) : AbstractTypeData( rhs ), m_dimension( rhs.m_dimension ), m_elementType( rhs.m_elementType ) { Q_ASSERT(m_dimension == rhs.m_dimension); } DelayedTypeData::DelayedTypeData() : m_kind(DelayedType::Delayed) { } DelayedTypeData::DelayedTypeData( const DelayedTypeData& rhs ) : AbstractTypeData( rhs ), m_identifier( rhs.m_identifier ), m_kind( rhs.m_kind ) { } bool SimpleTypeVisitor::preVisit (const AbstractType *) { return true; } void SimpleTypeVisitor::postVisit (const AbstractType *) { } void SimpleTypeVisitor::visit (const IntegralType * type) { visit( (AbstractType*)type ); } bool SimpleTypeVisitor::visit (const PointerType * type) { return visit( (AbstractType*)type ); } void SimpleTypeVisitor::endVisit (const PointerType * type) { visit( (AbstractType*)type ); } bool SimpleTypeVisitor::visit (const ReferenceType * type) { return visit( (AbstractType*)type ); } void SimpleTypeVisitor::endVisit (const ReferenceType * type) { visit( (AbstractType*)type ); } bool SimpleTypeVisitor::visit (const FunctionType * type) { return visit( (AbstractType*)type ); } void SimpleTypeVisitor::endVisit (const FunctionType * type) { visit( (AbstractType*)type ); } bool SimpleTypeVisitor::visit (const StructureType * type) { return visit( (AbstractType*)type ); } void SimpleTypeVisitor::endVisit (const StructureType * type) { visit( (AbstractType*)type ); } bool SimpleTypeVisitor::visit (const ArrayType * type) { return visit( (AbstractType*)type ); } void SimpleTypeVisitor::endVisit (const ArrayType * type) { visit( (AbstractType*)type ); } TypeVisitor::~TypeVisitor() { } TypePtr< KDevelop::AbstractType > TypeExchanger::exchange(const TypePtr< KDevelop::AbstractType >& type) { const_cast(type.data())->exchangeTypes(this); return type; } TypePtr< KDevelop::AbstractType > SimpleTypeExchanger::exchange(const TypePtr< KDevelop::AbstractType >& type) { if(type && type->equals(m_replace.data())) return m_replaceWith; else return TypeExchanger::exchange(type); } SimpleTypeExchanger::SimpleTypeExchanger(TypePtr< KDevelop::AbstractType > replace, TypePtr< KDevelop::AbstractType > replaceWith) : m_replace(replace), m_replaceWith(replaceWith) { } } diff --git a/language/duchain/types/typesystemdata.h b/language/duchain/types/typesystemdata.h index 2bc0cf41f..63e4e29be 100644 --- a/language/duchain/types/typesystemdata.h +++ b/language/duchain/types/typesystemdata.h @@ -1,223 +1,224 @@ /* This file is part of KDevelop Copyright 2006 Roberto Raggi Copyright 2006 Hamish Rodda Copyright 2007-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_TYPESYSTEMDATA_H #define KDEVPLATFORM_TYPESYSTEMDATA_H #include "../appendedlist.h" #include "indexedtype.h" #include "delayedtype.h" #include "identifiedtype.h" #include namespace KDevelop { KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(FunctionTypeData, m_arguments, IndexedType) /** * Private data structure for AbstractType. * * Inherit from this for custom type private data. * * Within your inherited data types, you can use the mechanisms described in appendedlist.h * * You must explicitly implement the copy constructor, see appendedlist.h for more information on copying dynamic data. * When calling initializeAppendedLists() as described there, you should always use m_dynamic as parameter. */ class KDEVPLATFORMLANGUAGE_EXPORT AbstractTypeData { public: /// Constructor. AbstractTypeData(); /** * Copy constructor. * * While cloning, the dynamic/constant attribute alternates(The copy of dynamic data is constant, and the copy of constant data is dynamic) * This means that when copying dynamic data, the size of the allocated buffer must be big enough to hold the appended lists. * the AbstractType::copyData function cares about that. * * \param rhs data to copy. */ AbstractTypeData( const AbstractTypeData& rhs ); /// Destructor. ~AbstractTypeData(); /** * Internal setup for the data structure. * * This must be called from actual class that belongs to this data(not parent classes), and the class must have the * "Identity" enumerator with a unique identity. Do NOT call this in copy-constructors! */ template void setTypeClassId() { + static_assert(T::Identity < std::numeric_limits::max(), "TypeClass ID out of bounds"); typeClassId = T::Identity; } - /// Remember which type this data was created for. \sa setTypeClassId() - uint typeClassId; + /// Reference-count for this type within the repository. Not used for comparison or hashes. + uint refCount; /// Type modifier flags - quint64 m_modifiers; + quint32 m_modifiers; + + /// Remember which type this data was created for. \sa setTypeClassId() + quint16 typeClassId; /// Remember whether this type is in a TypeRepository. Not used for comparison or hashes. bool inRepository : 1; - - /// Reference-count for this type within the repository. Not used for comparison or hashes. - uint refCount; APPENDED_LISTS_STUB(AbstractTypeData) /// Returns the pure data size of this class(not including anything dynamic). uint classSize() const; /// Returns the complete size of this item in memory, including derived class data and derived class appended list data unsigned int itemSize() const; /// Expensive unsigned int hash() const; void freeDynamicData() { } private: AbstractTypeData& operator=(const AbstractTypeData&); }; /// Private data structure for IntegralType class KDEVPLATFORMLANGUAGE_EXPORT IntegralTypeData : public AbstractTypeData { public: /// Constructor IntegralTypeData(); /// Copy constructor. \param rhs data to copy IntegralTypeData( const IntegralTypeData& rhs ); /// Data type uint m_dataType; }; /// Private data structure for PointerType class KDEVPLATFORMLANGUAGE_EXPORT PointerTypeData : public AbstractTypeData { public: /// Constructor PointerTypeData(); /// Copy constructor. \param rhs data to copy PointerTypeData( const PointerTypeData& rhs ); /// Type of data at which the pointer points IndexedType m_baseType; }; /// Private data structure for ReferenceType class KDEVPLATFORMLANGUAGE_EXPORT ReferenceTypeData : public AbstractTypeData { public: /// Constructor ReferenceTypeData(); /// Copy constructor. \param rhs data to copy ReferenceTypeData( const ReferenceTypeData& rhs ); /// Type of data which is referenced IndexedType m_baseType; /// True if this is an rvalue-reference, false for lvalue-references bool m_isRValue : 1; }; KDEVPLATFORMLANGUAGE_EXPORT DECLARE_LIST_MEMBER_HASH(FunctionTypeData, m_arguments, IndexedType) /// Private data structure for FunctionType class KDEVPLATFORMLANGUAGE_EXPORT FunctionTypeData : public AbstractTypeData { public: /// Constructor FunctionTypeData(); /// Copy constructor. \param rhs data to copy FunctionTypeData( const FunctionTypeData& rhs ); /// Destructor ~FunctionTypeData(); /// Function return type IndexedType m_returnType; START_APPENDED_LISTS_BASE(FunctionTypeData, AbstractTypeData); APPENDED_LIST_FIRST(FunctionTypeData, IndexedType, m_arguments); END_APPENDED_LISTS(FunctionTypeData, m_arguments); private: void operator=(const FunctionTypeData& rhs); }; /// Private data structure for ReferenceType class KDEVPLATFORMLANGUAGE_EXPORT TypeAliasTypeData : public MergeIdentifiedType::Data { public: /// Type of data which is typedeffed IndexedType m_type; }; /// Private data structure for StructureType class KDEVPLATFORMLANGUAGE_EXPORT StructureTypeData : public MergeIdentifiedType::Data { public: /// Constructor StructureTypeData(); /// Copy constructor. \param rhs data to copy StructureTypeData( const StructureTypeData& rhs ); /// Whether the type is closed yet }; /// Private data structure for ArrayType class KDEVPLATFORMLANGUAGE_EXPORT ArrayTypeData : public AbstractTypeData { public: /// Constructor ArrayTypeData(); /// Copy constructor. \param rhs data to copy ArrayTypeData( const ArrayTypeData& rhs ); /// Dimension of the array int m_dimension; /// Element type of the array IndexedType m_elementType; }; /// Private data structure for DelayedType class KDEVPLATFORMLANGUAGE_EXPORT DelayedTypeData : public AbstractTypeData { public: /// Constructor DelayedTypeData(); /// Copy constructor. \param rhs data to copy DelayedTypeData( const DelayedTypeData& rhs ); /// Identifier of the delayed type IndexedTypeIdentifier m_identifier; /// Type of delay in resolving the type DelayedType::Kind m_kind; }; /// Private data structure for ConstantIntegralType struct ConstantIntegralTypeData : public IntegralTypeData { /// Constructor ConstantIntegralTypeData(); /// Constant integer value qint64 m_value; }; } #endif