File indexing completed on 2024-05-12 04:37:58
0001 /* 0002 SPDX-FileCopyrightText: 2006-2008 Hamish Rodda <rodda@kde.org> 0003 SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #ifndef KDEVPLATFORM_DUCHAIN_H 0009 #define KDEVPLATFORM_DUCHAIN_H 0010 0011 #include <QObject> 0012 0013 #include "topducontext.h" 0014 #include "parsingenvironment.h" 0015 0016 #include <interfaces/isessionlock.h> 0017 0018 class QUrl; 0019 0020 namespace KDevelop { 0021 class IDocument; 0022 class TopDUContext; 0023 class DUChainLock; 0024 0025 class ParsingEnvironmentManager; 0026 class ParsingEnvironment; 0027 class ParsingEnvironmentFile; 0028 using ParsingEnvironmentFilePointer = QExplicitlySharedDataPointer<ParsingEnvironmentFile>; 0029 class Definitions; 0030 class Uses; 0031 0032 /** 0033 * \short Holds references to all top level source file contexts. 0034 * 0035 * The DUChain is a global static class which manages the definition-use 0036 * chains. It performs the following functions: 0037 * \li registers chains with addDocumentChain() and deregisters with removeDocumentChain() 0038 * \li allows querying for existing chains 0039 * \li watches text editors, registering and deregistering them with the BackgroundParser when files 0040 * are opened and closed. 0041 */ 0042 class KDEVPLATFORMLANGUAGE_EXPORT DUChain 0043 : public QObject 0044 { 0045 Q_OBJECT 0046 0047 public: 0048 /** 0049 * Initializes common static item repositories. 0050 * Must be called once for multi threaded applications to work reliably. 0051 */ 0052 static void initialize(); 0053 0054 /** 0055 * Return a list of all chains available 0056 */ 0057 QList<TopDUContext*> allChains() const; 0058 0059 /** 0060 * Makes sure the standard-context for the given url is up-to-date. 0061 * This may trigger a parsing in background, so a QObject can be given that will be notified 0062 * asynchronously once the update is ready. 0063 * If the context is already up to date, the given QObject is notified directly. 0064 * 0065 * @param document Document to update 0066 * @param minFeatures The requested features. If you want to force a full update of the context, give TopDUContext::ForceUpdate. 0067 * If you want to force an update including all imports, use TopDUContext::ForceUpdateRecursive. 0068 * @param notifyReady An optional pointer to a QObject that should contain a slot 0069 * "void updateReady(KDevelop::IndexedString url, KDevelop::ReferencedTopDUContext topContext)". 0070 * The notification is guaranteed to be called once for each call to updateContextForUrl. The given top-context 0071 * may be invalid if the update failed. A queued connection is used if a re-parse has to be done. The duchain 0072 * will _not_ be locked when updateReady is called. 0073 * @param priority An optional priority for the job. The lower the value, the higher it's priority. 0074 * @note The duchain must _not_ be locked when this is called! 0075 */ 0076 void updateContextForUrl(const IndexedString& document, TopDUContext::Features minFeatures, 0077 QObject* notifyReady = nullptr, int priority = 1) const; 0078 0079 /** 0080 * Convenience-function similar to updateContextForUrl that blocks this thread until the update of the given document is ready, 0081 * and returns the top-context. 0082 * @param document The document to update 0083 * @param minFeatures The requested features. If you want to force a full update of the context, give TopDUContext::ForceUpdate. 0084 * If you want to force an update including all imports, use TopDUContext::ForceUpdateRecursive. 0085 * @return The up-to-date top-context, or zero if the update failed 0086 * 0087 * @note The duchain must _not_ be locked when this is called! 0088 * 0089 */ 0090 KDevelop::ReferencedTopDUContext waitForUpdate(const KDevelop::IndexedString& document, 0091 KDevelop::TopDUContext::Features minFeatures, 0092 bool proxyContext = false); 0093 0094 /** 0095 * Return any chain for the given document 0096 * If available, the version accepting IndexedString should be used instead of this, for performance reasons. 0097 * When no fitting chain is in memory, one may be loaded from disk. 0098 * 0099 * @note The duchain must be at least read-locked locked when this is called! 0100 * */ 0101 TopDUContext* chainForDocument(const QUrl& document, bool proxyContext = false) const; 0102 TopDUContext* chainForDocument(const IndexedString& document, bool proxyContext = false) const; 0103 0104 /** 0105 * Return all chains for the given document that are currently in memory. 0106 * This does not load any chains from disk. 0107 * */ 0108 QList<TopDUContext*> chainsForDocument(const QUrl& document) const; 0109 0110 /** 0111 * Return all chains for the given document that are currently in memory. 0112 * This does not load any chains from disk. 0113 * Should be preferred over the QUrl version. 0114 * */ 0115 QList<TopDUContext*> chainsForDocument(const IndexedString& document) const; 0116 0117 /** 0118 * Find a chain that fits into the given environment. If no fitting chain is found, 0 is returned. 0119 * When no fitting chain is in memory, one may be loaded from disk. 0120 * @param proxyContext If this is true, only contexts are found that have an ParsingEnvironmentFile that has the proxy-flag set. Else, only content-contexts will be returned. 0121 * 0122 * @note The duchain must be at least read-locked locked when this is called! 0123 * */ 0124 TopDUContext* chainForDocument(const QUrl& document, const ParsingEnvironment* environment, 0125 bool proxyContext = false) const; 0126 0127 /** 0128 * Find a chain that fits into the given environment. If no fitting chain is found, 0 is returned. 0129 * When no fitting chain is in memory, one may be loaded from disk. 0130 * @param proxyContext If this is true, only contexts are found that have an ParsingEnvironmentFile that has the proxy-flag set. Else, only content-contexts will be returned. 0131 * 0132 * Prefer this over the QUrl version. 0133 * 0134 * @note The duchain must be at least read-locked locked when this is called! 0135 * */ 0136 TopDUContext* chainForDocument(const IndexedString& document, const ParsingEnvironment* environment, 0137 bool proxyContext = false) const; 0138 0139 /** 0140 * Find the environment-file of a chain that fits into the given environment. If no fitting chain is found, 0 is returned. 0141 * When no fitting chain is in memory, one may be loaded from disk. 0142 * 0143 * This should be preferred over chainForDocument when only the environment-info is needed, because the TopDUContext is not loaded in this function. 0144 * 0145 ** @param proxyContext If this is true, only contexts are found that have an ParsingEnvironmentFile that has the proxy-flag set. Else, only content-contexts will be returned. 0146 * 0147 * Prefer this over the QUrl version. 0148 * 0149 * @note The duchain must be at least read-locked locked when this is called! 0150 * */ 0151 ParsingEnvironmentFilePointer environmentFileForDocument(const IndexedString& document, 0152 const ParsingEnvironment* environment, 0153 bool proxyContext = false) const; 0154 0155 ParsingEnvironmentFilePointer environmentFileForDocument(IndexedTopDUContext topContext) const; 0156 0157 /** 0158 * Returns the list of the environment-infos of all versions of the given document. 0159 */ 0160 QList<ParsingEnvironmentFilePointer> allEnvironmentFiles(const IndexedString& document); 0161 0162 ///Returns the top-context that has the given index assigned, or zero if it doesn't exist. @see TopDUContext::ownIndex 0163 ///The duchain must be read-locked when this is called 0164 ///This function is inlined because it is called in a very high frequency 0165 inline TopDUContext* chainForIndex(uint index) 0166 { 0167 if (m_deleted) 0168 return nullptr; 0169 0170 { 0171 QMutexLocker lock(&chainsByIndexLock); 0172 0173 if (chainsByIndex.size() > index) { 0174 TopDUContext* top = chainsByIndex[index]; 0175 if (top) 0176 return top; 0177 } 0178 } 0179 0180 //Load the top-context 0181 return loadChain(index); 0182 } 0183 0184 ///Returns the url for the given top-context index if available. This does have some cost, so avoid it when possible. 0185 IndexedString urlForIndex(uint index) const; 0186 0187 /// Only used for debugging at the moment 0188 QList<QUrl> documents() const; 0189 0190 /// Only used for debugging at the moment 0191 /// Prefer that over the QUrl version for performance reasons 0192 QList<IndexedString> indexedDocuments() const; 0193 0194 /** 0195 * Registers a new definition-use \a chain for the given \a document. 0196 */ 0197 void addDocumentChain(TopDUContext* chain); 0198 0199 /// Returns true if the global duchain instance has already been deleted 0200 static bool deleted(); 0201 0202 /// Returns the global static instance. 0203 static DUChain* self(); 0204 0205 /// Returns the structure that manages mapping between definitions and declarations 0206 static Definitions* definitions(); 0207 0208 /// Returns the structure that manages mapping between declarations, and which top level contexts contain uses of them. 0209 static Uses* uses(); 0210 0211 static QString repositoryPathForSession(const KDevelop::ISessionLock::Ptr& session); 0212 0213 /** 0214 * Retrieve the read write lock for the entire definition-use chain. 0215 * To call non-const methods, you must be holding a write lock. 0216 * 0217 * Evaluations made prior to holding a lock (including which objects 0218 * exist) must be verified once the lock is held, as they may have changed 0219 * or been deleted. 0220 * 0221 * \threadsafe 0222 */ 0223 static DUChainLock* lock(); 0224 0225 /// Returns whether the top-context with the given index is currently loaded in memory 0226 bool isInMemory(uint topContextIndex) const; 0227 0228 /** 0229 * Changes the environment attached to the given top-level context, and updates the management-structures to reflect that 0230 * */ 0231 void updateContextEnvironment(TopDUContext* context, ParsingEnvironmentFile* file); 0232 0233 ///Allocates a new identity for a new top-context, no lock needed. The returned value is never zero 0234 static uint newTopContextIndex(); 0235 0236 ///If you call this, the persistent disk-storage structure will stay unaffected, and no duchain cleanup will be done. 0237 ///Call this from within tests. 0238 void disablePersistentStorage(bool disable = true); 0239 0240 ///Stores the whole duchain and all its repositories in the current state to disk 0241 ///The duchain must not be locked in any way 0242 void storeToDisk(); 0243 0244 ///Compares the whole duchain and all its repositories in the current state to disk 0245 ///When the comparison fails, debug-output will show why 0246 ///The duchain must not be locked when calling this 0247 ///@return true If the current memory state equals the disk state, else false 0248 bool compareToDisk(); 0249 0250 Q_SIGNALS: 0251 ///Is emitted when the declaration has been selected somewhere in the user-interface, for example in the completion-list 0252 void declarationSelected(const KDevelop::DeclarationPointer& decl); 0253 0254 /** 0255 * This signal is emitted whenever the DUChain data associated with @p url was updated. 0256 * 0257 * You can connect to this signal to get notified when the DUChain for a given file was updated. 0258 */ 0259 void updateReady(const KDevelop::IndexedString& url, const KDevelop::ReferencedTopDUContext& topContext); 0260 0261 public Q_SLOTS: 0262 ///Removes the given top-context from the duchain, and deletes it. 0263 void removeDocumentChain(KDevelop::TopDUContext* document); 0264 ///Emits the declarationSelected signal, so other parties can notice it. 0265 void emitDeclarationSelected(const KDevelop::DeclarationPointer& decl); 0266 0267 /** 0268 * Call this after you have modified the DUChain data associated with the file @p url. 0269 * 0270 * This triggers an emit of the @c updateReady signal. 0271 */ 0272 void emitUpdateReady(const KDevelop::IndexedString& url, const KDevelop::ReferencedTopDUContext& topContext); 0273 0274 /** 0275 * Shutdown and cleanup the DUChain. 0276 */ 0277 void shutdown(); 0278 0279 private Q_SLOTS: 0280 void documentActivated(KDevelop::IDocument* doc); 0281 void documentLoadedPrepare(KDevelop::IDocument* document); 0282 void documentRenamed(KDevelop::IDocument* document); 0283 void documentClosed(KDevelop::IDocument*); 0284 0285 private: 0286 TopDUContext* loadChain(uint index); 0287 //These two are exported here so that the extremely frequently called chainForIndex(..) can be inlined 0288 static bool m_deleted; 0289 static std::vector<TopDUContext*> chainsByIndex; 0290 static QMutex chainsByIndexLock; 0291 0292 /// Increases the reference-count for the given top-context. The result: It will not be unloaded. 0293 /// Do this to prevent KDevelop from unloading a top-context that you plan to use. Don't forget calling unReferenceToContext again, 0294 /// else the top-context will stay in memory for ever. 0295 void refCountUp(TopDUContext* top); 0296 0297 /// Decreases the reference-count for the given top-context. When it reaches zero, KDevelop is free to unload it at any time, 0298 /// also invalidating all the contained declarations and contexts. 0299 void refCountDown(TopDUContext* top); 0300 0301 void addToEnvironmentManager(TopDUContext* chain); 0302 void removeFromEnvironmentManager(TopDUContext* chain); 0303 DUChain(); 0304 ~DUChain() override; 0305 0306 friend class DUChainPrivate; 0307 friend class ReferencedTopDUContext; 0308 }; 0309 } 0310 0311 #endif // KDEVPLATFORM_DUCHAIN_H