File: ducontext.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 (951 lines) | stat: -rw-r--r-- 39,052 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
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
/*
    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_DUCONTEXT_H
#define KDEVPLATFORM_DUCONTEXT_H

#include <QHash>
#include <QList>
#include <QSet>
#include <QVector>

#include <util/kdevvarlengtharray.h>

#include "identifier.h"
#include "duchainbase.h"
#include "types/abstracttype.h"
#include "duchainpointer.h"
#include "declarationid.h"
#include "indexedducontext.h"

#include "navigation/abstractnavigationwidget.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();
};

using DUContextPointer = DUChainPointer<DUContext>;

/**
 * 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 = nullptr, bool anonymous = false);
    explicit DUContext(DUContextData&);

    /**
     * Destructor. Will delete all child contexts which are defined within
     * the same file as this context.
     */
    ~DUContext() override;

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

    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.
     */
    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 @p position.
     *
     * The search is recursive, so the most specific context is found.
     *
     * @param includeBorders When this is true, contexts will also be found that
     *                           have the position on their borders.
     *
     * @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 @p 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()) { }
        explicit 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<Import> 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<DUContext*> importers() const;

    /**
     * Returns the list of indexed importers.
     *
     * Cheap, because nothing needs to be loaded.
     */
    KDevVarLengthArray<IndexedDUContext> indexedImporters() const;

    /**
     * Returns the list of immediate child contexts for this context.
     *
     * @note This is expensive.
     */
    QVector<DUContext*> childContexts() const;

    /**
     * Clears and deletes all child contexts recursively.
     *
     * This will not cross file boundaries.
     */
    void deleteChildContextsRecursively();

    /**
     * Resort the child contexts by their range.
     *
     * You must call this when you manually change the range of child contexts in a way
     * that could break the internal range sorting.
     */
    void resortChildContexts();

    /**
     * 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 @p identifier in this context, which
     * is currently active at the given text @p position, with the given type @p dataType.
     * In fact, only items are returned that are declared BEFORE that position.
     *
     * @param identifier the identifier of the definition to search for
     * @param position 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 dataType 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<Declaration*> findDeclarations(const QualifiedIdentifier& identifier,
                                         const CursorInRevision& position = CursorInRevision::invalid(),
                                         const AbstractType::Ptr& dataType = AbstractType::Ptr(),
                                         const TopDUContext* topContext = nullptr,
                                         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 position   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<Declaration*> findDeclarations(const IndexedIdentifier& identifier,
                                         const CursorInRevision& position = CursorInRevision::invalid(),
                                         const TopDUContext* topContext = nullptr,
                                         SearchFlags flags = NoSearchFlags) const;

    /**
     * Prefer the version above for speed reasons.
     */
    QList<Declaration*> findDeclarations(const Identifier& identifier,
                                         const CursorInRevision& position = CursorInRevision::invalid(),
                                         const TopDUContext* topContext = nullptr,
                                         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<Declaration*> findLocalDeclarations(const IndexedIdentifier& identifier,
                                              const CursorInRevision& position = CursorInRevision::invalid(),
                                              const TopDUContext* topContext = nullptr,
                                              const AbstractType::Ptr& dataType = AbstractType::Ptr(),
                                              SearchFlags flags = NoSearchFlags) const;

    /**
     * Prefer the version above for speed reasons.
     */
    QList<Declaration*> findLocalDeclarations(const Identifier& identifier,
                                              const CursorInRevision& position = CursorInRevision::invalid(),
                                              const TopDUContext* topContext = nullptr,
                                              const AbstractType::Ptr& dataType = AbstractType::Ptr(),
                                              SearchFlags flags = NoSearchFlags) const;

    /**
     * Clears all local declarations.
     *
     * Does not delete the declaration; the caller assumes ownership.
     */
    QVector<Declaration*> 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<Declaration*> localDeclarations(const TopDUContext* source = nullptr) const;

    /**
     * Resort the local declarations by their range.
     *
     * You must call this when you manually change the range of declarations in a way
     * that could break the internal range sorting.
     */
    void resortLocalDeclarations();

    /**
     * Searches for the most specific context for the given cursor @p position in the given @p url.
     *
     * @param position 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 = nullptr) 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 @p position in a given @p url.
     *
     * @param position 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.
     */
    QVector<QPair<Declaration*, int>> 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<DUChainBase*>& 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 @p declarationIndex
     * to the use with index @p useIndex.
     */
    void setUseDeclaration(int useIndex, int declarationIndex);

    /**
     * Creates a new use of the declaration given  through @p 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 @p 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.
     *
     * 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.
     *
     * 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 AbstractNavigationWidget*
    createNavigationWidget(Declaration* decl = nullptr, TopDUContext* topContext = nullptr,
                           AbstractNavigationWidget::DisplayHints hints = AbstractNavigationWidget::NoHints) 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
    {
        using Ptr = QExplicitlySharedDataPointer<SearchItem>;
        using PtrList = KDevVarLengthArray<Ptr, 256>;

        /**
         * Constructs a representation of the given @p id qualified identifier,
         * starting at its index @p start.
         *
         * @param nextItem is set as next item to the last item in the chain
         */
        explicit SearchItem(const QualifiedIdentifier& id, const Ptr& nextItem = Ptr(), int start = 0);

        /**
         * Constructs a representation of the given @p id qualified identifier,
         * starting at its index @p start.
         *
         * @param nextItems 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
         */
        QVector<QualifiedIdentifier> 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

    using DeclarationList = QList<Declaration*>;

    /**
     * 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)
     */
    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'
     */
    QVector<QualifiedIdentifier> 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 @p 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 hadContexts is used to count together all contexts that already were
     *                visited, so they are not visited again.
     */
    virtual void mergeDeclarationsInternal(QVector<QPair<Declaration*, int>>& definitions,
                                           const CursorInRevision& position,
                                           QHash<const DUContext*, bool>& 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 = nullptr, 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 initFromTopContext();
    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 @p declarationIndex
 */
KDEVPLATFORMLANGUAGE_EXPORT QVector<RangeInRevision> allUses(DUContext* context,
                                                             int declarationIndex,
                                                             bool noEmptyRanges = false);
}

Q_DECLARE_TYPEINFO(KDevelop::DUContext::Import, Q_MOVABLE_TYPE);

KDEVPLATFORMLANGUAGE_EXPORT QDebug operator<<(QDebug dbg, const KDevelop::DUContext::Import& import);

#endif // KDEVPLATFORM_DUCONTEXT_H