File: topducontext.h

package info (click to toggle)
kdevelop 4%3A22.12.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 70,096 kB
  • sloc: cpp: 284,635; javascript: 3,558; python: 3,422; sh: 1,319; ansic: 685; xml: 331; php: 95; lisp: 66; makefile: 39; sed: 12
file content (389 lines) | stat: -rw-r--r-- 16,585 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
/*
    SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
    SPDX-FileCopyrightText: 2007-2009 David Nolden <david.nolden.kdevelop@art-master.de>

    SPDX-License-Identifier: LGPL-2.0-only
*/

#ifndef KDEVPLATFORM_TOPDUCONTEXT_H
#define KDEVPLATFORM_TOPDUCONTEXT_H

#include "ducontext.h"
#include <language/util/setrepository.h>
#include <QMetaType>

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.
using RecursiveImports = QHash<const TopDUContext*, QPair<int, const TopDUContext*>>;

using TopDUContextPointer = DUChainPointer<TopDUContext>;

using ProblemPointer = QExplicitlySharedDataPointer<Problem>;

///KDevelop can unload unused top-context at any time. To prevent unloading,
///keep a ReferencedTopDUContext.
class KDEVPLATFORMLANGUAGE_EXPORT ReferencedTopDUContext
{
public:
    ReferencedTopDUContext(TopDUContext* context = nullptr);
    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 = nullptr);
    explicit TopDUContext(TopDUContextData& data);

    TopDUContext& operator=(const TopDUContext& rhs) = delete;

    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> 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
    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<ProblemPointer> 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<ProblemPointer>& 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.
     */
    bool imports(const DUContext* origin, const CursorInRevision& position) const override;

    enum {
        Identity = 4
    };

    enum Feature : 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
    };
    Q_DECLARE_FLAGS(Features, Feature)

    ///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<int>::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 The index of the declaration which have to be retrieved
     * */
    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.
     */
    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<IAstContainer> ast() const;

    /**
     * Sets the AST Container.
     */
    void setAst(const QExplicitlySharedDataPointer<IAstContainer>& 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.
    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 QVector<QPair<TopDUContext*, CursorInRevision>>& 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.
    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<TopDUContext*>& 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.
    void clearImportedParentContexts() override;

    using IndexedRecursiveImports = Utils::StorableSet<IndexedTopDUContext, IndexedTopDUContextIndexConversion, RecursiveImportRepository,
        true>;

    QVector<Import> importedParentContexts() const override;

    QVector<DUContext*> importers() const override;

    ///Returns all currently loade importers
    virtual QList<DUContext*> loadedImporters() const;

    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;

    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 <class Acceptor>
    void applyAliases(const SearchItem::PtrList& identifiers, Acceptor& accept, const CursorInRevision& position,
                      bool canBeNamespace) const;

protected:
    ~TopDUContext() override;

    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 <class Acceptor>
    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 QVector<RangeInRevision> allUses(TopDUContext* context, Declaration* declaration,
                                                             bool noEmptyRanges = false);

inline uint qHash(const ReferencedTopDUContext& ctx)
{
    return ctx.hash();
}

Q_DECLARE_OPERATORS_FOR_FLAGS(TopDUContext::Features)
}

Q_DECLARE_TYPEINFO(KDevelop::ReferencedTopDUContext, Q_MOVABLE_TYPE);
Q_DECLARE_METATYPE(KDevelop::ReferencedTopDUContext)

#endif // KDEVPLATFORM_TOPDUCONTEXT_H