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

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 "topducontext.h"
0009 #include "topducontextutils.h"
0010 
0011 #include <limits>
0012 
0013 #include "persistentsymboltable.h"
0014 #include "problem.h"
0015 #include "declaration.h"
0016 #include "duchain.h"
0017 #include "duchainlock.h"
0018 #include "parsingenvironment.h"
0019 #include "duchainpointer.h"
0020 #include "declarationid.h"
0021 #include "namespacealiasdeclaration.h"
0022 #include "aliasdeclaration.h"
0023 #include "uses.h"
0024 #include "topducontextdata.h"
0025 #include "duchainregister.h"
0026 #include "topducontextdynamicdata.h"
0027 #include <debug.h>
0028 
0029 #include <language/interfaces/iastcontainer.h>
0030 
0031 #include <QMutexLocker>
0032 #include <QRecursiveMutex>
0033 
0034 // #define DEBUG_SEARCH
0035 
0036 const uint maxApplyAliasesRecursion = 100;
0037 
0038 namespace KDevelop {
0039 Utils::BasicSetRepository* RecursiveImportRepository::repository()
0040 {
0041     static QRecursiveMutex mutex;
0042     static Utils::BasicSetRepository recursiveImportRepositoryObject(QStringLiteral("Recursive Imports"), &mutex,
0043                                                                      &KDevelop::globalItemRepositoryRegistry());
0044     return &recursiveImportRepositoryObject;
0045 }
0046 
0047 ReferencedTopDUContext::ReferencedTopDUContext(TopDUContext* context) : m_topContext(context)
0048 {
0049     if (m_topContext)
0050         DUChain::self()->refCountUp(m_topContext);
0051 }
0052 
0053 ReferencedTopDUContext::ReferencedTopDUContext(const ReferencedTopDUContext& rhs) : m_topContext(rhs.m_topContext)
0054 {
0055     if (m_topContext)
0056         DUChain::self()->refCountUp(m_topContext);
0057 }
0058 
0059 ReferencedTopDUContext::~ReferencedTopDUContext()
0060 {
0061     if (m_topContext && !DUChain::deleted())
0062         DUChain::self()->refCountDown(m_topContext);
0063 }
0064 
0065 ReferencedTopDUContext& ReferencedTopDUContext::operator=(const ReferencedTopDUContext& rhs)
0066 {
0067     if (m_topContext == rhs.m_topContext)
0068         return *this;
0069 
0070     if (m_topContext)
0071         DUChain::self()->refCountDown(m_topContext);
0072 
0073     m_topContext = rhs.m_topContext;
0074 
0075     if (m_topContext)
0076         DUChain::self()->refCountUp(m_topContext);
0077     return *this;
0078 }
0079 
0080 DEFINE_LIST_MEMBER_HASH(TopDUContextData, m_usedDeclarationIds, DeclarationId)
0081 DEFINE_LIST_MEMBER_HASH(TopDUContextData, m_problems, LocalIndexedProblem)
0082 REGISTER_DUCHAIN_ITEM(TopDUContext);
0083 
0084 QRecursiveMutex importStructureMutex;
0085 
0086 //Contains data that is not shared among top-contexts that share their duchain entries
0087 class TopDUContextLocalPrivate
0088 {
0089 public:
0090     TopDUContextLocalPrivate (TopDUContext* ctxt, uint index) :
0091         m_ctxt(ctxt)
0092         , m_ownIndex(index)
0093         , m_inDuChain(false)
0094     {
0095         m_indexedRecursiveImports.insert(index);
0096     }
0097 
0098     ~TopDUContextLocalPrivate()
0099     {
0100         //Either we use some other contexts data and have no users, or we own the data and have users that share it.
0101         QMutexLocker lock(&importStructureMutex);
0102 
0103         for (const DUContext::Import& import : qAsConst(m_importedContexts)) {
0104             if (DUChain::self()->isInMemory(import.topContextIndex()) &&
0105                 dynamic_cast<TopDUContext*>(import.context(nullptr)))
0106                 dynamic_cast<TopDUContext*>(import.context(nullptr))->m_local->m_directImporters.remove(m_ctxt);
0107         }
0108     }
0109 
0110     ///@todo Make all this work consistently together with import-caching
0111 
0112     //After loading, should rebuild the links
0113     void rebuildDynamicImportStructure()
0114     {
0115         //Currently we do not store the whole data in TopDUContextLocalPrivate, so we reconstruct it from what was stored by DUContext.
0116         Q_ASSERT(m_importedContexts.isEmpty());
0117 
0118         FOREACH_FUNCTION(const DUContext::Import& import, m_ctxt->d_func()->m_importedContexts) {
0119             if (DUChain::self()->isInMemory(import.topContextIndex())) {
0120                 Q_ASSERT(import.context(nullptr));
0121                 TopDUContext* top = import.context(nullptr)->topContext();
0122                 Q_ASSERT(top);
0123                 addImportedContextRecursively(top, false, true);
0124             }
0125         }
0126         FOREACH_FUNCTION(const IndexedDUContext &importer, m_ctxt->d_func()->m_importers) {
0127             if (DUChain::self()->isInMemory(importer.topContextIndex())) {
0128                 Q_ASSERT(importer.context());
0129                 TopDUContext* top = importer.context()->topContext();
0130                 Q_ASSERT(top);
0131                 top->m_local->addImportedContextRecursively(m_ctxt, false, true);
0132             }
0133         }
0134     }
0135 
0136     //Index of this top-context within the duchain
0137     //Since the data of top-contexts can be shared among multiple, this can be used to add imports that are local to this top-context.
0138     QVector<DUContext::Import> m_importedContexts;
0139 //   mutable bool m_haveImportStructure : 1;
0140     TopDUContext* m_ctxt;
0141 
0142     QSet<DUContext*> m_directImporters;
0143 
0144     ParsingEnvironmentFilePointer m_file;
0145 
0146     QExplicitlySharedDataPointer<IAstContainer> m_ast;
0147 
0148     uint m_ownIndex;
0149 
0150     bool m_inDuChain;
0151 
0152     void clearImportedContextsRecursively()
0153     {
0154         QMutexLocker lock(&importStructureMutex);
0155 
0156 //     Q_ASSERT(m_recursiveImports.size() == m_indexedRecursiveImports.count()-1);
0157 
0158         QSet<QPair<TopDUContext*, const TopDUContext*>> rebuild;
0159 
0160         for (const DUContext::Import& import : qAsConst(m_importedContexts)) {
0161             auto* top = dynamic_cast<TopDUContext*>(import.context(nullptr));
0162             if (top) {
0163                 top->m_local->m_directImporters.remove(m_ctxt);
0164 
0165                 if (!m_ctxt->usingImportsCache()) {
0166                     removeImportedContextRecursion(top, top, 1, rebuild);
0167 
0168                     QHash<const TopDUContext*, QPair<int, const TopDUContext*>> b = top->m_local->m_recursiveImports;
0169                     for (RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it) {
0170                         if (m_recursiveImports.contains(it.key()) && m_recursiveImports[it.key()].second == top)
0171                             removeImportedContextRecursion(top, it.key(), it->first + 1, rebuild); //Remove all contexts that are imported through the context
0172                     }
0173                 }
0174             }
0175         }
0176 
0177         m_importedContexts.clear();
0178 
0179         rebuildImportStructureRecursion(rebuild);
0180 
0181         Q_ASSERT(m_recursiveImports.isEmpty());
0182 //     Q_ASSERT(m_recursiveImports.size() == m_indexedRecursiveImports.count()-1);
0183     }
0184 
0185     //Adds the context to this and all contexts that import this, and manages m_recursiveImports
0186     void addImportedContextRecursively(TopDUContext* context, bool temporary, bool local)
0187     {
0188         QMutexLocker lock(&importStructureMutex);
0189 
0190         context->m_local->m_directImporters.insert(m_ctxt);
0191 
0192         if (local) {
0193             // note: m_importedContexts may end up with duplicate entries -- not sure whether we should protect against this --Kevin
0194             m_importedContexts << DUContext::Import(context, m_ctxt);
0195         }
0196 
0197         if (!m_ctxt->usingImportsCache()) {
0198             addImportedContextRecursion(context, context, 1, temporary);
0199 
0200             QHash<const TopDUContext*, QPair<int, const TopDUContext*>> b = context->m_local->m_recursiveImports;
0201             for (RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it)
0202                 addImportedContextRecursion(context, it.key(), (*it).first + 1, temporary); //Add contexts that were imported earlier into the given one
0203         }
0204     }
0205 
0206     //Removes the context from this and all contexts that import this, and manages m_recursiveImports
0207     void removeImportedContextRecursively(TopDUContext* context, bool local)
0208     {
0209         QMutexLocker lock(&importStructureMutex);
0210 
0211         context->m_local->m_directImporters.remove(m_ctxt);
0212 
0213         if (local)
0214             m_importedContexts.removeAll(DUContext::Import(context, m_ctxt));
0215 
0216         QSet<QPair<TopDUContext*, const TopDUContext*>> rebuild;
0217         if (!m_ctxt->usingImportsCache()) {
0218             removeImportedContextRecursion(context, context, 1, rebuild);
0219 
0220             QHash<const TopDUContext*, QPair<int, const TopDUContext*>> b = context->m_local->m_recursiveImports;
0221             for (RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it) {
0222                 if (m_recursiveImports.contains(it.key()) && m_recursiveImports[it.key()].second == context)
0223                     removeImportedContextRecursion(context, it.key(), it->first + 1, rebuild); //Remove all contexts that are imported through the context
0224             }
0225         }
0226 
0227         rebuildImportStructureRecursion(rebuild);
0228     }
0229 
0230     void removeImportedContextsRecursively(const QList<TopDUContext*>& contexts, bool local)
0231     {
0232         QMutexLocker lock(&importStructureMutex);
0233 
0234         QSet<QPair<TopDUContext*, const TopDUContext*>> rebuild;
0235         for (TopDUContext* context : contexts) {
0236             context->m_local->m_directImporters.remove(m_ctxt);
0237 
0238             if (local)
0239                 m_importedContexts.removeAll(DUContext::Import(context, m_ctxt));
0240 
0241             if (!m_ctxt->usingImportsCache()) {
0242                 removeImportedContextRecursion(context, context, 1, rebuild);
0243 
0244                 QHash<const TopDUContext*, QPair<int, const TopDUContext*>> b = context->m_local->m_recursiveImports;
0245                 for (RecursiveImports::const_iterator it = b.constBegin(); it != b.constEnd(); ++it) {
0246                     const auto recursiveImportIt = m_recursiveImports.constFind(it.key());
0247                     if (recursiveImportIt != m_recursiveImports.constEnd() && recursiveImportIt->second == context)
0248                         removeImportedContextRecursion(context, it.key(), it->first + 1, rebuild); //Remove all contexts that are imported through the context
0249                 }
0250             }
0251         }
0252 
0253         rebuildImportStructureRecursion(rebuild);
0254     }
0255 
0256     //Has an entry for every single recursively imported file, that contains the shortest path, and the next context on that path to the imported context.
0257     //This does not need to be stored to disk, because it is defined implicitly.
0258     //What makes this most complicated is the fact that loops are allowed in the import structure.
0259     using RecursiveImports = QHash<const TopDUContext*, QPair<int, const TopDUContext*>>;
0260     mutable RecursiveImports m_recursiveImports;
0261     mutable TopDUContext::IndexedRecursiveImports m_indexedRecursiveImports;
0262 
0263 private:
0264     void addImportedContextRecursion(const TopDUContext* traceNext, const TopDUContext* imported, int depth,
0265                                      bool temporary = false)
0266     {
0267         if (m_ctxt->usingImportsCache())
0268             return;
0269 
0270 //     if(!m_haveImportStructure)
0271 //       return;
0272 
0273         if (imported == m_ctxt)
0274             return;
0275 
0276         const bool computeShortestPaths = false; ///@todo We do not compute the shortest path. Think what's right.
0277 
0278 //     traceNext->m_local->needImportStructure();
0279 //     imported->m_local->needImportStructure();
0280 
0281         RecursiveImports::iterator it = m_recursiveImports.find(imported);
0282         if (it == m_recursiveImports.end()) {
0283             //Insert new path to "imported"
0284             m_recursiveImports[imported] = qMakePair(depth, traceNext);
0285 
0286             m_indexedRecursiveImports.insert(imported->indexed());
0287 //       Q_ASSERT(m_indexedRecursiveImports.size() == m_recursiveImports.size()+1);
0288 
0289             Q_ASSERT(traceNext != m_ctxt);
0290         } else {
0291             if (!computeShortestPaths)
0292                 return;
0293 
0294             if (temporary) //For temporary imports, we don't record the best path.
0295                 return;
0296             //It would be better if we would use the following code, but it creates too much cost in updateImportedContextRecursion when imports are removed again.
0297 
0298             //Check whether the new way to "imported" is shorter than the stored one
0299             if ((*it).first > depth) {
0300                 //Add a shorter path
0301                 (*it).first = depth;
0302                 Q_ASSERT(traceNext);
0303                 (*it).second = traceNext;
0304                 Q_ASSERT(traceNext == imported ||
0305                          (traceNext->m_local->m_recursiveImports.contains(imported) &&
0306                           traceNext->m_local->m_recursiveImports[imported].first < (*it).first));
0307             } else {
0308                 //The imported context is already imported through a same/better path, so we can just stop processing. This saves us from endless recursion.
0309                 return;
0310             }
0311         }
0312 
0313         if (temporary)
0314             return;
0315 
0316         for (auto* context : qAsConst(m_directImporters)) {
0317             auto* top = dynamic_cast<TopDUContext*>(context);
0318             if (top) ///@todo also record this for local imports
0319                 top->m_local->addImportedContextRecursion(m_ctxt, imported, depth + 1);
0320         }
0321     }
0322 
0323     void removeImportedContextRecursion(const TopDUContext* traceNext, const TopDUContext* imported, int distance,
0324                                         QSet<QPair<TopDUContext*, const TopDUContext*>>& rebuild)
0325     {
0326         if (m_ctxt->usingImportsCache())
0327             return;
0328 
0329         if (imported == m_ctxt)
0330             return;
0331 
0332 //     if(!m_haveImportStructure)
0333 //       return;
0334 
0335         RecursiveImports::iterator it = m_recursiveImports.find(imported);
0336         if (it == m_recursiveImports.end()) {
0337             //We don't import. Just return, this saves us from endless recursion.
0338             return;
0339         } else {
0340             //Check whether we have imported "imported" through "traceNext". If not, return. Else find a new trace.
0341             if ((*it).second == traceNext && (*it).first == distance) {
0342                 //We need to remove the import through traceNext. Check whether there is another imported context that imports it.
0343 
0344                 m_recursiveImports.erase(it); //In order to prevent problems, we completely remove everything, and re-add it.
0345                                               //Just updating these complex structures is very hard.
0346                 Q_ASSERT(imported != m_ctxt);
0347 
0348                 m_indexedRecursiveImports.remove(imported->indexed());
0349 //         Q_ASSERT(m_indexedRecursiveImports.size() == m_recursiveImports.size());
0350 
0351                 rebuild.insert(qMakePair(m_ctxt, imported));
0352                 //We MUST do this before finding another trace, because else we would create loops
0353                 for (QSet<DUContext*>::const_iterator childIt = m_directImporters.constBegin();
0354                      childIt != m_directImporters.constEnd(); ++childIt) {
0355                     auto* top = dynamic_cast<TopDUContext*>(const_cast<DUContext*>(*childIt)); //Avoid detaching, so use const iterator
0356                     if (top)
0357                         top->m_local->removeImportedContextRecursion(m_ctxt, imported, distance + 1, rebuild); //Don't use 'it' from here on, it may be invalid
0358                 }
0359             }
0360         }
0361     }
0362 
0363     //Updates the trace to 'imported'
0364     void rebuildStructure(const TopDUContext* imported);
0365 
0366     void rebuildImportStructureRecursion(const QSet<QPair<TopDUContext*, const TopDUContext*>>& rebuild)
0367     {
0368         for (auto& rebuildPair : rebuild) {
0369             //for(int a = rebuild.size()-1; a >= 0; --a) {
0370             //Find the best imported parent
0371             rebuildPair.first->m_local->rebuildStructure(rebuildPair.second);
0372         }
0373     }
0374 };
0375 
0376 const TopDUContext::IndexedRecursiveImports& TopDUContext::recursiveImportIndices() const
0377 {
0378 //   No lock-check for performance reasons
0379     QMutexLocker lock(&importStructureMutex);
0380     if (!d_func()->m_importsCache.isEmpty())
0381         return d_func()->m_importsCache;
0382 
0383     return m_local->m_indexedRecursiveImports;
0384 }
0385 
0386 void TopDUContextData::updateImportCacheRecursion(uint baseIndex, IndexedTopDUContext currentContext,
0387                                                   TopDUContext::IndexedRecursiveImports& visited)
0388 {
0389     if (visited.contains(currentContext.index()))
0390         return;
0391     Q_ASSERT(currentContext.index()); //The top-context must be in the repository when this is called
0392     if (!currentContext.data()) {
0393         qCDebug(LANGUAGE) << "importing invalid context";
0394         return;
0395     }
0396     visited.insert(currentContext.index());
0397 
0398     const TopDUContextData* currentData = currentContext.data()->topContext()->d_func();
0399     if (currentData->m_importsCache.contains(baseIndex) || currentData->m_importsCache.isEmpty()) {
0400         //If we have a loop or no imports-cache is used, we have to look at each import separately.
0401         const KDevelop::DUContext::Import* imports = currentData->m_importedContexts();
0402         uint importsSize = currentData->m_importedContextsSize();
0403         for (uint a = 0; a < importsSize; ++a) {
0404             IndexedTopDUContext next(imports[a].topContextIndex());
0405             if (next.isValid())
0406                 updateImportCacheRecursion(baseIndex, next, visited);
0407         }
0408     } else {
0409         //If we don't have a loop with baseIndex, we can safely just merge with the imported importscache
0410         visited += currentData->m_importsCache;
0411     }
0412 }
0413 
0414 void TopDUContextData::updateImportCacheRecursion(IndexedTopDUContext currentContext, std::set<uint>& visited)
0415 {
0416     if (visited.find(currentContext.index()) != visited.end())
0417         return;
0418     Q_ASSERT(currentContext.index()); //The top-context must be in the repository when this is called
0419     if (!currentContext.data()) {
0420         qCDebug(LANGUAGE) << "importing invalid context";
0421         return;
0422     }
0423     visited.insert(currentContext.index());
0424     const TopDUContextData* currentData = currentContext.data()->topContext()->d_func();
0425     const KDevelop::DUContext::Import* imports = currentData->m_importedContexts();
0426     uint importsSize = currentData->m_importedContextsSize();
0427     for (uint a = 0; a < importsSize; ++a) {
0428         IndexedTopDUContext next(imports[a].topContextIndex());
0429         if (next.isValid())
0430             updateImportCacheRecursion(next, visited);
0431     }
0432 }
0433 
0434 void TopDUContext::updateImportsCache()
0435 {
0436     QMutexLocker lock(&importStructureMutex);
0437 
0438     const bool use_fully_recursive_import_cache_computation = false;
0439 
0440     if (use_fully_recursive_import_cache_computation) {
0441         std::set<uint> visited;
0442         TopDUContextData::updateImportCacheRecursion(this, visited);
0443         Q_ASSERT(visited.find(ownIndex()) != visited.end());
0444         d_func_dynamic()->m_importsCache = IndexedRecursiveImports(visited);
0445     } else {
0446         d_func_dynamic()->m_importsCache = IndexedRecursiveImports();
0447         TopDUContextData::updateImportCacheRecursion(ownIndex(), this, d_func_dynamic()->m_importsCache);
0448     }
0449     Q_ASSERT(d_func_dynamic()->m_importsCache.contains(IndexedTopDUContext(this)));
0450     Q_ASSERT(usingImportsCache());
0451     Q_ASSERT(imports(this, CursorInRevision::invalid()));
0452 
0453     if (parsingEnvironmentFile())
0454         parsingEnvironmentFile()->setImportsCache(d_func()->m_importsCache);
0455 }
0456 
0457 bool TopDUContext::usingImportsCache() const
0458 {
0459     return !d_func()->m_importsCache.isEmpty();
0460 }
0461 
0462 CursorInRevision TopDUContext::importPosition(const DUContext* target) const
0463 {
0464     ENSURE_CAN_READ
0465         DUCHAIN_D(DUContext);
0466     Import import(const_cast<DUContext*>(target), const_cast<TopDUContext*>(this), CursorInRevision::invalid());
0467     for (unsigned int a = 0; a < d->m_importedContextsSize(); ++a)
0468         if (d->m_importedContexts()[a] == import)
0469             return d->m_importedContexts()[a].position;
0470 
0471     return DUContext::importPosition(target);
0472 }
0473 
0474 void TopDUContextLocalPrivate::rebuildStructure(const TopDUContext* imported)
0475 {
0476     if (m_ctxt == imported)
0477         return;
0478 
0479     for (auto& importedContext : qAsConst(m_importedContexts)) {
0480         auto* top = dynamic_cast<TopDUContext*>(importedContext.context(nullptr));
0481         if (top) {
0482 //       top->m_local->needImportStructure();
0483             if (top == imported) {
0484                 addImportedContextRecursion(top, imported, 1);
0485             } else {
0486                 RecursiveImports::const_iterator it2 = top->m_local->m_recursiveImports.constFind(imported);
0487                 if (it2 != top->m_local->m_recursiveImports.constEnd()) {
0488                     addImportedContextRecursion(top, imported, (*it2).first + 1);
0489                 }
0490             }
0491         }
0492     }
0493 
0494     for (unsigned int a = 0; a < m_ctxt->d_func()->m_importedContextsSize(); ++a) {
0495         auto* top =
0496             dynamic_cast<TopDUContext*>(const_cast<DUContext*>(m_ctxt->d_func()->m_importedContexts()[a].context(nullptr)));           //To avoid detaching, use const iterator
0497         if (top) {
0498 //       top->m_local->needImportStructure();
0499             if (top == imported) {
0500                 addImportedContextRecursion(top, imported, 1);
0501             } else {
0502                 RecursiveImports::const_iterator it2 = top->m_local->m_recursiveImports.constFind(imported);
0503                 if (it2 != top->m_local->m_recursiveImports.constEnd()) {
0504                     addImportedContextRecursion(top, imported, (*it2).first + 1);
0505                 }
0506             }
0507         }
0508     }
0509 }
0510 
0511 void TopDUContext::rebuildDynamicImportStructure()
0512 {
0513     m_local->rebuildDynamicImportStructure();
0514 }
0515 
0516 void TopDUContext::rebuildDynamicData(DUContext* parent, uint ownIndex)
0517 {
0518     Q_ASSERT(parent == nullptr && ownIndex != 0);
0519     m_local->m_ownIndex = ownIndex;
0520 
0521     DUContext::rebuildDynamicData(parent, 0);
0522 }
0523 
0524 IndexedTopDUContext TopDUContext::indexed() const
0525 {
0526     return IndexedTopDUContext(m_local->m_ownIndex);
0527 }
0528 
0529 uint TopDUContext::ownIndex() const
0530 {
0531     return m_local->m_ownIndex;
0532 }
0533 
0534 TopDUContext::TopDUContext(TopDUContextData& data) : DUContext(data)
0535     , m_local(new TopDUContextLocalPrivate(this, data.m_ownIndex))
0536     , m_dynamicData(new TopDUContextDynamicData(this))
0537 {
0538     initFromTopContext();
0539 }
0540 
0541 TopDUContext::TopDUContext(const IndexedString& url, const RangeInRevision& range, ParsingEnvironmentFile* file)
0542     : DUContext(*new TopDUContextData(url), range)
0543     , m_local(new TopDUContextLocalPrivate(this, DUChain::newTopContextIndex()))
0544     , m_dynamicData(new TopDUContextDynamicData(this))
0545 {
0546     initFromTopContext();
0547 
0548     Q_ASSERT(url.toUrl().isValid() && !url.toUrl().isRelative());
0549     d_func_dynamic()->setClassId(this);
0550     setType(Global);
0551 
0552     DUCHAIN_D_DYNAMIC(TopDUContext);
0553     d->m_features = VisibleDeclarationsAndContexts;
0554     d->m_ownIndex = m_local->m_ownIndex;
0555     setParsingEnvironmentFile(file);
0556     setInSymbolTable(true);
0557 }
0558 
0559 QExplicitlySharedDataPointer<ParsingEnvironmentFile> TopDUContext::parsingEnvironmentFile() const
0560 {
0561     return m_local->m_file;
0562 }
0563 
0564 TopDUContext::~TopDUContext()
0565 {
0566     m_dynamicData->m_deleting = true;
0567 
0568     //Clear the AST, so that the 'feature satisfaction' cache is eventually updated
0569     clearAst();
0570 
0571     if (!isOnDisk()) {
0572         //Clear the 'feature satisfaction' cache which is managed in ParsingEnvironmentFile
0573         setFeatures(Empty);
0574 
0575         clearUsedDeclarationIndices();
0576     }
0577 
0578     deleteChildContextsRecursively();
0579     deleteLocalDeclarations();
0580     m_dynamicData->clear();
0581 }
0582 
0583 void TopDUContext::deleteSelf()
0584 {
0585     //We've got to make sure that m_dynamicData and m_local are still valid while all the sub-contexts are destroyed
0586     TopDUContextLocalPrivate* local = m_local;
0587     TopDUContextDynamicData* dynamicData = m_dynamicData;
0588 
0589     m_dynamicData->m_deleting = true;
0590 
0591     delete this;
0592 
0593     delete local;
0594     delete dynamicData;
0595 }
0596 
0597 TopDUContext::Features TopDUContext::features() const
0598 {
0599     auto ret = d_func()->m_features;
0600 
0601     if (ast())
0602         ret |= TopDUContext::AST;
0603 
0604     return ret;
0605 }
0606 
0607 void TopDUContext::setFeatures(Features features)
0608 {
0609     features &= ~Recursive; //Remove the "Recursive" flag since that's only for searching
0610     features &= ~ForceUpdateRecursive; //Remove the update flags
0611     features &= ~AST; //Remove the AST flag, it's only used while updating
0612     d_func_dynamic()->m_features = features;
0613 
0614     //Replicate features to ParsingEnvironmentFile
0615     if (parsingEnvironmentFile())
0616         parsingEnvironmentFile()->setFeatures(this->features());
0617 }
0618 
0619 void TopDUContext::setAst(const QExplicitlySharedDataPointer<IAstContainer>& ast)
0620 {
0621     ENSURE_CAN_WRITE
0622     m_local->m_ast = ast;
0623 
0624     if (parsingEnvironmentFile())
0625         parsingEnvironmentFile()->setFeatures(features());
0626 }
0627 
0628 void TopDUContext::setParsingEnvironmentFile(ParsingEnvironmentFile* file)
0629 {
0630     if (m_local->m_file) //Clear the "feature satisfaction" cache
0631         m_local->m_file->setFeatures(Empty);
0632 
0633     //We do not enforce a duchain lock here, since this is also used while loading a top-context
0634     m_local->m_file = QExplicitlySharedDataPointer<ParsingEnvironmentFile>(file);
0635 
0636     //Replicate features to ParsingEnvironmentFile
0637     if (file) {
0638         file->setTopContext(IndexedTopDUContext(ownIndex()));
0639         Q_ASSERT(file->indexedTopContext().isValid());
0640         file->setFeatures(d_func()->m_features);
0641 
0642         file->setImportsCache(d_func()->m_importsCache);
0643     }
0644 }
0645 
0646 struct TopDUContext::FindDeclarationsAcceptor
0647 {
0648     FindDeclarationsAcceptor(const TopDUContext* _top, DeclarationList& _target, const DeclarationChecker& _check,
0649                              SearchFlags _flags) : top(_top)
0650         , target(_target)
0651         , check(_check)
0652     {
0653         flags = _flags;
0654     }
0655 
0656     bool operator()(const QualifiedIdentifier& id)
0657     {
0658 #ifdef DEBUG_SEARCH
0659         qCDebug(LANGUAGE) << "accepting" << id.toString();
0660 #endif
0661 
0662         auto visitDeclaration = [&](const IndexedDeclaration& iDecl) {
0663             Declaration* decl = iDecl.data();
0664 
0665             if (!decl)
0666                 return PersistentSymbolTable::VisitorState::Continue;
0667 
0668             if (!check(decl))
0669                 return PersistentSymbolTable::VisitorState::Continue;
0670 
0671             if (!(flags & DontResolveAliases) && decl->kind() == Declaration::Alias) {
0672                 //Apply alias declarations
0673                 auto* alias = static_cast<AliasDeclaration*>(decl);
0674                 if (alias->aliasedDeclaration().isValid()) {
0675                     decl = alias->aliasedDeclaration().declaration();
0676                 } else {
0677                     qCDebug(LANGUAGE) << "lost aliased declaration";
0678                 }
0679             }
0680 
0681             target.append(decl);
0682             return PersistentSymbolTable::VisitorState::Continue;
0683         };
0684 
0685         if (check.flags & DUContext::NoImportsCheck) {
0686             PersistentSymbolTable::self().visitDeclarations(id, visitDeclaration);
0687         } else {
0688             PersistentSymbolTable::self().visitFilteredDeclarations(id, top->recursiveImportIndices(),
0689                                                                     visitDeclaration);
0690         }
0691 
0692         check.createVisibleCache = nullptr;
0693 
0694         return !top->foundEnough(target, flags);
0695     }
0696 
0697     const TopDUContext* top;
0698     DeclarationList& target;
0699     const DeclarationChecker& check;
0700     QFlags<KDevelop::DUContext::SearchFlag> flags;
0701 };
0702 
0703 bool TopDUContext::findDeclarationsInternal(const SearchItem::PtrList& identifiers, const CursorInRevision& position,
0704                                             const AbstractType::Ptr& dataType, DeclarationList& ret,
0705                                             const TopDUContext* /*source*/, SearchFlags flags, uint /*depth*/) const
0706 {
0707     ENSURE_CAN_READ
0708 
0709 #ifdef DEBUG_SEARCH
0710     for (const SearchItem::Ptr& idTree : identifiers) {
0711         const auto ids = idTree->toList();
0712         for (const QualifiedIdentifier& id : ids) {
0713             qCDebug(LANGUAGE) << "searching item" << id.toString();
0714         }
0715     }
0716 
0717 #endif
0718 
0719     DeclarationChecker check(this, position, dataType, flags);
0720     FindDeclarationsAcceptor storer(this, ret, check, flags);
0721 
0722     ///The actual scopes are found within applyAliases, and each complete qualified identifier is given to FindDeclarationsAcceptor.
0723     ///That stores the found declaration to the output.
0724     applyAliases(identifiers, storer, position, false);
0725 
0726     return true;
0727 }
0728 
0729 //This is used to prevent endless recursion due to "using namespace .." declarations, by storing all imports that are already being used.
0730 struct TopDUContext::ApplyAliasesBuddyInfo
0731 {
0732     ApplyAliasesBuddyInfo(uint importChainType, ApplyAliasesBuddyInfo* predecessor,
0733                           const IndexedQualifiedIdentifier& importId) : m_importChainType(importChainType)
0734         , m_predecessor(predecessor)
0735         , m_importId(importId)
0736     {
0737         if (m_predecessor && m_predecessor->m_importChainType != importChainType)
0738             m_predecessor = nullptr;
0739     }
0740 
0741     bool alreadyImporting(const IndexedQualifiedIdentifier& id)
0742     {
0743         ApplyAliasesBuddyInfo* current = this;
0744         while (current) {
0745             if (current->m_importId == id)
0746                 return true;
0747             current = current->m_predecessor;
0748         }
0749         return false;
0750     }
0751 
0752     uint m_importChainType;
0753     ApplyAliasesBuddyInfo* m_predecessor;
0754     IndexedQualifiedIdentifier m_importId;
0755 };
0756 
0757 ///@todo Implement a cache so at least the global import checks don't need to be done repeatedly. The cache should be thread-local, using DUChainPointer for the hashed items, and when an item was deleted, it should be discarded
0758 template <class Acceptor>
0759 bool TopDUContext::applyAliases(const QualifiedIdentifier& previous, const SearchItem::Ptr& identifier,
0760                                 Acceptor& accept, const CursorInRevision& position, bool canBeNamespace,
0761                                 ApplyAliasesBuddyInfo* buddy, uint recursionDepth) const
0762 {
0763     if (recursionDepth > maxApplyAliasesRecursion) {
0764         const auto searches = identifier->toList();
0765         QualifiedIdentifier id;
0766         if (!searches.isEmpty())
0767             id = searches.first();
0768 
0769         qCDebug(LANGUAGE) << "maximum apply-aliases recursion reached while searching" << id;
0770     }
0771     bool foundAlias = false;
0772 
0773     QualifiedIdentifier id(previous);
0774     id.push(identifier->identifier);
0775 
0776     if (!id.inRepository())
0777         return true; //If the qualified identifier is not in the identifier repository, it cannot be registered anywhere, so there's nothing we need to do
0778 
0779     if (!identifier->next.isEmpty() || canBeNamespace) { //If it cannot be a namespace, the last part of the scope will be ignored
0780         //Search for namespace-aliases, by using globalAliasIdentifier, which is inserted into the symbol-table by NamespaceAliasDeclaration
0781         QualifiedIdentifier aliasId(id);
0782         aliasId.push(globalIndexedAliasIdentifier());
0783 
0784 #ifdef DEBUG_SEARCH
0785         qCDebug(LANGUAGE) << "checking" << id.toString();
0786 #endif
0787 
0788         if (aliasId.inRepository()) {
0789             DeclarationChecker check(this, position, AbstractType::Ptr(), NoSearchFlags, nullptr);
0790 
0791             bool isDone = false;
0792             // The first part of the identifier has been found as a namespace-alias.
0793             // In c++, we only need the first alias. However, just to be correct, follow them all for now.
0794             // This efficiently filters the visible declarations out of all declarations
0795             PersistentSymbolTable::self().visitFilteredDeclarations(
0796                 aliasId, recursiveImportIndices(), [&](const IndexedDeclaration& indexedAliasDecl) {
0797                     auto* aliasDecl = indexedAliasDecl.data();
0798                     if (!aliasDecl)
0799                         return PersistentSymbolTable::VisitorState::Continue;
0800 
0801                     if (!check(aliasDecl))
0802                         return PersistentSymbolTable::VisitorState::Continue;
0803 
0804                     if (aliasDecl->kind() != Declaration::NamespaceAlias)
0805                         return PersistentSymbolTable::VisitorState::Continue;
0806 
0807                     if (foundAlias)
0808                         return PersistentSymbolTable::VisitorState::Break;
0809 
0810                     Q_ASSERT(dynamic_cast<NamespaceAliasDeclaration*>(aliasDecl));
0811 
0812                     auto* alias = static_cast<NamespaceAliasDeclaration*>(aliasDecl);
0813 
0814                     foundAlias = true;
0815 
0816                     QualifiedIdentifier importIdentifier = alias->importIdentifier();
0817 
0818                     if (importIdentifier.isEmpty()) {
0819                         qCDebug(LANGUAGE) << "found empty import";
0820                         return PersistentSymbolTable::VisitorState::Continue;
0821                     }
0822 
0823                     if (buddy && buddy->alreadyImporting(importIdentifier)) {
0824                         // This import has already been applied to this search
0825                         return PersistentSymbolTable::VisitorState::Continue;
0826                     }
0827 
0828                     ApplyAliasesBuddyInfo info(1, buddy, importIdentifier);
0829 
0830                     if (identifier->next.isEmpty()) {
0831                         // Just insert the aliased namespace identifier
0832                         if (!accept(importIdentifier)) {
0833                             isDone = true;
0834                             return PersistentSymbolTable::VisitorState::Break;
0835                         }
0836                     } else {
0837                         // Create an identifiers where namespace-alias part is replaced with the alias target
0838                         for (const SearchItem::Ptr& item : qAsConst(identifier->next)) {
0839                             if (!applyAliases(importIdentifier, item, accept, position, canBeNamespace, &info,
0840                                               recursionDepth + 1)) {
0841                                 isDone = true;
0842                                 return PersistentSymbolTable::VisitorState::Break;
0843                             }
0844                         }
0845                     }
0846                     return PersistentSymbolTable::VisitorState::Continue;
0847                 });
0848 
0849             if (isDone) {
0850                 return false;
0851             }
0852         }
0853     }
0854 
0855     if (!foundAlias) { //If we haven't found an alias, put the current versions into the result list. Additionally we will compute the identifiers transformed through "using".
0856         if (identifier->next.isEmpty()) {
0857             if (!accept(id)) //We're at the end of a qualified identifier, accept it
0858                 return false;
0859         } else {
0860             for (const SearchItem::Ptr& next : qAsConst(identifier->next)) {
0861                 if (!applyAliases(id, next, accept, position, canBeNamespace, nullptr, recursionDepth + 1))
0862                     return false;
0863             }
0864         }
0865     }
0866 
0867     /*if( !prefix.explicitlyGlobal() || !prefix.isEmpty() ) {*/ ///@todo check iso c++ if using-directives should be respected on top-level when explicitly global
0868     ///@todo this is bad for a very big repository(the chains should be walked for the top-context instead)
0869 
0870     //Find all namespace-imports at given scope
0871 
0872     {
0873         QualifiedIdentifier importId(previous);
0874         importId.push(globalIndexedImportIdentifier());
0875 
0876 #ifdef DEBUG_SEARCH
0877 //   qCDebug(LANGUAGE) << "checking imports in" << (backPointer ? id.toString() : QStringLiteral("global"));
0878 #endif
0879 
0880         if (importId.inRepository()) {
0881             DeclarationChecker check(this, position, AbstractType::Ptr(), NoSearchFlags, nullptr);
0882             bool isDone = false;
0883             //This iterator efficiently filters the visible declarations out of all declarations
0884             PersistentSymbolTable::self().visitFilteredDeclarations(
0885                 importId, recursiveImportIndices(), [&](const IndexedDeclaration& indexedImportDecl) {
0886                     Declaration* importDecl = indexedImportDecl.data();
0887                     if (!importDecl)
0888                         return PersistentSymbolTable::VisitorState::Continue;
0889 
0890                     //We must never break or return from this loop, because else we might be creating a bad cache
0891                     if (!check(importDecl))
0892                         return PersistentSymbolTable::VisitorState::Continue;
0893 
0894                     //Search for the identifier with the import-identifier prepended
0895                     Q_ASSERT(dynamic_cast<NamespaceAliasDeclaration*>(importDecl));
0896                     auto* alias = static_cast<NamespaceAliasDeclaration*>(importDecl);
0897 
0898 #ifdef DEBUG_SEARCH
0899                     qCDebug(LANGUAGE) << "found import of" << alias->importIdentifier().toString();
0900 #endif
0901 
0902                     QualifiedIdentifier importIdentifier = alias->importIdentifier();
0903 
0904                     if (importIdentifier.isEmpty()) {
0905                         qCDebug(LANGUAGE) << "found empty import";
0906                         return PersistentSymbolTable::VisitorState::Continue;
0907                     }
0908 
0909                     if (buddy && buddy->alreadyImporting(importIdentifier)) {
0910                         // This import has already been applied to this search
0911                         return PersistentSymbolTable::VisitorState::Continue;
0912                     }
0913 
0914                     ApplyAliasesBuddyInfo info(2, buddy, importIdentifier);
0915 
0916                     if (previous != importIdentifier) {
0917                         if (!applyAliases(importIdentifier, identifier, accept,
0918                                           importDecl->topContext() == this ? importDecl->range().start : position,
0919                                           canBeNamespace, &info, recursionDepth + 1)) {
0920                             isDone = true;
0921                             return PersistentSymbolTable::VisitorState::Break;
0922                         }
0923                     }
0924                     return PersistentSymbolTable::VisitorState::Continue;
0925                 });
0926 
0927             if (isDone) {
0928                 return false;
0929             }
0930         }
0931     }
0932     return true;
0933 }
0934 
0935 template <class Acceptor>
0936 void TopDUContext::applyAliases(const SearchItem::PtrList& identifiers, Acceptor& acceptor,
0937                                 const CursorInRevision& position, bool canBeNamespace) const
0938 {
0939     QualifiedIdentifier emptyId;
0940 
0941     for (const SearchItem::Ptr& item : identifiers)
0942         applyAliases(emptyId, item, acceptor, position, canBeNamespace, nullptr, 0);
0943 }
0944 
0945 TopDUContext* TopDUContext::topContext() const
0946 {
0947     return const_cast<TopDUContext*>(this);
0948 }
0949 
0950 bool TopDUContext::deleting() const
0951 {
0952     return m_dynamicData->m_deleting;
0953 }
0954 
0955 QList<ProblemPointer> TopDUContext::problems() const
0956 {
0957     ENSURE_CAN_READ
0958 
0959     const auto data = d_func();
0960     QList<ProblemPointer> ret;
0961     ret.reserve(data->m_problemsSize());
0962     for (uint i = 0; i < data->m_problemsSize(); ++i) {
0963         ret << ProblemPointer(data->m_problems()[i].data(this));
0964     }
0965 
0966     return ret;
0967 }
0968 
0969 void TopDUContext::setProblems(const QList<ProblemPointer>& problems)
0970 {
0971     ENSURE_CAN_WRITE
0972         clearProblems();
0973     for (const auto& problem : problems) {
0974         addProblem(problem);
0975     }
0976 }
0977 
0978 void TopDUContext::addProblem(const ProblemPointer& problem)
0979 {
0980     ENSURE_CAN_WRITE
0981 
0982         Q_ASSERT(problem);
0983 
0984     auto data = d_func_dynamic();
0985     // store for indexing
0986     LocalIndexedProblem indexedProblem(problem, this);
0987     Q_ASSERT(indexedProblem.isValid());
0988     data->m_problemsList().append(indexedProblem);
0989     Q_ASSERT(indexedProblem.data(this));
0990 }
0991 
0992 void TopDUContext::clearProblems()
0993 {
0994     ENSURE_CAN_WRITE
0995         d_func_dynamic()->m_problemsList().clear();
0996     m_dynamicData->clearProblems();
0997 }
0998 
0999 QVector<DUContext*> TopDUContext::importers() const
1000 {
1001     ENSURE_CAN_READ
1002     const QSet<DUContext*>& directImporters = m_local->m_directImporters;
1003     return QVector<DUContext*>(directImporters.begin(), directImporters.end());
1004 }
1005 
1006 QList<DUContext*> TopDUContext::loadedImporters() const
1007 {
1008     ENSURE_CAN_READ
1009     return m_local->m_directImporters.values();
1010 }
1011 
1012 QVector<DUContext::Import> TopDUContext::importedParentContexts() const
1013 {
1014     ENSURE_CAN_READ
1015     return DUContext::importedParentContexts();
1016 }
1017 
1018 bool TopDUContext::imports(const DUContext* origin, const CursorInRevision& position) const
1019 {
1020     return importsPrivate(origin, position);
1021 }
1022 
1023 bool TopDUContext::importsPrivate(const DUContext* origin, const CursorInRevision& position) const
1024 {
1025     Q_UNUSED(position);
1026 
1027     if (const auto* top = dynamic_cast<const TopDUContext*>(origin)) {
1028         QMutexLocker lock(&importStructureMutex);
1029         bool ret = recursiveImportIndices().contains(IndexedTopDUContext(const_cast<TopDUContext*>(top)));
1030         if (top == this)
1031             Q_ASSERT(ret);
1032         return ret;
1033     } else {
1034         //Cannot import a non top-context
1035         return false;
1036     }
1037 }
1038 
1039 void TopDUContext::clearImportedParentContexts()
1040 {
1041     if (usingImportsCache()) {
1042         d_func_dynamic()->m_importsCache = IndexedRecursiveImports();
1043         d_func_dynamic()->m_importsCache.insert(IndexedTopDUContext(this));
1044     }
1045 
1046     DUContext::clearImportedParentContexts();
1047 
1048     m_local->clearImportedContextsRecursively();
1049 
1050     Q_ASSERT(m_local->m_recursiveImports.count() == 0);
1051 
1052     Q_ASSERT(m_local->m_indexedRecursiveImports.count() == 1);
1053 
1054     Q_ASSERT(imports(this, CursorInRevision::invalid()));
1055 }
1056 
1057 void TopDUContext::addImportedParentContext(DUContext* context, const CursorInRevision& position, bool anonymous,
1058                                             bool temporary)
1059 {
1060     if (context == this)
1061         return;
1062 
1063     if (!dynamic_cast<TopDUContext*>(context)) {
1064         //We cannot do this, because of the extended way we treat top-context imports.
1065         qCDebug(LANGUAGE) << "tried to import a non top-context into a top-context. This is not possible.";
1066         return;
1067     }
1068 
1069     //Always make the contexts anonymous, because we care about importers in TopDUContextLocalPrivate
1070     DUContext::addImportedParentContext(context, position, anonymous, temporary);
1071 
1072     m_local->addImportedContextRecursively(static_cast<TopDUContext*>(context), temporary, true);
1073 }
1074 
1075 void TopDUContext::removeImportedParentContext(DUContext* context)
1076 {
1077     DUContext::removeImportedParentContext(context);
1078 
1079     m_local->removeImportedContextRecursively(static_cast<TopDUContext*>(context), true);
1080 }
1081 
1082 void TopDUContext::addImportedParentContexts(const QVector<QPair<TopDUContext*, CursorInRevision>>& contexts,
1083                                              bool temporary)
1084 {
1085     using Pair = QPair<TopDUContext*, CursorInRevision>;
1086 
1087     for (const Pair pair : contexts) {
1088         addImportedParentContext(pair.first, pair.second, false, temporary);
1089     }
1090 }
1091 
1092 void TopDUContext::removeImportedParentContexts(const QList<TopDUContext*>& contexts)
1093 {
1094     for (TopDUContext* context : contexts) {
1095         DUContext::removeImportedParentContext(context);
1096     }
1097 
1098     m_local->removeImportedContextsRecursively(contexts, true);
1099 }
1100 
1101 /// Returns true if this object is registered in the du-chain. If it is not, all sub-objects(context, declarations, etc.)
1102 bool TopDUContext::inDUChain() const
1103 {
1104     return m_local->m_inDuChain;
1105 }
1106 
1107 /// This flag is only used by DUChain, never change it from outside.
1108 void TopDUContext::setInDuChain(bool b)
1109 {
1110     m_local->m_inDuChain = b;
1111 }
1112 
1113 bool TopDUContext::isOnDisk() const
1114 {
1115     ///@todo Change this to releasingToDisk, and only enable it while saving a top-context to disk.
1116     return m_dynamicData->isOnDisk();
1117 }
1118 
1119 void TopDUContext::clearUsedDeclarationIndices()
1120 {
1121     ENSURE_CAN_WRITE
1122     for (unsigned int a = 0; a < d_func()->m_usedDeclarationIdsSize(); ++a)
1123         DUChain::uses()->removeUse(d_func()->m_usedDeclarationIds()[a], this);
1124 
1125     d_func_dynamic()->m_usedDeclarationIdsList().clear();
1126 }
1127 
1128 void TopDUContext::deleteUsesRecursively()
1129 {
1130     clearUsedDeclarationIndices();
1131     KDevelop::DUContext::deleteUsesRecursively();
1132 }
1133 
1134 Declaration* TopDUContext::usedDeclarationForIndex(unsigned int declarationIndex) const
1135 {
1136     ENSURE_CAN_READ
1137     if (declarationIndex & (1 << 31)) {
1138         //We use the highest bit to mark direct indices into the local declarations
1139         declarationIndex &= ~(1 << 31); //unset the highest bit
1140         return m_dynamicData->declarationForIndex(declarationIndex);
1141     } else if (declarationIndex < d_func()->m_usedDeclarationIdsSize())
1142         return d_func()->m_usedDeclarationIds()[declarationIndex].declaration(this);
1143     else
1144         return nullptr;
1145 }
1146 
1147 int TopDUContext::indexForUsedDeclaration(Declaration* declaration, bool create)
1148 {
1149     if (create) {
1150         ENSURE_CAN_WRITE
1151     } else {
1152         ENSURE_CAN_READ
1153     }
1154 
1155     if (!declaration) {
1156         return std::numeric_limits<int>::max();
1157     }
1158 
1159     if (declaration->topContext() == this && !declaration->inSymbolTable() &&
1160         !m_dynamicData->isTemporaryDeclarationIndex(declaration->ownIndex())) {
1161         uint index = declaration->ownIndex();
1162         Q_ASSERT(!(index & (1 << 31)));
1163         return ( int )(index | (1 << 31)); //We don't put context-local declarations into the list, that's a waste. We just use the mark them with the highest bit.
1164     }
1165 
1166     // if the declaration can not be found from this top-context, we create a direct
1167     // reference by index, to ensure that the use can be resolved in
1168     // usedDeclarationForIndex
1169     bool useDirectId = !recursiveImportIndices().contains(declaration->topContext());
1170     DeclarationId id(declaration->id(useDirectId));
1171 
1172     int index = -1;
1173 
1174     uint size = d_func()->m_usedDeclarationIdsSize();
1175     const DeclarationId* ids = d_func()->m_usedDeclarationIds();
1176 
1177     ///@todo Make m_usedDeclarationIds sorted, and find the decl. using binary search
1178     for (unsigned int a = 0; a < size; ++a)
1179         if (ids[a] == id) {
1180             index = a;
1181             break;
1182         }
1183 
1184     if (index != -1)
1185         return index;
1186     if (!create)
1187         return std::numeric_limits<int>::max();
1188 
1189     d_func_dynamic()->m_usedDeclarationIdsList().append(id);
1190 
1191     if (declaration->topContext() != this)
1192         DUChain::uses()->addUse(id, this);
1193 
1194     return d_func()->m_usedDeclarationIdsSize() - 1;
1195 }
1196 
1197 QVector<RangeInRevision> allUses(TopDUContext* context, Declaration* declaration, bool noEmptyRanges)
1198 {
1199     QVector<RangeInRevision> ret;
1200     int declarationIndex = context->indexForUsedDeclaration(declaration, false);
1201     if (declarationIndex == std::numeric_limits<int>::max())
1202         return ret;
1203     return allUses(context, declarationIndex, noEmptyRanges);
1204 }
1205 
1206 QExplicitlySharedDataPointer<IAstContainer> TopDUContext::ast() const
1207 {
1208     return m_local->m_ast;
1209 }
1210 
1211 void TopDUContext::clearAst()
1212 {
1213     setAst(QExplicitlySharedDataPointer<IAstContainer>(nullptr));
1214 }
1215 
1216 IndexedString TopDUContext::url() const
1217 {
1218     return d_func()->m_url;
1219 }
1220 }