File indexing completed on 2024-05-12 04:38:01

0001 /*
0002     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2007-2009 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "ducontext.h"
0009 
0010 #include <limits>
0011 #include <algorithm>
0012 
0013 #include <QSet>
0014 
0015 #include "ducontextdata.h"
0016 #include "declaration.h"
0017 #include "duchain.h"
0018 #include "duchainlock.h"
0019 #include "use.h"
0020 #include "identifier.h"
0021 #include "topducontext.h"
0022 #include "persistentsymboltable.h"
0023 #include "aliasdeclaration.h"
0024 #include "namespacealiasdeclaration.h"
0025 #include "abstractfunctiondeclaration.h"
0026 #include "duchainregister.h"
0027 #include "topducontextdynamicdata.h"
0028 #include "importers.h"
0029 #include "uses.h"
0030 #include "navigation/abstractdeclarationnavigationcontext.h"
0031 #include "navigation/abstractnavigationwidget.h"
0032 #include "ducontextdynamicdata.h"
0033 #include <debug.h>
0034 
0035 // maximum depth for DUContext::findDeclarationsInternal searches
0036 const uint maxParentDepth = 20;
0037 
0038 using namespace KTextEditor;
0039 
0040 #ifndef NDEBUG
0041 #define ENSURE_CAN_WRITE_(x) {if (x->inDUChain()) { ENSURE_CHAIN_WRITE_LOCKED }}
0042 #define ENSURE_CAN_READ_(x) {if (x->inDUChain()) { ENSURE_CHAIN_READ_LOCKED }}
0043 #else
0044 #define ENSURE_CAN_WRITE_(x)
0045 #define ENSURE_CAN_READ_(x)
0046 #endif
0047 
0048 QDebug operator<<(QDebug dbg, const KDevelop::DUContext::Import& import)
0049 {
0050     QDebugStateSaver saver(dbg);
0051     dbg.nospace() << "Import(" << import.indexedContext().data() << ')';
0052     return dbg;
0053 }
0054 
0055 namespace KDevelop {
0056 DEFINE_LIST_MEMBER_HASH(DUContextData, m_childContexts, LocalIndexedDUContext)
0057 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importers, IndexedDUContext)
0058 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importedContexts, DUContext::Import)
0059 DEFINE_LIST_MEMBER_HASH(DUContextData, m_localDeclarations, LocalIndexedDeclaration)
0060 DEFINE_LIST_MEMBER_HASH(DUContextData, m_uses, Use)
0061 
0062 REGISTER_DUCHAIN_ITEM(DUContext);
0063 
0064 DUChainVisitor::~DUChainVisitor()
0065 {
0066 }
0067 
0068 /**
0069  * We leak here, to prevent a possible crash during destruction, as the destructor
0070  * of Identifier is not safe to be called after the duchain has been destroyed
0071  */
0072 const Identifier& globalImportIdentifier()
0073 {
0074     static const Identifier globalImportIdentifierObject(QStringLiteral("{...import...}"));
0075     return globalImportIdentifierObject;
0076 }
0077 
0078 const Identifier& globalAliasIdentifier()
0079 {
0080     static const Identifier globalAliasIdentifierObject(QStringLiteral("{...alias...}"));
0081     return globalAliasIdentifierObject;
0082 }
0083 
0084 const IndexedIdentifier& globalIndexedImportIdentifier()
0085 {
0086     static const IndexedIdentifier id(globalImportIdentifier());
0087     return id;
0088 }
0089 
0090 const IndexedIdentifier& globalIndexedAliasIdentifier()
0091 {
0092     static const IndexedIdentifier id(globalAliasIdentifier());
0093     return id;
0094 }
0095 
0096 void DUContext::rebuildDynamicData(DUContext* parent, uint ownIndex)
0097 {
0098     Q_ASSERT(!parent || ownIndex);
0099     m_dynamicData->m_topContext = parent ? parent->topContext() : static_cast<TopDUContext*>(this);
0100     m_dynamicData->m_indexInTopContext = ownIndex;
0101     m_dynamicData->m_parentContext = DUContextPointer(parent);
0102     m_dynamicData->m_context = this;
0103 
0104     m_dynamicData->m_childContexts.clear();
0105     m_dynamicData->m_childContexts.reserve(d_func()->m_childContextsSize());
0106     FOREACH_FUNCTION(const LocalIndexedDUContext &ctx, d_func()->m_childContexts) {
0107         m_dynamicData->m_childContexts << ctx.data(m_dynamicData->m_topContext);
0108     }
0109 
0110     m_dynamicData->m_localDeclarations.clear();
0111     m_dynamicData->m_localDeclarations.reserve(d_func()->m_localDeclarationsSize());
0112     FOREACH_FUNCTION(const LocalIndexedDeclaration &idx, d_func()->m_localDeclarations) {
0113         auto declaration = idx.data(m_dynamicData->m_topContext);
0114         if (!declaration) {
0115             qCWarning(LANGUAGE) << "child declaration number" << idx.localIndex() << "of" <<
0116                 d_func_dynamic()->m_localDeclarationsSize() << "is invalid";
0117             continue;
0118         }
0119         m_dynamicData->m_localDeclarations << declaration;
0120     }
0121 
0122     DUChainBase::rebuildDynamicData(parent, ownIndex);
0123 }
0124 
0125 DUContextData::DUContextData()
0126     : m_inSymbolTable(false)
0127     , m_anonymousInParent(false)
0128     , m_propagateDeclarations(false)
0129 {
0130     initializeAppendedLists();
0131 }
0132 
0133 DUContextData::~DUContextData()
0134 {
0135     freeAppendedLists();
0136 }
0137 
0138 DUContextData::DUContextData(const DUContextData& rhs)
0139     : DUChainBaseData(rhs)
0140     , m_inSymbolTable(rhs.m_inSymbolTable)
0141     , m_anonymousInParent(rhs.m_anonymousInParent)
0142     , m_propagateDeclarations(rhs.m_propagateDeclarations)
0143 {
0144     initializeAppendedLists();
0145     copyListsFrom(rhs);
0146     m_scopeIdentifier = rhs.m_scopeIdentifier;
0147     m_contextType = rhs.m_contextType;
0148     m_owner = rhs.m_owner;
0149 }
0150 
0151 DUContextDynamicData::DUContextDynamicData(DUContext* d)
0152     : m_topContext(nullptr)
0153     , m_indexInTopContext(0)
0154     , m_context(d)
0155 {
0156 }
0157 
0158 void DUContextDynamicData::scopeIdentifier(bool includeClasses, QualifiedIdentifier& target) const
0159 {
0160     if (m_parentContext)
0161         m_parentContext->m_dynamicData->scopeIdentifier(includeClasses, target);
0162 
0163     if (includeClasses || d_func()->m_contextType != DUContext::Class)
0164         target += d_func()->m_scopeIdentifier;
0165 }
0166 
0167 bool DUContextDynamicData::imports(const DUContext* context, const TopDUContext* source,
0168                                    QSet<const DUContextDynamicData*>* recursionGuard) const
0169 {
0170     if (this == context->m_dynamicData)
0171         return true;
0172 
0173     if (recursionGuard->contains(this)) {
0174         return false;
0175     }
0176     recursionGuard->insert(this);
0177 
0178     FOREACH_FUNCTION(const DUContext::Import& ctx, d_func()->m_importedContexts) {
0179         DUContext* import = ctx.context(source);
0180         if (import == context || (import && import->m_dynamicData->imports(context, source, recursionGuard)))
0181             return true;
0182     }
0183 
0184     return false;
0185 }
0186 
0187 inline bool isContextTemporary(uint index)
0188 {
0189     return index > (0xffffffff / 2);
0190 }
0191 
0192 void DUContextDynamicData::addDeclaration(Declaration* newDeclaration)
0193 {
0194     // The definition may not have its identifier set when it's assigned...
0195     // allow dupes here, TODO catch the error elsewhere
0196 
0197     //If this context is temporary, added declarations should be as well, and viceversa
0198     Q_ASSERT(isContextTemporary(m_indexInTopContext) == isContextTemporary(newDeclaration->ownIndex()));
0199 
0200     CursorInRevision start = newDeclaration->range().start;
0201 
0202     bool inserted = false;
0203     ///@todo Do binary search to find the position
0204     for (int i = m_localDeclarations.size() - 1; i >= 0; --i) {
0205         Declaration* child = m_localDeclarations[i];
0206         Q_ASSERT(d_func()->m_localDeclarations()[i].data(m_topContext) == child);
0207         if (child == newDeclaration)
0208             return;
0209         //TODO: All declarations in a macro will have the same empty range, and just get appended
0210         //that may not be Good Enough in complex cases.
0211         if (start >= child->range().start) {
0212             m_localDeclarations.insert(i + 1, newDeclaration);
0213             d_func_dynamic()->m_localDeclarationsList().insert(i + 1, newDeclaration);
0214             Q_ASSERT(d_func()->m_localDeclarations()[i + 1].data(m_topContext) == newDeclaration);
0215 
0216             inserted = true;
0217             break;
0218         }
0219     }
0220 
0221     if (!inserted) {
0222         // We haven't found any child that is before this one, so prepend it
0223         m_localDeclarations.insert(0, newDeclaration);
0224         d_func_dynamic()->m_localDeclarationsList().insert(0, newDeclaration);
0225         Q_ASSERT(d_func()->m_localDeclarations()[0].data(m_topContext) == newDeclaration);
0226     }
0227 }
0228 
0229 bool DUContextDynamicData::removeDeclaration(Declaration* declaration)
0230 {
0231     const int idx = m_localDeclarations.indexOf(declaration);
0232     if (idx != -1) {
0233         Q_ASSERT(d_func()->m_localDeclarations()[idx].data(m_topContext) == declaration);
0234         m_localDeclarations.remove(idx);
0235         d_func_dynamic()->m_localDeclarationsList().remove(idx);
0236         return true;
0237     } else {
0238         Q_ASSERT(d_func_dynamic()->m_localDeclarationsList().indexOf(LocalIndexedDeclaration(declaration)) == -1);
0239         return false;
0240     }
0241 }
0242 
0243 void DUContextDynamicData::addChildContext(DUContext* context)
0244 {
0245     // Internal, don't need to assert a lock
0246     Q_ASSERT(!context->m_dynamicData->m_parentContext
0247              || context->m_dynamicData->m_parentContext.data()->m_dynamicData == this);
0248 
0249     LocalIndexedDUContext indexed(context->m_dynamicData->m_indexInTopContext);
0250 
0251     //If this context is temporary, added declarations should be as well, and viceversa
0252     Q_ASSERT(isContextTemporary(m_indexInTopContext) == isContextTemporary(indexed.localIndex()));
0253 
0254     bool inserted = false;
0255 
0256     int childCount = m_childContexts.size();
0257 
0258     for (int i = childCount - 1; i >= 0; --i) {///@todo Do binary search to find the position
0259         DUContext* child = m_childContexts[i];
0260         Q_ASSERT(d_func_dynamic()->m_childContexts()[i] == LocalIndexedDUContext(child));
0261         if (context == child)
0262             return;
0263         if (context->range().start >= child->range().start) {
0264             m_childContexts.insert(i + 1, context);
0265             d_func_dynamic()->m_childContextsList().insert(i + 1, indexed);
0266             context->m_dynamicData->m_parentContext = m_context;
0267             inserted = true;
0268             break;
0269         }
0270     }
0271 
0272     if (!inserted) {
0273         m_childContexts.insert(0, context);
0274         d_func_dynamic()->m_childContextsList().insert(0, indexed);
0275         context->m_dynamicData->m_parentContext = m_context;
0276     }
0277 }
0278 
0279 bool DUContextDynamicData::removeChildContext(DUContext* context)
0280 {
0281 //   ENSURE_CAN_WRITE
0282 
0283     const int idx = m_childContexts.indexOf(context);
0284     if (idx != -1) {
0285         m_childContexts.remove(idx);
0286         Q_ASSERT(d_func()->m_childContexts()[idx] == LocalIndexedDUContext(context));
0287         d_func_dynamic()->m_childContextsList().remove(idx);
0288         return true;
0289     } else {
0290         Q_ASSERT(d_func_dynamic()->m_childContextsList().indexOf(LocalIndexedDUContext(context)) == -1);
0291         return false;
0292     }
0293 }
0294 
0295 void DUContextDynamicData::addImportedChildContext(DUContext* context)
0296 {
0297 //   ENSURE_CAN_WRITE
0298     DUContext::Import import(m_context, context);
0299 
0300     if (import.isDirect()) {
0301         //Direct importers are registered directly within the data
0302         if (d_func_dynamic()->m_importersList().contains(IndexedDUContext(context))) {
0303             qCDebug(LANGUAGE) << m_context->scopeIdentifier(true).toString() << "importer added multiple times:" <<
0304                 context->scopeIdentifier(true).toString();
0305             return;
0306         }
0307 
0308         d_func_dynamic()->m_importersList().append(context);
0309     } else {
0310         //Indirect importers are registered separately
0311         Importers::self().addImporter(import.indirectDeclarationId(), IndexedDUContext(context));
0312     }
0313 }
0314 
0315 //Can also be called with a context that is not in the list
0316 void DUContextDynamicData::removeImportedChildContext(DUContext* context)
0317 {
0318 //   ENSURE_CAN_WRITE
0319     DUContext::Import import(m_context, context);
0320 
0321     if (import.isDirect()) {
0322         d_func_dynamic()->m_importersList().removeOne(IndexedDUContext(context));
0323     } else {
0324         //Indirect importers are registered separately
0325         Importers::self().removeImporter(import.indirectDeclarationId(), IndexedDUContext(context));
0326     }
0327 }
0328 
0329 int DUContext::depth() const
0330 {
0331     if (!parentContext()) {
0332         return 0;
0333     }
0334 
0335     return parentContext()->depth() + 1;
0336 }
0337 
0338 DUContext::DUContext(DUContextData& data)
0339     : DUChainBase(data)
0340     , m_dynamicData(new DUContextDynamicData(this))
0341 {
0342 }
0343 
0344 DUContext::DUContext(const RangeInRevision& range, DUContext* parent, bool anonymous)
0345     : DUChainBase(*new DUContextData(), range)
0346     , m_dynamicData(new DUContextDynamicData(this))
0347 {
0348     d_func_dynamic()->setClassId(this);
0349     if (parent)
0350         m_dynamicData->m_topContext = parent->topContext();
0351 
0352     d_func_dynamic()->setClassId(this);
0353     DUCHAIN_D_DYNAMIC(DUContext);
0354     d->m_contextType = Other;
0355     m_dynamicData->m_parentContext = nullptr;
0356 
0357     d->m_anonymousInParent = anonymous;
0358     d->m_inSymbolTable = false;
0359 
0360     if (parent) {
0361         m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this,
0362                                                                                                        parent->isAnonymous() ||
0363                                                                                                        anonymous);
0364         Q_ASSERT(m_dynamicData->m_indexInTopContext);
0365 
0366         if (!anonymous)
0367             parent->m_dynamicData->addChildContext(this);
0368         else
0369             m_dynamicData->m_parentContext = parent;
0370     }
0371 
0372     if (parent && !anonymous && parent->inSymbolTable())
0373         setInSymbolTable(true);
0374 }
0375 
0376 bool DUContext::isAnonymous() const
0377 {
0378     return d_func()->m_anonymousInParent ||
0379            (m_dynamicData->m_parentContext && m_dynamicData->m_parentContext->isAnonymous());
0380 }
0381 
0382 void DUContext::initFromTopContext()
0383 {
0384     Q_ASSERT(dynamic_cast<TopDUContext*>(this));
0385     m_dynamicData->m_topContext = static_cast<TopDUContext*>(this);
0386 }
0387 
0388 DUContext::DUContext(DUContextData& dd, const RangeInRevision& range, DUContext* parent, bool anonymous)
0389     : DUChainBase(dd, range)
0390     , m_dynamicData(new DUContextDynamicData(this))
0391 {
0392     if (parent)
0393         m_dynamicData->m_topContext = parent->topContext();
0394     // else initTopContext must be called, doing a static_cast here is UB
0395 
0396     DUCHAIN_D_DYNAMIC(DUContext);
0397     d->m_contextType = Other;
0398     m_dynamicData->m_parentContext = nullptr;
0399     d->m_inSymbolTable = false;
0400     d->m_anonymousInParent = anonymous;
0401     if (parent) {
0402         m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this,
0403                                                                                                        parent->isAnonymous() ||
0404                                                                                                        anonymous);
0405 
0406         if (!anonymous)
0407             parent->m_dynamicData->addChildContext(this);
0408         else
0409             m_dynamicData->m_parentContext = parent;
0410     }
0411 }
0412 
0413 DUContext::DUContext(DUContext& useDataFrom)
0414     : DUChainBase(useDataFrom)
0415     , m_dynamicData(useDataFrom.m_dynamicData)
0416 {
0417 }
0418 
0419 DUContext::~DUContext()
0420 {
0421     TopDUContext* top = topContext();
0422 
0423     if (top != this) {
0424         const auto doCleanup = !top->deleting() || !top->isOnDisk();
0425 
0426         if (doCleanup) {
0427             DUCHAIN_D_DYNAMIC(DUContext);
0428 
0429             if (d->m_owner.declaration())
0430                 d->m_owner.declaration()->setInternalContext(nullptr);
0431 
0432             while (d->m_importersSize() != 0) {
0433                 if (d->m_importers()[0].data())
0434                     d->m_importers()[0].data()->removeImportedParentContext(this);
0435                 else {
0436                     qCDebug(LANGUAGE) << "importer disappeared";
0437                     d->m_importersList().removeOne(d->m_importers()[0]);
0438                 }
0439             }
0440 
0441             clearImportedParentContexts();
0442         }
0443 
0444         deleteChildContextsRecursively();
0445 
0446         if (doCleanup)
0447             deleteUses();
0448 
0449         deleteLocalDeclarations();
0450 
0451         //If the top-context is being delete, we don't need to spend time rebuilding the inner structure.
0452         //That's expensive, especially when the data is not dynamic.
0453         if (doCleanup && m_dynamicData->m_parentContext) {
0454             m_dynamicData->m_parentContext->m_dynamicData->removeChildContext(this);
0455         }
0456 
0457         top->m_dynamicData->clearContextIndex(this);
0458 
0459         Q_ASSERT(d_func()->isDynamic() ==
0460                 (doCleanup ||
0461                 top->m_dynamicData->isTemporaryContextIndex(m_dynamicData->m_indexInTopContext)));
0462     }
0463 
0464     delete m_dynamicData;
0465 }
0466 
0467 QVector<DUContext*> DUContext::childContexts() const
0468 {
0469     ENSURE_CAN_READ
0470 
0471     return m_dynamicData->m_childContexts;
0472 }
0473 
0474 Declaration* DUContext::owner() const
0475 {
0476     ENSURE_CAN_READ
0477     return d_func()->m_owner.declaration();
0478 }
0479 
0480 void DUContext::setOwner(Declaration* owner)
0481 {
0482     ENSURE_CAN_WRITE
0483         DUCHAIN_D_DYNAMIC(DUContext);
0484     if (owner == d->m_owner.declaration())
0485         return;
0486 
0487     Declaration* oldOwner = d->m_owner.declaration();
0488 
0489     d->m_owner = owner;
0490 
0491     //Q_ASSERT(!oldOwner || oldOwner->internalContext() == this);
0492     if (oldOwner && oldOwner->internalContext() == this)
0493         oldOwner->setInternalContext(nullptr);
0494 
0495     //The context set as internal context should always be the last opened context
0496     if (owner)
0497         owner->setInternalContext(this);
0498 }
0499 
0500 DUContext* DUContext::parentContext() const
0501 {
0502     //ENSURE_CAN_READ Commented out for performance reasons
0503 
0504     return m_dynamicData->m_parentContext.data();
0505 }
0506 
0507 void DUContext::setPropagateDeclarations(bool propagate)
0508 {
0509     ENSURE_CAN_WRITE
0510         DUCHAIN_D_DYNAMIC(DUContext);
0511 
0512     if (propagate == d->m_propagateDeclarations)
0513         return;
0514 
0515     d->m_propagateDeclarations = propagate;
0516 }
0517 
0518 bool DUContext::isPropagateDeclarations() const
0519 {
0520     return d_func()->m_propagateDeclarations;
0521 }
0522 
0523 QList<Declaration*> DUContext::findLocalDeclarations(const IndexedIdentifier& identifier,
0524                                                      const CursorInRevision& position,
0525                                                      const TopDUContext* topContext,
0526                                                      const AbstractType::Ptr& dataType,
0527                                                      SearchFlags flags) const
0528 {
0529     ENSURE_CAN_READ
0530 
0531     DeclarationList ret;
0532     findLocalDeclarationsInternal(identifier,
0533                                   position.isValid() ? position : range().end, dataType, ret,
0534                                   topContext ? topContext : this->topContext(), flags);
0535     return ret;
0536 }
0537 
0538 QList<Declaration*> DUContext::findLocalDeclarations(const Identifier& identifier,
0539                                                      const CursorInRevision& position,
0540                                                      const TopDUContext* topContext,
0541                                                      const AbstractType::Ptr& dataType,
0542                                                      SearchFlags flags) const
0543 {
0544     return findLocalDeclarations(IndexedIdentifier(identifier), position, topContext, dataType, flags);
0545 }
0546 
0547 namespace {
0548 bool contextIsChildOrEqual(const DUContext* childContext, const DUContext* context)
0549 {
0550     if (childContext == context)
0551         return true;
0552 
0553     if (childContext->parentContext())
0554         return contextIsChildOrEqual(childContext->parentContext(), context);
0555     else
0556         return false;
0557 }
0558 
0559 struct Checker
0560 {
0561     Checker(DUContext::SearchFlags flags, const AbstractType::Ptr& dataType,
0562             const CursorInRevision& position, DUContext::ContextType ownType)
0563         : m_flags(flags)
0564         , m_dataType(dataType)
0565         , m_position(position)
0566         , m_ownType(ownType)
0567     {
0568     }
0569 
0570     Declaration* check(Declaration* declaration) const
0571     {
0572         ///@todo This is C++-specific
0573         if (m_ownType != DUContext::Class && m_ownType != DUContext::Template
0574             && m_position.isValid() && m_position <= declaration->range().start) {
0575             return nullptr;
0576         }
0577 
0578         if (declaration->kind() == Declaration::Alias && !(m_flags & DUContext::DontResolveAliases)) {
0579             //Apply alias declarations
0580             auto* alias = static_cast<AliasDeclaration*>(declaration);
0581             if (alias->aliasedDeclaration().isValid()) {
0582                 declaration = alias->aliasedDeclaration().declaration();
0583             } else {
0584                 qCDebug(LANGUAGE) << "lost aliased declaration";
0585             }
0586         }
0587 
0588         if (declaration->kind() == Declaration::NamespaceAlias && !(m_flags & DUContext::NoFiltering)) {
0589             return nullptr;
0590         }
0591 
0592         if (( m_flags& DUContext::OnlyFunctions ) && !declaration->isFunctionDeclaration()) {
0593             return nullptr;
0594         }
0595 
0596         if (m_dataType && m_dataType->indexed() != declaration->indexedType()) {
0597             return nullptr;
0598         }
0599 
0600         return declaration;
0601     }
0602 
0603     DUContext::SearchFlags m_flags;
0604     const AbstractType::Ptr m_dataType;
0605     const CursorInRevision m_position;
0606     DUContext::ContextType m_ownType;
0607 };
0608 }
0609 
0610 void DUContext::findLocalDeclarationsInternal(const Identifier& identifier, const CursorInRevision& position,
0611                                               const AbstractType::Ptr& dataType, DeclarationList& ret,
0612                                               const TopDUContext* source, SearchFlags flags) const
0613 {
0614     findLocalDeclarationsInternal(IndexedIdentifier(identifier), position, dataType, ret, source, flags);
0615 }
0616 
0617 void DUContext::findLocalDeclarationsInternal(const IndexedIdentifier& identifier,
0618                                               const CursorInRevision& position,
0619                                               const AbstractType::Ptr& dataType,
0620                                               DeclarationList& ret, const TopDUContext* /*source*/,
0621                                               SearchFlags flags) const
0622 {
0623     Checker checker(flags, dataType, position, type());
0624 
0625     DUCHAIN_D(DUContext);
0626     if (d->m_inSymbolTable && !d->m_scopeIdentifier.isEmpty() && !identifier.isEmpty()) {
0627         //This context is in the symbol table, use the symbol-table to speed up the search
0628         QualifiedIdentifier id(scopeIdentifier(true) + identifier);
0629 
0630         TopDUContext* top = topContext();
0631 
0632         PersistentSymbolTable::self().visitDeclarations(id, [&](const IndexedDeclaration& indexedDecl) {
0633             ///@todo Eventually do efficient iteration-free filtering
0634             if (indexedDecl.topContextIndex() == top->ownIndex()) {
0635                 Declaration* decl = indexedDecl.declaration();
0636                 if (decl && contextIsChildOrEqual(decl->context(), this)) {
0637                     Declaration* checked = checker.check(decl);
0638                     if (checked) {
0639                         ret.append(checked);
0640                     }
0641                 }
0642             }
0643             return PersistentSymbolTable::VisitorState::Continue;
0644         });
0645     } else {
0646         //Iterate through all declarations
0647         DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
0648         while (it) {
0649             Declaration* declaration = *it;
0650             if (declaration && declaration->indexedIdentifier() == identifier) {
0651                 Declaration* checked = checker.check(declaration);
0652                 if (checked)
0653                     ret.append(checked);
0654             }
0655             ++it;
0656         }
0657     }
0658 }
0659 
0660 bool DUContext::foundEnough(const DeclarationList& ret, SearchFlags flags) const
0661 {
0662     if (!ret.isEmpty() && !(flags & DUContext::NoFiltering))
0663         return true;
0664     else
0665         return false;
0666 }
0667 
0668 bool DUContext::findDeclarationsInternal(const SearchItem::PtrList& baseIdentifiers,
0669                                          const CursorInRevision& position,
0670                                          const AbstractType::Ptr& dataType,
0671                                          DeclarationList& ret, const TopDUContext* source,
0672                                          SearchFlags flags, uint depth) const
0673 {
0674     if (depth > maxParentDepth) {
0675         qCDebug(LANGUAGE) << "maximum depth reached in" << scopeIdentifier(true);
0676         return false;
0677     }
0678 
0679     DUCHAIN_D(DUContext);
0680     if (d->m_contextType != Namespace) {
0681         // If we're in a namespace, delay all the searching into the top-context, because only that has the overview to pick the correct declarations.
0682         for (auto& baseIdentifier : baseIdentifiers) {
0683             if (!baseIdentifier->isExplicitlyGlobal && baseIdentifier->next.isEmpty()) {
0684                 // It makes no sense searching locally for qualified identifiers
0685                 findLocalDeclarationsInternal(baseIdentifier->identifier, position, dataType, ret, source, flags);
0686             }
0687         }
0688 
0689         if (foundEnough(ret, flags)) {
0690             return true;
0691         }
0692     }
0693 
0694     ///Step 1: Apply namespace-aliases and -imports
0695     SearchItem::PtrList aliasedIdentifiers;
0696     //Because of namespace-imports and aliases, this identifier may need to be searched under multiple names
0697     applyAliases(baseIdentifiers, aliasedIdentifiers, position, false,
0698                  type() != DUContext::Namespace && type() != DUContext::Global);
0699 
0700     if (d->m_importedContextsSize() != 0) {
0701         ///Step 2: Give identifiers that are not marked as explicitly-global to imported contexts(explicitly global ones are treatead in TopDUContext)
0702         SearchItem::PtrList nonGlobalIdentifiers;
0703         for (const SearchItem::Ptr& identifier : qAsConst(aliasedIdentifiers)) {
0704             if (!identifier->isExplicitlyGlobal) {
0705                 nonGlobalIdentifiers << identifier;
0706             }
0707         }
0708 
0709         if (!nonGlobalIdentifiers.isEmpty()) {
0710             const auto& url = this->url();
0711             for (int import = d->m_importedContextsSize() - 1; import >= 0; --import) {
0712                 if (position.isValid() && d->m_importedContexts()[import].position.isValid() &&
0713                     position < d->m_importedContexts()[import].position) {
0714                     continue;
0715                 }
0716 
0717                 DUContext* context = d->m_importedContexts()[import].context(source);
0718 
0719                 if (!context) {
0720                     continue;
0721                 } else if (context == this) {
0722                     qCDebug(LANGUAGE) << "resolved self as import:" << scopeIdentifier(true);
0723                     continue;
0724                 }
0725 
0726                 if (!context->findDeclarationsInternal(nonGlobalIdentifiers,
0727                                                        url == context->url() ? position : context->range().end,
0728                                                        dataType, ret, source, flags | InImportedParentContext,
0729                                                        depth + 1)) {
0730                     return false;
0731                 }
0732             }
0733         }
0734     }
0735 
0736     if (foundEnough(ret, flags)) {
0737         return true;
0738     }
0739 
0740     ///Step 3: Continue search in parent-context
0741     if (!(flags & DontSearchInParent) && shouldSearchInParent(flags) && m_dynamicData->m_parentContext) {
0742         applyUpwardsAliases(aliasedIdentifiers, source);
0743         return m_dynamicData->m_parentContext->findDeclarationsInternal(aliasedIdentifiers,
0744                                                                         url() == m_dynamicData->m_parentContext->url() ? position : m_dynamicData->m_parentContext->range().end,
0745                                                                         dataType, ret, source, flags, depth);
0746     }
0747     return true;
0748 }
0749 
0750 QVector<QualifiedIdentifier> DUContext::fullyApplyAliases(const QualifiedIdentifier& id,
0751                                                           const TopDUContext* source) const
0752 {
0753     ENSURE_CAN_READ
0754 
0755     if (!source)
0756         source = topContext();
0757 
0758     SearchItem::PtrList identifiers;
0759     identifiers << SearchItem::Ptr(new SearchItem(id));
0760 
0761     const DUContext* current = this;
0762     while (current) {
0763         SearchItem::PtrList aliasedIdentifiers;
0764         current->applyAliases(identifiers, aliasedIdentifiers, CursorInRevision::invalid(), true, false);
0765         current->applyUpwardsAliases(identifiers, source);
0766 
0767         current = current->parentContext();
0768     }
0769 
0770     QVector<QualifiedIdentifier> ret;
0771     for (const SearchItem::Ptr& item : qAsConst(identifiers)) {
0772         ret += item->toList();
0773     }
0774 
0775     return ret;
0776 }
0777 
0778 QList<Declaration*> DUContext::findDeclarations(const QualifiedIdentifier& identifier,
0779                                                 const CursorInRevision& position,
0780                                                 const AbstractType::Ptr& dataType,
0781                                                 const TopDUContext* topContext, SearchFlags flags) const
0782 {
0783     ENSURE_CAN_READ
0784 
0785     DeclarationList ret;
0786     // optimize: we don't want to allocate the top node always
0787     // so create it on stack but ref it so its not deleted by the smart pointer
0788     SearchItem item(identifier);
0789     item.ref.ref();
0790 
0791     SearchItem::PtrList identifiers{SearchItem::Ptr(&item)};
0792 
0793     findDeclarationsInternal(identifiers,
0794                              position.isValid() ? position : range().end, dataType, ret,
0795                              topContext ? topContext : this->topContext(), flags, 0);
0796 
0797     return ret;
0798 }
0799 
0800 bool DUContext::imports(const DUContext* origin, const CursorInRevision& /*position*/) const
0801 {
0802     ENSURE_CAN_READ
0803 
0804     QSet<const DUContextDynamicData*> recursionGuard;
0805     recursionGuard.reserve(8);
0806     return m_dynamicData->imports(origin, topContext(), &recursionGuard);
0807 }
0808 
0809 bool DUContext::addIndirectImport(const DUContext::Import& import)
0810 {
0811     ENSURE_CAN_WRITE
0812         DUCHAIN_D_DYNAMIC(DUContext);
0813 
0814     for (unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
0815         if (d->m_importedContexts()[a] == import) {
0816             d->m_importedContextsList()[a].position = import.position;
0817             return true;
0818         }
0819     }
0820 
0821     ///Do not sort the imported contexts by their own line-number, it makes no sense.
0822     ///Contexts added first, aka template-contexts, should stay in first place, so they are searched first.
0823 
0824     d->m_importedContextsList().append(import);
0825     return false;
0826 }
0827 
0828 void DUContext::addImportedParentContext(DUContext* context, const CursorInRevision& position, bool anonymous,
0829                                          bool /*temporary*/)
0830 {
0831     ENSURE_CAN_WRITE
0832 
0833     if (context == this) {
0834         qCDebug(LANGUAGE) << "Tried to import self";
0835         return;
0836     }
0837     if (!context) {
0838         qCDebug(LANGUAGE) << "Tried to import invalid context";
0839         return;
0840     }
0841 
0842     Import import(context, this, position);
0843     if (addIndirectImport(import))
0844         return;
0845 
0846     if (!anonymous) {
0847         ENSURE_CAN_WRITE_(context)
0848         context->m_dynamicData->addImportedChildContext(this);
0849     }
0850 }
0851 
0852 void DUContext::removeImportedParentContext(DUContext* context)
0853 {
0854     ENSURE_CAN_WRITE
0855         DUCHAIN_D_DYNAMIC(DUContext);
0856 
0857     Import import(context, this, CursorInRevision::invalid());
0858 
0859     for (unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
0860         if (d->m_importedContexts()[a] == import) {
0861             d->m_importedContextsList().remove(a);
0862             break;
0863         }
0864     }
0865 
0866     if (!context)
0867         return;
0868 
0869     context->m_dynamicData->removeImportedChildContext(this);
0870 }
0871 
0872 KDevVarLengthArray<IndexedDUContext> DUContext::indexedImporters() const
0873 {
0874     KDevVarLengthArray<IndexedDUContext> ret;
0875     if (owner())
0876         ret = Importers::self().importers(owner()->id()); //Add indirect importers to the list
0877 
0878     FOREACH_FUNCTION(const IndexedDUContext &ctx, d_func()->m_importers)
0879     ret.append(ctx);
0880 
0881     return ret;
0882 }
0883 
0884 QVector<DUContext*> DUContext::importers() const
0885 {
0886     ENSURE_CAN_READ
0887 
0888     QVector<DUContext*> ret;
0889     ret.reserve(d_func()->m_importersSize());
0890     FOREACH_FUNCTION(const IndexedDUContext &ctx, d_func()->m_importers)
0891     ret << ctx.context();
0892 
0893     if (owner()) {
0894         //Add indirect importers to the list
0895         const KDevVarLengthArray<IndexedDUContext> indirect = Importers::self().importers(owner()->id());
0896         ret.reserve(ret.size() + indirect.size());
0897         for (const IndexedDUContext ctx : indirect) {
0898             ret << ctx.context();
0899         }
0900     }
0901 
0902     return ret;
0903 }
0904 
0905 DUContext* DUContext::findContext(const CursorInRevision& position, DUContext* parent) const
0906 {
0907     ENSURE_CAN_READ
0908 
0909     if (!parent)
0910         parent = const_cast<DUContext*>(this);
0911 
0912     for (DUContext* context : qAsConst(parent->m_dynamicData->m_childContexts)) {
0913         if (context->range().contains(position)) {
0914             DUContext* ret = findContext(position, context);
0915             if (!ret) {
0916                 ret = context;
0917             }
0918 
0919             return ret;
0920         }
0921     }
0922 
0923     return nullptr;
0924 }
0925 
0926 bool DUContext::parentContextOf(DUContext* context) const
0927 {
0928     if (this == context)
0929         return true;
0930 
0931     const auto& childContexts = m_dynamicData->m_childContexts;
0932     return std::any_of(childContexts.begin(), childContexts.end(), [&](DUContext* child) {
0933         return child->parentContextOf(context);
0934     });
0935 }
0936 
0937 QVector<QPair<Declaration*, int>> DUContext::allDeclarations(const CursorInRevision& position,
0938                                                              const TopDUContext* topContext,
0939                                                              bool searchInParents) const
0940 {
0941     ENSURE_CAN_READ
0942 
0943     QVector<QPair<Declaration*, int>> ret;
0944 
0945     QHash<const DUContext*, bool> hadContexts;
0946     // Iterate back up the chain
0947     mergeDeclarationsInternal(ret, position, hadContexts, topContext ? topContext : this->topContext(),
0948                               searchInParents);
0949 
0950     return ret;
0951 }
0952 
0953 QVector<Declaration*> DUContext::localDeclarations(const TopDUContext* source) const
0954 {
0955     ENSURE_CAN_READ
0956     // TODO: remove this parameter once we kill old-cpp
0957         Q_UNUSED(source);
0958     return m_dynamicData->m_localDeclarations;
0959 }
0960 
0961 void DUContext::mergeDeclarationsInternal(QVector<QPair<Declaration*, int>>& definitions,
0962                                           const CursorInRevision& position,
0963                                           QHash<const DUContext*, bool>& hadContexts,
0964                                           const TopDUContext* source,
0965                                           bool searchInParents, int currentDepth) const
0966 {
0967     ENSURE_CAN_READ
0968 
0969     if ((currentDepth > 300 && currentDepth < 1000) || currentDepth > 1300) {
0970         qCDebug(LANGUAGE) << "too much depth";
0971         return;
0972     }
0973     DUCHAIN_D(DUContext);
0974 
0975     if (hadContexts.contains(this) && !searchInParents)
0976         return;
0977 
0978     if (!hadContexts.contains(this)) {
0979         hadContexts[this] = true;
0980 
0981         if ((type() == DUContext::Namespace || type() == DUContext::Global) && currentDepth < 1000)
0982             currentDepth += 1000;
0983 
0984         {
0985             DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
0986             while (it) {
0987                 Declaration* decl = *it;
0988 
0989                 if (decl && (!position.isValid() || decl->range().start <= position))
0990                     definitions << qMakePair(decl, currentDepth);
0991                 ++it;
0992             }
0993         }
0994 
0995         for (int a = d->m_importedContextsSize() - 1; a >= 0; --a) {
0996             const Import* import(&d->m_importedContexts()[a]);
0997             DUContext* context = import->context(source);
0998             while (!context && a > 0) {
0999                 --a;
1000                 import = &d->m_importedContexts()[a];
1001                 context = import->context(source);
1002             }
1003             if (!context)
1004                 break;
1005 
1006             if (context == this) {
1007                 qCDebug(LANGUAGE) << "resolved self as import:" << scopeIdentifier(true);
1008                 continue;
1009             }
1010 
1011             if (position.isValid() && import->position.isValid() && position < import->position)
1012                 continue;
1013 
1014             context->mergeDeclarationsInternal(definitions,
1015                                                CursorInRevision::invalid(), hadContexts, source,
1016                                                searchInParents && context->shouldSearchInParent(
1017                                                    InImportedParentContext) &&  context->parentContext()->type() == DUContext::Helper,
1018                                                currentDepth + 1);
1019         }
1020     }
1021 
1022     ///Only respect the position if the parent-context is not a class(@todo this is language-dependent)
1023     if (parentContext() && searchInParents)
1024         parentContext()->mergeDeclarationsInternal(definitions,
1025                                                    parentContext()->type() == DUContext::Class ? parentContext()->range().end : position, hadContexts, source, searchInParents,
1026                                                    currentDepth + 1);
1027 }
1028 
1029 void DUContext::deleteLocalDeclarations()
1030 {
1031     ENSURE_CAN_WRITE
1032     // It may happen that the deletion of one declaration triggers the deletion of another one
1033     // Therefore we copy the list of indexed declarations and work on those. Indexed declarations
1034     // will return zero for already deleted declarations.
1035     KDevVarLengthArray<LocalIndexedDeclaration> indexedLocal;
1036     if (d_func()->m_localDeclarations()) {
1037         indexedLocal.append(d_func()->m_localDeclarations(), d_func()->m_localDeclarationsSize());
1038     }
1039     for (const LocalIndexedDeclaration& indexed : indexedLocal) {
1040         delete indexed.data(topContext());
1041     }
1042 
1043     m_dynamicData->m_localDeclarations.clear();
1044 }
1045 
1046 void DUContext::deleteChildContextsRecursively()
1047 {
1048     ENSURE_CAN_WRITE
1049 
1050     // note: operate on copy here because child ctx deletion changes m_dynamicData->m_childContexts
1051     const auto currentChildContexts = m_dynamicData->m_childContexts;
1052     qDeleteAll(currentChildContexts);
1053 
1054     m_dynamicData->m_childContexts.clear();
1055 }
1056 
1057 QVector<Declaration*> DUContext::clearLocalDeclarations()
1058 {
1059     auto copy = m_dynamicData->m_localDeclarations;
1060     for (Declaration* dec : qAsConst(copy)) {
1061         dec->setContext(nullptr);
1062     }
1063 
1064     return copy;
1065 }
1066 
1067 QualifiedIdentifier DUContext::scopeIdentifier(bool includeClasses) const
1068 {
1069     ENSURE_CAN_READ
1070 
1071     QualifiedIdentifier ret;
1072     m_dynamicData->scopeIdentifier(includeClasses, ret);
1073 
1074     return ret;
1075 }
1076 
1077 bool DUContext::equalScopeIdentifier(const DUContext* rhs) const
1078 {
1079     ENSURE_CAN_READ
1080 
1081     const DUContext* left = this;
1082     const DUContext* right = rhs;
1083 
1084     while (left || right) {
1085         if (!left || !right)
1086             return false;
1087 
1088         if (!(left->d_func()->m_scopeIdentifier == right->d_func()->m_scopeIdentifier))
1089             return false;
1090 
1091         left = left->parentContext();
1092         right = right->parentContext();
1093     }
1094 
1095     return true;
1096 }
1097 
1098 void DUContext::setLocalScopeIdentifier(const QualifiedIdentifier& identifier)
1099 {
1100     ENSURE_CAN_WRITE
1101     bool wasInSymbolTable = inSymbolTable();
1102     setInSymbolTable(false);
1103     d_func_dynamic()->m_scopeIdentifier = identifier;
1104     setInSymbolTable(wasInSymbolTable);
1105 }
1106 
1107 QualifiedIdentifier DUContext::localScopeIdentifier() const
1108 {
1109     //ENSURE_CAN_READ Commented out for performance reasons
1110 
1111     return d_func()->m_scopeIdentifier;
1112 }
1113 
1114 IndexedQualifiedIdentifier DUContext::indexedLocalScopeIdentifier() const
1115 {
1116     return d_func()->m_scopeIdentifier;
1117 }
1118 
1119 DUContext::ContextType DUContext::type() const
1120 {
1121     //ENSURE_CAN_READ This is disabled, because type() is called very often while searching, and it costs us performance
1122 
1123     return d_func()->m_contextType;
1124 }
1125 
1126 void DUContext::setType(ContextType type)
1127 {
1128     ENSURE_CAN_WRITE
1129 
1130         d_func_dynamic()->m_contextType = type;
1131 }
1132 
1133 QList<Declaration*> DUContext::findDeclarations(const Identifier& identifier, const CursorInRevision& position,
1134                                                 const TopDUContext* topContext, SearchFlags flags) const
1135 {
1136     return findDeclarations(IndexedIdentifier(identifier), position, topContext, flags);
1137 }
1138 
1139 QList<Declaration*> DUContext::findDeclarations(const IndexedIdentifier& identifier, const CursorInRevision& position,
1140                                                 const TopDUContext* topContext, SearchFlags flags) const
1141 {
1142     ENSURE_CAN_READ
1143 
1144     DeclarationList ret;
1145     SearchItem::PtrList identifiers;
1146     identifiers << SearchItem::Ptr(new SearchItem(false, identifier, SearchItem::PtrList()));
1147     findDeclarationsInternal(identifiers, position.isValid() ? position : range().end,
1148                              AbstractType::Ptr(), ret, topContext ? topContext : this->topContext(), flags, 0);
1149     return ret;
1150 }
1151 
1152 void DUContext::deleteUse(int index)
1153 {
1154     ENSURE_CAN_WRITE
1155         DUCHAIN_D_DYNAMIC(DUContext);
1156     d->m_usesList().remove(index);
1157 }
1158 
1159 void DUContext::deleteUses()
1160 {
1161     ENSURE_CAN_WRITE
1162 
1163         DUCHAIN_D_DYNAMIC(DUContext);
1164     d->m_usesList().clear();
1165 }
1166 
1167 void DUContext::deleteUsesRecursively()
1168 {
1169     deleteUses();
1170 
1171     for (DUContext* childContext : qAsConst(m_dynamicData->m_childContexts)) {
1172         childContext->deleteUsesRecursively();
1173     }
1174 }
1175 
1176 bool DUContext::inDUChain() const
1177 {
1178     if (d_func()->m_anonymousInParent || !m_dynamicData->m_parentContext)
1179         return false;
1180 
1181     TopDUContext* top = topContext();
1182     return top && top->inDUChain();
1183 }
1184 
1185 DUContext* DUContext::specialize(const IndexedInstantiationInformation& /*specialization*/,
1186                                  const TopDUContext* topContext, int /*upDistance*/)
1187 {
1188     if (!topContext)
1189         return nullptr;
1190     return this;
1191 }
1192 
1193 CursorInRevision DUContext::importPosition(const DUContext* target) const
1194 {
1195     ENSURE_CAN_READ
1196         DUCHAIN_D(DUContext);
1197     Import import(const_cast<DUContext*>(target), this, CursorInRevision::invalid());
1198     for (unsigned int a = 0; a < d->m_importedContextsSize(); ++a)
1199         if (d->m_importedContexts()[a] == import)
1200             return d->m_importedContexts()[a].position;
1201 
1202     return CursorInRevision::invalid();
1203 }
1204 
1205 QVector<DUContext::Import> DUContext::importedParentContexts() const
1206 {
1207     ENSURE_CAN_READ
1208     QVector<DUContext::Import> ret;
1209     ret.reserve(d_func()->m_importedContextsSize());
1210     FOREACH_FUNCTION(const DUContext::Import& import, d_func()->m_importedContexts)
1211     ret << import;
1212     return ret;
1213 }
1214 
1215 void DUContext::applyAliases(const SearchItem::PtrList& baseIdentifiers, SearchItem::PtrList& identifiers,
1216                              const CursorInRevision& position, bool canBeNamespace, bool onlyImports) const
1217 {
1218     DeclarationList imports;
1219     findLocalDeclarationsInternal(globalIndexedImportIdentifier(), position, AbstractType::Ptr(), imports,
1220                                   topContext(), DUContext::NoFiltering);
1221 
1222     if (imports.isEmpty() && onlyImports) {
1223         identifiers = baseIdentifiers;
1224         return;
1225     }
1226 
1227     for (const SearchItem::Ptr& identifier : baseIdentifiers) {
1228         bool addUnmodified = true;
1229 
1230         if (!identifier->isExplicitlyGlobal) {
1231             if (!imports.isEmpty()) {
1232                 //We have namespace-imports.
1233                 for (Declaration* importDecl : qAsConst(imports)) {
1234                     //Search for the identifier with the import-identifier prepended
1235                     if (dynamic_cast<NamespaceAliasDeclaration*>(importDecl)) {
1236                         auto* alias = static_cast<NamespaceAliasDeclaration*>(importDecl);
1237                         identifiers.append(SearchItem::Ptr(new SearchItem(alias->importIdentifier(), identifier)));
1238                     } else {
1239                         qCDebug(LANGUAGE) << "Declaration with namespace alias identifier has the wrong type" <<
1240                             importDecl->url().str() << importDecl->range().castToSimpleRange();
1241                     }
1242                 }
1243             }
1244 
1245             if (!identifier->isEmpty() && (identifier->hasNext() || canBeNamespace)) {
1246                 DeclarationList aliases;
1247                 findLocalDeclarationsInternal(identifier->identifier, position,
1248                                               AbstractType::Ptr(), imports, nullptr, DUContext::NoFiltering);
1249 
1250                 if (!aliases.isEmpty()) {
1251                     //The first part of the identifier has been found as a namespace-alias.
1252                     //In c++, we only need the first alias. However, just to be correct, follow them all for now.
1253                     for (Declaration* aliasDecl : qAsConst(aliases)) {
1254                         if (!dynamic_cast<NamespaceAliasDeclaration*>(aliasDecl))
1255                             continue;
1256 
1257                         addUnmodified = false; //The un-modified identifier can be ignored, because it will be replaced with the resolved alias
1258                         auto* alias = static_cast<NamespaceAliasDeclaration*>(aliasDecl);
1259 
1260                         //Create an identifier where namespace-alias part is replaced with the alias target
1261                         identifiers.append(SearchItem::Ptr(new SearchItem(alias->importIdentifier(),
1262                                                                           identifier->next)));
1263                     }
1264                 }
1265             }
1266         }
1267 
1268         if (addUnmodified)
1269             identifiers.append(identifier);
1270     }
1271 }
1272 
1273 void DUContext::applyUpwardsAliases(SearchItem::PtrList& identifiers, const TopDUContext* /*source*/) const
1274 {
1275     if (type() == Namespace) {
1276         if (d_func()->m_scopeIdentifier.isEmpty())
1277             return;
1278 
1279         //Make sure we search for the items in all namespaces of the same name, by duplicating each one with the namespace-identifier prepended.
1280         //We do this by prepending items to the current identifiers that equal the local scope identifier.
1281         SearchItem::Ptr newItem(new SearchItem(d_func()->m_scopeIdentifier.identifier()));
1282 
1283         //This will exclude explicitly global identifiers
1284         newItem->addToEachNode(identifiers);
1285 
1286         if (!newItem->next.isEmpty()) {
1287             //Prepend the full scope before newItem
1288             DUContext* parent = m_dynamicData->m_parentContext.data();
1289             while (parent) {
1290                 newItem = SearchItem::Ptr(new SearchItem(parent->d_func()->m_scopeIdentifier, newItem));
1291                 parent = parent->m_dynamicData->m_parentContext.data();
1292             }
1293 
1294             newItem->isExplicitlyGlobal = true;
1295             identifiers.insert(0, newItem);
1296         }
1297     }
1298 }
1299 
1300 bool DUContext::shouldSearchInParent(SearchFlags flags) const
1301 {
1302     return (parentContext() && parentContext()->type() == DUContext::Helper && (flags & InImportedParentContext))
1303            || !(flags & InImportedParentContext);
1304 }
1305 
1306 const Use* DUContext::uses() const
1307 {
1308     ENSURE_CAN_READ
1309 
1310     return d_func()->m_uses();
1311 }
1312 
1313 bool DUContext::declarationHasUses(Declaration* decl)
1314 {
1315     return DUChain::uses()->hasUses(decl->id());
1316 }
1317 
1318 int DUContext::usesCount() const
1319 {
1320     return d_func()->m_usesSize();
1321 }
1322 
1323 bool usesRangeLessThan(const Use& left, const Use& right)
1324 {
1325     return left.m_range.start < right.m_range.start;
1326 }
1327 
1328 int DUContext::createUse(int declarationIndex, const RangeInRevision& range, int insertBefore)
1329 {
1330     DUCHAIN_D_DYNAMIC(DUContext);
1331     ENSURE_CAN_WRITE
1332 
1333     Use use(range, declarationIndex);
1334     if (insertBefore == -1) {
1335         //Find position where to insert
1336         const unsigned int size = d->m_usesSize();
1337         const Use* uses = d->m_uses();
1338         const Use* lowerBound = std::lower_bound(uses, uses + size, use, usesRangeLessThan);
1339         insertBefore = lowerBound - uses;
1340         // comment out to test this:
1341         /*
1342            unsigned int a = 0;
1343            for(; a < size && range.start > uses[a].m_range.start; ++a) {
1344            }
1345            Q_ASSERT(a == insertBefore);
1346          */
1347     }
1348 
1349     d->m_usesList().insert(insertBefore, use);
1350 
1351     return insertBefore;
1352 }
1353 
1354 void DUContext::changeUseRange(int useIndex, const RangeInRevision& range)
1355 {
1356     ENSURE_CAN_WRITE
1357         d_func_dynamic()->m_usesList()[useIndex].m_range = range;
1358 }
1359 
1360 void DUContext::setUseDeclaration(int useNumber, int declarationIndex)
1361 {
1362     ENSURE_CAN_WRITE
1363         d_func_dynamic()->m_usesList()[useNumber].m_declarationIndex = declarationIndex;
1364 }
1365 
1366 DUContext* DUContext::findContextAt(const CursorInRevision& position, bool includeRightBorder) const
1367 {
1368     ENSURE_CAN_READ
1369 
1370 //   qCDebug(LANGUAGE) << "searching" << position << "in:" << scopeIdentifier(true).toString() << range() << includeRightBorder;
1371 
1372     if (!range().contains(position) && (!includeRightBorder || range().end != position)) {
1373 //     qCDebug(LANGUAGE) << "mismatch";
1374         return nullptr;
1375     }
1376 
1377     const auto childContexts = m_dynamicData->m_childContexts;
1378     for (int a = childContexts.size() - 1; a >= 0; --a) {
1379         if (DUContext* specific = childContexts[a]->findContextAt(position, includeRightBorder)) {
1380             return specific;
1381         }
1382     }
1383 
1384     return const_cast<DUContext*>(this);
1385 }
1386 
1387 Declaration* DUContext::findDeclarationAt(const CursorInRevision& position) const
1388 {
1389     ENSURE_CAN_READ
1390 
1391     if (!range().contains(position))
1392         return nullptr;
1393 
1394     for (Declaration* child : qAsConst(m_dynamicData->m_localDeclarations)) {
1395         if (child->range().contains(position)) {
1396             return child;
1397         }
1398     }
1399 
1400     return nullptr;
1401 }
1402 
1403 DUContext* DUContext::findContextIncluding(const RangeInRevision& range) const
1404 {
1405     ENSURE_CAN_READ
1406 
1407     if (!this->range().contains(range))
1408         return nullptr;
1409 
1410     for (DUContext* child : qAsConst(m_dynamicData->m_childContexts)) {
1411         if (DUContext* specific = child->findContextIncluding(range)) {
1412             return specific;
1413         }
1414     }
1415 
1416     return const_cast<DUContext*>(this);
1417 }
1418 
1419 int DUContext::findUseAt(const CursorInRevision& position) const
1420 {
1421     ENSURE_CAN_READ
1422 
1423     if (!range().contains(position))
1424         return -1;
1425 
1426     for (unsigned int a = 0; a < d_func()->m_usesSize(); ++a)
1427         if (d_func()->m_uses()[a].m_range.contains(position))
1428             return a;
1429 
1430     return -1;
1431 }
1432 
1433 bool DUContext::inSymbolTable() const
1434 {
1435     return d_func()->m_inSymbolTable;
1436 }
1437 
1438 void DUContext::setInSymbolTable(bool inSymbolTable)
1439 {
1440     d_func_dynamic()->m_inSymbolTable = inSymbolTable;
1441 }
1442 
1443 void DUContext::clearImportedParentContexts()
1444 {
1445     ENSURE_CAN_WRITE
1446         DUCHAIN_D_DYNAMIC(DUContext);
1447 
1448     while (d->m_importedContextsSize() != 0) {
1449         DUContext* ctx = d->m_importedContexts()[0].context(nullptr, false);
1450         if (ctx)
1451             ctx->m_dynamicData->removeImportedChildContext(this);
1452 
1453         d->m_importedContextsList().removeOne(d->m_importedContexts()[0]);
1454     }
1455 }
1456 
1457 void DUContext::cleanIfNotEncountered(const QSet<DUChainBase*>& encountered)
1458 {
1459     ENSURE_CAN_WRITE
1460 
1461     // It may happen that the deletion of one declaration triggers the deletion of another one
1462     // Therefore we copy the list of indexed declarations and work on those. Indexed declarations
1463     // will return zero for already deleted declarations.
1464     KDevVarLengthArray<LocalIndexedDeclaration> indexedLocal;
1465     if (d_func()->m_localDeclarations()) {
1466         indexedLocal.append(d_func()->m_localDeclarations(), d_func()->m_localDeclarationsSize());
1467     }
1468     for (const LocalIndexedDeclaration& indexed : indexedLocal) {
1469         auto dec = indexed.data(topContext());
1470         if (dec && !encountered.contains(dec) && (!dec->isAutoDeclaration() || !dec->hasUses())) {
1471             delete dec;
1472         }
1473     }
1474 
1475     const auto currentChildContexts = m_dynamicData->m_childContexts;
1476     for (DUContext* childContext : currentChildContexts) {
1477         if (!encountered.contains(childContext)) {
1478             delete childContext;
1479         }
1480     }
1481 }
1482 
1483 TopDUContext* DUContext::topContext() const
1484 {
1485     return m_dynamicData->m_topContext;
1486 }
1487 
1488 AbstractNavigationWidget* DUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext,
1489                                                             AbstractNavigationWidget::DisplayHints hints) const
1490 {
1491     if (decl) {
1492         auto* widget = new AbstractNavigationWidget;
1493         widget->setDisplayHints(hints);
1494         auto* context = new AbstractDeclarationNavigationContext(DeclarationPointer(decl),
1495                                                                  TopDUContextPointer(topContext));
1496         widget->setContext(NavigationContextPointer(context));
1497         return widget;
1498     } else {
1499         return nullptr;
1500     }
1501 }
1502 
1503 QVector<RangeInRevision> allUses(DUContext* context, int declarationIndex, bool noEmptyUses)
1504 {
1505     QVector<RangeInRevision> ret;
1506     for (int a = 0; a < context->usesCount(); ++a)
1507         if (context->uses()[a].m_declarationIndex == declarationIndex)
1508             if (!noEmptyUses || !context->uses()[a].m_range.isEmpty())
1509                 ret << context->uses()[a].m_range;
1510 
1511     const auto childContexts = context->childContexts();
1512     for (DUContext* child : childContexts) {
1513         ret += allUses(child, declarationIndex, noEmptyUses);
1514     }
1515 
1516     return ret;
1517 }
1518 
1519 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, const Ptr& nextItem, int start)
1520     : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false)
1521 {
1522     if (!id.isEmpty()) {
1523         if (id.count() > start)
1524             identifier = id.indexedAt(start);
1525 
1526         if (id.count() > start + 1)
1527             addNext(Ptr(new SearchItem(id, nextItem, start + 1)));
1528         else if (nextItem)
1529             next.append(nextItem);
1530     } else if (nextItem) {
1531         ///If there is no prefix, just copy nextItem
1532         isExplicitlyGlobal = nextItem->isExplicitlyGlobal;
1533         identifier = nextItem->identifier;
1534         next = nextItem->next;
1535     }
1536 }
1537 
1538 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, const PtrList& nextItems, int start)
1539     : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false)
1540 {
1541     if (id.count() > start)
1542         identifier = id.indexedAt(start);
1543 
1544     if (id.count() > start + 1)
1545         addNext(Ptr(new SearchItem(id, nextItems, start + 1)));
1546     else
1547         next = nextItems;
1548 }
1549 
1550 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, const IndexedIdentifier& id, const PtrList& nextItems)
1551     : isExplicitlyGlobal(explicitlyGlobal)
1552     , identifier(id)
1553     , next(nextItems)
1554 {
1555 }
1556 
1557 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, const IndexedIdentifier& id, const Ptr& nextItem)
1558     : isExplicitlyGlobal(explicitlyGlobal)
1559     , identifier(id)
1560 {
1561     next.append(nextItem);
1562 }
1563 
1564 bool DUContext::SearchItem::match(const QualifiedIdentifier& id, int offset) const
1565 {
1566     if (id.isEmpty()) {
1567         if (identifier.isEmpty() && next.isEmpty())
1568             return true;
1569         else
1570             return false;
1571     }
1572 
1573     if (id.at(offset) != identifier) //The identifier is different
1574         return false;
1575 
1576     if (offset == id.count() - 1) {
1577         if (next.isEmpty())
1578             return true; //match
1579         else
1580             return false; //id is too short
1581     }
1582 
1583     for (int a = 0; a < next.size(); ++a)
1584         if (next[a]->match(id, offset + 1))
1585             return true;
1586 
1587     return false;
1588 }
1589 
1590 bool DUContext::SearchItem::isEmpty() const
1591 {
1592     return identifier.isEmpty();
1593 }
1594 
1595 bool DUContext::SearchItem::hasNext() const
1596 {
1597     return !next.isEmpty();
1598 }
1599 
1600 QVector<QualifiedIdentifier> DUContext::SearchItem::toList(const QualifiedIdentifier& prefix) const
1601 {
1602     QVector<QualifiedIdentifier> ret;
1603 
1604     QualifiedIdentifier id = prefix;
1605     if (id.isEmpty())
1606         id.setExplicitlyGlobal(isExplicitlyGlobal);
1607     if (!identifier.isEmpty())
1608         id.push(identifier);
1609 
1610     if (next.isEmpty()) {
1611         ret << id;
1612     } else {
1613         for (int a = 0; a < next.size(); ++a)
1614             ret += next[a]->toList(id);
1615     }
1616     return ret;
1617 }
1618 
1619 void DUContext::SearchItem::addNext(const SearchItem::Ptr& other)
1620 {
1621     next.append(other);
1622 }
1623 
1624 void DUContext::SearchItem::addToEachNode(const SearchItem::Ptr& other)
1625 {
1626     if (other->isExplicitlyGlobal)
1627         return;
1628 
1629     next.append(other);
1630     for (int a = 0; a < next.size() - 1; ++a)
1631         next[a]->addToEachNode(other);
1632 }
1633 
1634 void DUContext::SearchItem::addToEachNode(const SearchItem::PtrList& other)
1635 {
1636     int added = 0;
1637     for (const SearchItem::Ptr& o : other) {
1638         if (!o->isExplicitlyGlobal) {
1639             next.append(o);
1640             ++added;
1641         }
1642     }
1643 
1644     for (int a = 0; a < next.size() - added; ++a)
1645         next[a]->addToEachNode(other);
1646 }
1647 
1648 DUContext::Import::Import(DUContext* _context, const DUContext* importer, const CursorInRevision& _position)
1649     : position(_position)
1650 {
1651     if (_context && _context->owner() &&
1652         (_context->owner()->specialization().index() ||
1653          (importer && importer->topContext() != _context->topContext()))) {
1654         m_declaration = _context->owner()->id();
1655     } else {
1656         m_context = _context;
1657     }
1658 }
1659 
1660 DUContext::Import::Import(const DeclarationId& id, const CursorInRevision& _position)
1661     : position(_position)
1662     , m_declaration(id)
1663 {
1664 }
1665 
1666 DUContext* DUContext::Import::context(const TopDUContext* topContext, bool instantiateIfRequired) const
1667 {
1668     if (m_declaration.isValid()) {
1669         Declaration* decl = m_declaration.declaration(topContext, instantiateIfRequired);
1670         //This first case rests on the assumption that no context will ever import a function's expression context
1671         //More accurately, that no specialized or cross-topContext imports will, but if the former assumption fails the latter will too
1672         if (auto* functionDecl = dynamic_cast<AbstractFunctionDeclaration*>(decl)) {
1673             if (functionDecl->internalFunctionContext()) {
1674                 return functionDecl->internalFunctionContext();
1675             } else {
1676                 qCWarning(LANGUAGE) << "Import of function declaration without internal function context encountered!";
1677             }
1678         }
1679         if (decl)
1680             return decl->logicalInternalContext(topContext);
1681         else
1682             return nullptr;
1683     } else {
1684         return m_context.data();
1685     }
1686 }
1687 
1688 bool DUContext::Import::isDirect() const
1689 {
1690     return m_context.isValid();
1691 }
1692 
1693 void DUContext::visit(DUChainVisitor& visitor)
1694 {
1695     ENSURE_CAN_READ
1696 
1697     visitor.visit(this);
1698 
1699     for (Declaration* decl : qAsConst(m_dynamicData->m_localDeclarations)) {
1700         visitor.visit(decl);
1701     }
1702 
1703     for (DUContext* childContext : qAsConst(m_dynamicData->m_childContexts)) {
1704         childContext->visit(visitor);
1705     }
1706 }
1707 
1708 static bool sortByRange(const DUChainBase* lhs, const DUChainBase* rhs)
1709 {
1710     return lhs->range() < rhs->range();
1711 }
1712 
1713 void DUContext::resortLocalDeclarations()
1714 {
1715     ENSURE_CAN_WRITE
1716 
1717     std::sort(m_dynamicData->m_localDeclarations.begin(), m_dynamicData->m_localDeclarations.end(), sortByRange);
1718 
1719     auto top = topContext();
1720     auto& declarations = d_func_dynamic()->m_localDeclarationsList();
1721     std::sort(declarations.begin(), declarations.end(),
1722               [top](const LocalIndexedDeclaration& lhs, const LocalIndexedDeclaration& rhs) {
1723             return lhs.data(top)->range() < rhs.data(top)->range();
1724         });
1725 }
1726 
1727 void DUContext::resortChildContexts()
1728 {
1729     ENSURE_CAN_WRITE
1730 
1731     std::sort(m_dynamicData->m_childContexts.begin(), m_dynamicData->m_childContexts.end(), sortByRange);
1732 
1733     auto top = topContext();
1734     auto& contexts = d_func_dynamic()->m_childContextsList();
1735     std::sort(contexts.begin(), contexts.end(),
1736               [top](const LocalIndexedDUContext& lhs, const LocalIndexedDUContext& rhs) {
1737             return lhs.data(top)->range() < rhs.data(top)->range();
1738         });
1739 }
1740 }