1 /*
2     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
3     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
4 
5     SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #ifndef DUCONTEXTDYNAMICDATA_H
9 #define DUCONTEXTDYNAMICDATA_H
10 
11 #include "ducontextdata.h"
12 
13 namespace KDevelop {
14 ///This class contains data that is only runtime-dependent and does not need to be stored to disk
15 class DUContextDynamicData
16 {
17 private:
d_func()18     inline const DUContextData* d_func() const { return m_context->d_func(); }
d_func_dynamic()19     inline DUContextData* d_func_dynamic() { return m_context->d_func_dynamic(); }
ctx_d_func(DUContext * ctx)20     static inline const DUContextData* ctx_d_func(DUContext* ctx) { return ctx->d_func(); }
ctx_dynamicData(DUContext * ctx)21     static inline DUContextDynamicData* ctx_dynamicData(DUContext* ctx) { return ctx->m_dynamicData; }
22 
23 public:
24     explicit DUContextDynamicData(DUContext*);
25     DUContextPointer m_parentContext;
26 
27     TopDUContext* m_topContext;
28 
29     uint m_indexInTopContext; //Index of this DUContext in the top-context
30 
31     DUContext* m_context;
32 
33     // cache of unserialized child contexts
34     QVector<DUContext*> m_childContexts;
35     // cache of unserialized local declarations
36     QVector<Declaration*> m_localDeclarations;
37 
38     /**
39      * Adds a child context.
40      *
41      * \note Be sure to have set the text location first, so that
42      * the chain is sorted correctly.
43      */
44     void addChildContext(DUContext* context);
45 
46     /**Removes the context from childContexts
47      * @return Whether a context was removed
48      * */
49     bool removeChildContext(DUContext* context);
50 
51     void addImportedChildContext(DUContext* context);
52     void removeImportedChildContext(DUContext* context);
53 
54     void addDeclaration(Declaration* declaration);
55 
56     /**Removes the declaration from localDeclarations
57      * @return Whether a declaration was removed
58      * */
59     bool removeDeclaration(Declaration* declaration);
60 
61     //Files the scope identifier into target
62     void scopeIdentifier(bool includeClasses, QualifiedIdentifier& target) const;
63 
64     //Iterates through all visible declarations within a given context, including the ones propagated from sub-contexts
65     class VisibleDeclarationIterator
66     {
67 public:
68         struct StackEntry
69         {
70             explicit StackEntry(const DUContextDynamicData* data = nullptr)
dataStackEntry71                 : data(data)
72                 , index(0)
73                 , nextChild(0)
74             {
75             }
76 
77             const DUContextDynamicData* data;
78             int index;
79             uint nextChild;
80         };
81 
VisibleDeclarationIterator(const DUContextDynamicData * data)82         explicit VisibleDeclarationIterator(const DUContextDynamicData* data)
83             : current(data)
84         {
85             toValidPosition();
86         }
87 
88         inline Declaration* operator*() const
89         {
90             return current.data ? current.data->m_localDeclarations.value(current.index) : nullptr;
91         }
92 
93         inline VisibleDeclarationIterator& operator++()
94         {
95             ++current.index;
96             toValidPosition();
97             return *this;
98         }
99 
100         inline operator bool() const
101         {
102             return current.data && !current.data->m_localDeclarations.isEmpty();
103         }
104 
105         // Moves the cursor to the next valid position, from an invalid one
toValidPosition()106         void toValidPosition()
107         {
108             if (!current.data || current.index < current.data->m_localDeclarations.size()) {
109                 // still valid
110                 return;
111             }
112 
113             do {
114                 // Check if we can proceed into a propagating child-context
115                 for (int a = current.nextChild; a < current.data->m_childContexts.size(); ++a) {
116                     DUContext* child = current.data->m_childContexts[a];
117 
118                     if (ctx_d_func(child)->m_propagateDeclarations) {
119                         current.nextChild = a + 1;
120                         stack.append(current);
121                         current = StackEntry(ctx_dynamicData(child));
122                         toValidPosition();
123                         return;
124                     }
125                 }
126 
127                 //Go up and into the next valid context
128                 if (stack.isEmpty()) {
129                     current = StackEntry();
130                     return;
131                 }
132 
133                 current = stack.back();
134                 stack.pop_back();
135             } while (true);
136         }
137 
138         StackEntry current;
139 
140         KDevVarLengthArray<StackEntry> stack;
141     };
142 
143     /**
144      * Returns true if this context is imported by the given one, on any level.
145      * */
146     bool imports(const DUContext* context, const TopDUContext* source,
147                  QSet<const DUContextDynamicData*>* recursionGuard) const;
148 };
149 }
150 
151 Q_DECLARE_TYPEINFO(KDevelop::DUContextDynamicData::VisibleDeclarationIterator::StackEntry, Q_MOVABLE_TYPE);
152 
153 #endif
154