/* 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 KSharedPtr; 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 KSharedPtr 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; /** * @see ParsingEnvironmentFile * May return zero if no file was set. * */ KSharedPtr 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; /// 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; enum { Identity = 4 }; enum Flags { NoFlags = 0, ///Can be used by language parts to mark contexts they currently update(for their internal usage) UpdatingContext = 1, ///You can define own language-dependent flags behind this flag LastFlag = 2 }; enum Features { ///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(); /** * Use flags to mark top-contexts for special behavior. Any flags above LastFlag may be used for language-specific stuff. * */ Flags flags() const; void setFlags(Flags f); /** * 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 */ KSharedPtr ast() const; /** * Sets the AST Container. */ void setAst(KSharedPtr 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); ///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); ///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(); typedef Utils::StorableSet IndexedRecursiveImports; virtual QVector importedParentContexts() const; virtual QVector importers() const; ///Returns all currently loade importers virtual QList loadedImporters() const; virtual CursorInRevision importPosition(const DUContext* target) const; ///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; 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); //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 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on