1 /*
2 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
3 SPDX-FileCopyrightText: 2007-2009 David Nolden <david.nolden.kdevelop@art-master.de>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6 */
7
8 #ifndef KDEVPLATFORM_TOPDUCONTEXT_H
9 #define KDEVPLATFORM_TOPDUCONTEXT_H
10
11 #include "ducontext.h"
12 #include <language/util/setrepository.h>
13 #include <QMetaType>
14
15 template <class T>
16 class QExplicitlySharedDataPointer;
17
18 namespace KDevelop {
19 class IAstContainer;
20 class QualifiedIdentifier;
21 class DUChain;
22 class ParsingEnvironmentFile;
23 class TopDUContextData;
24 class TopDUContextLocalPrivate;
25 class IndexedTopDUContext;
26 // class TopDUContextDynamicData;
27 class Problem;
28 class DeclarationChecker;
29 class TopDUContext;
30
31 struct KDEVPLATFORMLANGUAGE_EXPORT RecursiveImportRepository
32 {
33 static Utils::BasicSetRepository* repository();
34 };
35
36 ///Maps an imported top-context to a pair:
37 ///1. The distance to the top-context, and 2. The next step towards the top-context
38 ///in the chain.
39 using RecursiveImports = QHash<const TopDUContext*, QPair<int, const TopDUContext*>>;
40
41 using TopDUContextPointer = DUChainPointer<TopDUContext>;
42
43 using ProblemPointer = QExplicitlySharedDataPointer<Problem>;
44
45 ///KDevelop can unload unused top-context at any time. To prevent unloading,
46 ///keep a ReferencedTopDUContext.
47 class KDEVPLATFORMLANGUAGE_EXPORT ReferencedTopDUContext
48 {
49 public:
50 ReferencedTopDUContext(TopDUContext* context = nullptr);
51 ReferencedTopDUContext(const ReferencedTopDUContext& rhs);
52 ~ReferencedTopDUContext();
53
54 ReferencedTopDUContext& operator=(const ReferencedTopDUContext& rhs);
55
data()56 inline TopDUContext* data() const
57 {
58 return m_topContext;
59 }
60
61 inline operator TopDUContext*() const {
62 return m_topContext;
63 }
64
65 inline bool operator==(const ReferencedTopDUContext& rhs) const
66 {
67 return m_topContext == rhs.m_topContext;
68 }
69
70 inline bool operator!=(const ReferencedTopDUContext& rhs) const
71 {
72 return m_topContext != rhs.m_topContext;
73 }
74
75 inline TopDUContext* operator->() const
76 {
77 return m_topContext;
78 }
79
hash()80 inline uint hash() const
81 {
82 return ( uint )((( quint64 )m_topContext) * 37);
83 }
84
85 private:
86 TopDUContext* m_topContext;
87 };
88
89 /**
90 * The top context in a definition-use chain for one source file.
91 *
92 * Implements SymbolTable lookups and locking for the chain.
93 *
94 * Contexts and Classes can only be found through TopDUContext if they are in the symbol table.
95 * @see DUContext::setInSymbolTable, Declaration::setInSymbolTable
96 *
97 * \todo move the registration with DUChain here
98 *
99 * @warning Do not delete top-contexts directly, use DUChain::removeDocumentChain instead.
100 */
101 class KDEVPLATFORMLANGUAGE_EXPORT TopDUContext
102 : public DUContext
103 {
104 public:
105 explicit TopDUContext(const IndexedString& url, const RangeInRevision& range,
106 ParsingEnvironmentFile* file = nullptr);
107 explicit TopDUContext(TopDUContextData& data);
108
109 TopDUContext& operator=(const TopDUContext& rhs) = delete;
110
111 TopDUContext* topContext() const override;
112
113 ///Returns an indexed representation of this top-context. Indexed representations stay valid even if the top-context is unloaded.
114 IndexedTopDUContext indexed() const;
115
116 uint ownIndex() const;
117
118 IndexedString url() const override;
119
120 /**
121 * @see ParsingEnvironmentFile
122 * May return zero if no file was set.
123 * */
124 QExplicitlySharedDataPointer<ParsingEnvironmentFile> parsingEnvironmentFile() const;
125
126 /// Returns true if this object is being deleted, otherwise false.
127 bool deleting() const;
128
129 /// Returns true if this object is registered in the du-chain. If it is not, all sub-objects(context, declarations, etc.) can be changed
130 bool inDUChain() const override;
131 /// This flag is only used by DUChain, never change it from outside.
132 void setInDuChain(bool);
133
134 /// Whether this top-context has a stored version on disk
135 bool isOnDisk() const;
136
137 /**
138 * Returns a list of all problems encountered while parsing this top-context.
139 * Does not include the problems of imported contexts.
140 * */
141 QList<ProblemPointer> problems() const;
142
143 /**
144 * Add a parsing-problem to this context.
145 *
146 * \note you must be holding a write lock when you access this function.
147 * */
148 void addProblem(const ProblemPointer& problem);
149
150 /**
151 * Clear the list of problems
152 *
153 * \note you must be holding a write lock when you access this function.
154 */
155 void clearProblems();
156
157 /**
158 * Set the list of problems, replacing all existing ones.
159 *
160 * \note you must be holding a write lock when you access this function.
161 */
162 void setProblems(const QList<ProblemPointer>& pointers);
163
164 /**
165 * Determine if this chain imports another chain recursively.
166 *
167 * This uses the imports-cache for speedup if it is available, thus it is not necessarily 100% correct
168 * if the cache is not up-to-date.
169 *
170 * \note you must be holding a read but not a write chain lock when you access this function.
171 */
172 bool imports(const DUContext* origin, const CursorInRevision& position) const override;
173
174 enum {
175 Identity = 4
176 };
177
178 enum Feature : quint16 {
179 ///Top-context features standard that can be requested from the duchain, and that are stored in the features() member.
180 Empty = 0, //Only the top-context structure (imports etc.) is built, but no declarations and no contexts
181 SimplifiedVisibleDeclarationsAndContexts = 2, //The top-context should only contain publically simplified accessible declarations and contexts, without doing type look-up,
182 //without extended information like function-argument declarations, etc., imported contexts can be parsed with 'Empty' features
183 //This flag essentially leads to a ctags-like processing level.
184 VisibleDeclarationsAndContexts = SimplifiedVisibleDeclarationsAndContexts + 4, //Default: The top-context should only contain publically accessible declarations and contexts
185 AllDeclarationsAndContexts = VisibleDeclarationsAndContexts + 8, //The top-context should also contain non-public declarations and contexts, but no uses
186 AllDeclarationsContextsAndUses = 16 + AllDeclarationsAndContexts, //The top-context should contain uses and all declarations + contexts
187 AST = 32, //Signalizes that the ast() should be filled
188 AllDeclarationsContextsUsesAndAST = AST | AllDeclarationsContextsAndUses, //Convenience flag, combining AST and AllDeclarationsContextsAndUses
189
190 ///Additional update-flags that have a special meaning during updating, but are not set stored into a top-context
191 Recursive = 64, //Request the given features on all recursively imported contexts. Only the features are applied recursively (including AST)
192 ForceUpdate = 128, //Enforce updating the top-context
193 ForceUpdateRecursive = ForceUpdate | 256, //Enforce updating the top-context and all its imports
194
195 ///You can define own language-dependent features behind this flag
196 LastFeature = 512
197 };
198 Q_DECLARE_FLAGS(Features, Feature)
199
200 ///Returns the currently active features of this top-context. The features will include AST if ast() is valid.
201 Features features() const;
202 ///Set the features of this top-context. These features are ignored: AST, ForceUpdate, and ForceUpdateRecursive.
203 void setFeatures(Features);
204
205 /**
206 * Retrieves or creates a local index that is to be used for referencing the given @param declaration
207 * in local uses. Also registers this context as a user of the declaration.
208 * @param create If this is false, only already registered indices will be returned.
209 * If the declaration is not registered, std::numeric_limits<int>::max() is returned
210 *
211 * The duchain must be write-locked if create is true, else it must at least be read-locked.
212 * */
213 int indexForUsedDeclaration(Declaration* declaration, bool create = true);
214
215 /**
216 * Tries to retrieve the used declaration
217 * @param declarationIndex The index of the declaration which have to be retrieved
218 * */
219 Declaration* usedDeclarationForIndex(unsigned int declarationIndex) const;
220
221 /**
222 * You can use this before you rebuild all uses. This does not affect any uses directly,
223 * it only invalidates the mapping of declarationIndices to Declarations.
224 *
225 * usedDeclarationForIndex(..) must not be called until the use has gotten a new index through
226 * indexForUsedDeclaration(..).
227 * */
228 void clearUsedDeclarationIndices();
229
230 /**
231 * Recursively deletes all contained uses, declaration-indices, etc.
232 */
233 void deleteUsesRecursively() override;
234
235 /**
236 * Returns the AST Container, that contains the AST created during parsing.
237 * This is only created if you request the AST feature for parsing.
238 * It may be discarded at any time. Every update without the AST feature will discard it.
239 * The actual contents is language-specific.
240 *
241 * @todo Figure out logic to get rid of AST when it is not needed/useful
242 */
243 QExplicitlySharedDataPointer<IAstContainer> ast() const;
244
245 /**
246 * Sets the AST Container.
247 */
248 void setAst(const QExplicitlySharedDataPointer<IAstContainer>& ast);
249
250 /**
251 * Utility function to clear the AST Container
252 */
253 void clearAst();
254
255 ///@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,
256 ///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.
257 ///When this top-context does not own its private data, the import is added locally only to this context, not into the shared data.
258 void addImportedParentContext(DUContext* context,
259 const CursorInRevision& position = CursorInRevision(), bool anonymous = false,
260 bool temporary = false) override;
261 ///Use this for mass-adding of imported contexts, it is faster than adding them individually.
262 ///@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,
263 ///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.
264 ///When this top-context does not own its private data, the import is added locally only to this context, not into the shared data.
265 virtual void addImportedParentContexts(const QVector<QPair<TopDUContext*, CursorInRevision>>& contexts,
266 bool temporary = false);
267
268 ///When this top-context does not own its private data, the import is removed locally only from this context, not from the shared data.
269 void removeImportedParentContext(DUContext* context) override;
270 ///Use this for mass-removing of imported contexts, it is faster than removing them individually.
271 ///When this top-context does not own its private data, the import is removed locally only from this context, not from the shared data.
272 virtual void removeImportedParentContexts(const QList<TopDUContext*>& contexts);
273
274 ///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.
275 void clearImportedParentContexts() override;
276
277 using IndexedRecursiveImports = Utils::StorableSet<IndexedTopDUContext, IndexedTopDUContextIndexConversion, RecursiveImportRepository,
278 true>;
279
280 QVector<Import> importedParentContexts() const override;
281
282 QVector<DUContext*> importers() const override;
283
284 ///Returns all currently loade importers
285 virtual QList<DUContext*> loadedImporters() const;
286
287 CursorInRevision importPosition(const DUContext* target) const override;
288
289 ///Returns the set of all recursively imported top-contexts. If import-caching is used, this returns the cached set.
290 ///The list also contains this context itself. This set is used to determine declaration-visibility from within this top-context.
291 const IndexedRecursiveImports& recursiveImportIndices() const;
292
293 /**
294 * Updates the cache of recursive imports. When you call this, from that moment on the set returned by recursiveImportIndices() is fixed, until
295 * you call it again to update them. If your language has a very complex often-changing import-structure,
296 * like for example in the case of C++, it is recommended to call this during while parsing, instead of using
297 * the expensive builtin implicit mechanism.
298 * Note that if you use caching, you _must_ call this before you see any visibility-effect after adding imports.
299 *
300 * Using import-caching has another big advantage: A top-context can be loaded without loading all its imports.
301 *
302 * Note: This is relatively expensive since it requires loading all imported contexts.
303 *
304 * When this is called, the top-context must already be registered in the duchain.
305 */
306 void updateImportsCache();
307
308 bool usingImportsCache() const;
309
310 bool findDeclarationsInternal(const SearchItem::PtrList& identifiers, const CursorInRevision& position,
311 const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source,
312 SearchFlags flags, uint depth) const override;
313
314 protected:
315 void setParsingEnvironmentFile(ParsingEnvironmentFile*);
316
317 /**
318 * Does the same as DUContext::updateAliases, except that it uses the symbol-store, and processes the whole identifier.
319 * @param canBeNamespace whether the searched identifier may be a namespace.
320 * If this is true, namespace-aliasing is applied to the last elements of the identifiers.
321 * */
322 template <class Acceptor>
323 void applyAliases(const SearchItem::PtrList& identifiers, Acceptor& accept, const CursorInRevision& position,
324 bool canBeNamespace) const;
325
326 protected:
327 ~TopDUContext() override;
328
329 void clearFeaturesSatisfied();
330 void rebuildDynamicData(DUContext* parent, uint ownIndex) override;
331 //Must be called after all imported top-contexts were loaded into the du-chain
332 void rebuildDynamicImportStructure();
333
334 struct AliasChainElement;
335 struct FindDeclarationsAcceptor;
336 struct DeclarationChecker;
337 struct ApplyAliasesBuddyInfo;
338
339 template <class Acceptor>
340 bool applyAliases(const QualifiedIdentifier& previous, const SearchItem::Ptr& identifier, Acceptor& acceptor,
341 const CursorInRevision& position, bool canBeNamespace, ApplyAliasesBuddyInfo* buddy,
342 uint recursionDepth) const;
343 //Same as imports, without the slow access-check, for internal usage
344 bool importsPrivate(const DUContext* origin, const CursorInRevision& position) const;
345 DUCHAIN_DECLARE_DATA(TopDUContext)
346
347 ///Called by DUChain::removeDocumentChain to destroy this top-context.
348 void deleteSelf();
349
350 //Most of these classes need access to m_dynamicData
351 friend class DUChain;
352 friend class DUChainPrivate;
353 friend class TopDUContextData;
354 friend class TopDUContextLocalPrivate;
355 friend class TopDUContextDynamicData;
356 friend class Declaration;
357 friend class DUContext;
358 friend class Problem;
359 friend class IndexedDeclaration;
360 friend class IndexedDUContext;
361 friend class LocalIndexedDeclaration;
362 friend class LocalIndexedDUContext;
363 friend class LocalIndexedProblem;
364 friend class DeclarationId;
365 friend class ParsingEnvironmentFile;
366
367 TopDUContextLocalPrivate* m_local;
368
369 class TopDUContextDynamicData* m_dynamicData;
370 };
371
372 /**
373 * Returns all uses of the given declaration within this top-context and all sub-contexts
374 * */
375 KDEVPLATFORMLANGUAGE_EXPORT QVector<RangeInRevision> allUses(TopDUContext* context, Declaration* declaration,
376 bool noEmptyRanges = false);
377
qHash(const ReferencedTopDUContext & ctx)378 inline uint qHash(const ReferencedTopDUContext& ctx)
379 {
380 return ctx.hash();
381 }
382
383 #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
384 Q_DECLARE_OPERATORS_FOR_FLAGS(TopDUContext::Features)
385 #endif
386
387 }
388
389 #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
390 Q_DECLARE_OPERATORS_FOR_FLAGS(KDevelop::TopDUContext::Features)
391 #endif
392
393 Q_DECLARE_TYPEINFO(KDevelop::ReferencedTopDUContext, Q_MOVABLE_TYPE);
394 Q_DECLARE_METATYPE(KDevelop::ReferencedTopDUContext)
395
396 #endif // KDEVPLATFORM_TOPDUCONTEXT_H
397