File indexing completed on 2024-05-12 04:37:57

0001 /*
0002     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "declaration.h"
0009 #include "declarationdata.h"
0010 
0011 #include <QByteArray>
0012 
0013 #include <limits>
0014 
0015 #include "topducontext.h"
0016 #include "topducontextdynamicdata.h"
0017 #include "use.h"
0018 #include "forwarddeclaration.h"
0019 #include "duchain.h"
0020 #include "duchainlock.h"
0021 #include "ducontextdata.h"
0022 #include "declarationid.h"
0023 #include "uses.h"
0024 #include <serialization/indexedstring.h>
0025 #include "duchainregister.h"
0026 #include "persistentsymboltable.h"
0027 #include "types/identifiedtype.h"
0028 #include "types/structuretype.h"
0029 #include "functiondefinition.h"
0030 #include "codemodel.h"
0031 #include "specializationstore.h"
0032 #include "types/typeutils.h"
0033 #include "types/typealiastype.h"
0034 #include "classdeclaration.h"
0035 #include "serialization/stringrepository.h"
0036 #include "ducontextdynamicdata.h"
0037 
0038 namespace KDevelop {
0039 REGISTER_DUCHAIN_ITEM(Declaration);
0040 
0041 DeclarationData::DeclarationData()
0042     : m_isDefinition(false)
0043     , m_inSymbolTable(false)
0044     , m_isTypeAlias(false)
0045     , m_anonymousInContext(false)
0046     , m_isDeprecated(false)
0047     , m_alwaysForceDirect(false)
0048     , m_isAutoDeclaration(false)
0049     , m_isExplicitlyDeleted(false)
0050     , m_isExplicitlyTyped(false)
0051 {
0052 }
0053 
0054 struct DeclarationComment {
0055 };
0056 template <>
0057 class ItemRepositoryFor<DeclarationComment>
0058 {
0059     friend struct LockedItemRepository;
0060     static auto& repo()
0061     {
0062         static QMutex mutex;
0063         ///@todo Use reference counting
0064         static Repositories::StringRepository repo(QStringLiteral("Comment Repository"), &mutex);
0065         return repo;
0066     }
0067 };
0068 
0069 void initDeclarationRepositories()
0070 {
0071     LockedItemRepository::initialize<DeclarationComment>();
0072 }
0073 
0074 Declaration::Kind Declaration::kind() const
0075 {
0076     DUCHAIN_D(Declaration);
0077     return d->m_kind;
0078 }
0079 
0080 void Declaration::setKind(Kind kind)
0081 {
0082     DUCHAIN_D_DYNAMIC(Declaration);
0083     d->m_kind = kind;
0084     updateCodeModel();
0085 }
0086 
0087 bool Declaration::inDUChain() const
0088 {
0089     DUCHAIN_D(Declaration);
0090     if (d->m_anonymousInContext)
0091         return false;
0092     if (!context())
0093         return false;
0094     TopDUContext* top = topContext();
0095     return top && top->inDUChain();
0096 }
0097 
0098 Declaration::Declaration(const RangeInRevision& range, DUContext* context)
0099     : DUChainBase(*new DeclarationData, range)
0100 {
0101     d_func_dynamic()->setClassId(this);
0102     m_topContext = nullptr;
0103     m_context = nullptr;
0104     m_indexInTopContext = 0;
0105 
0106     if (context)
0107         setContext(context);
0108 }
0109 
0110 uint Declaration::ownIndex() const
0111 {
0112     ENSURE_CAN_READ
0113     return m_indexInTopContext;
0114 }
0115 
0116 Declaration::Declaration(const Declaration& rhs)
0117     : DUChainBase(*new DeclarationData(*rhs.d_func()))
0118 {
0119 }
0120 
0121 Declaration::Declaration(DeclarationData& dd) : DUChainBase(dd)
0122 {
0123 }
0124 
0125 Declaration::Declaration(DeclarationData& dd, const RangeInRevision& range)
0126     : DUChainBase(dd, range)
0127 {
0128 }
0129 
0130 bool Declaration::persistentlyDestroying() const
0131 {
0132     TopDUContext* topContext = this->topContext();
0133     return !topContext->deleting() || !topContext->isOnDisk();
0134 }
0135 
0136 Declaration::~Declaration()
0137 {
0138     uint oldOwnIndex = m_indexInTopContext;
0139 
0140     TopDUContext* topContext = this->topContext();
0141 
0142     //Only perform the actions when the top-context isn't being deleted, or when it hasn't been stored to disk
0143     if (persistentlyDestroying()) {
0144         DUCHAIN_D_DYNAMIC(Declaration);
0145 
0146         // Inserted by the builder after construction has finished.
0147         if (d->m_internalContext.context())
0148             d->m_internalContext.context()->setOwner(nullptr);
0149 
0150         setInSymbolTable(false);
0151     }
0152 
0153     // If the parent-context already has dynamic data, like for example any temporary context,
0154     // always delete the declaration, to not create crashes within more complex code like C++ template stuff.
0155     if (context() && !d_func()->m_anonymousInContext) {
0156         if (!topContext->deleting() || !topContext->isOnDisk() || context()->d_func()->isDynamic())
0157             context()->m_dynamicData->removeDeclaration(this);
0158     }
0159 
0160     clearOwnIndex();
0161 
0162     if (!topContext->deleting() || !topContext->isOnDisk()) {
0163         setContext(nullptr);
0164 
0165         setAbstractType(AbstractType::Ptr());
0166     }
0167     Q_ASSERT(d_func()->isDynamic() ==
0168              (!topContext->deleting() || !topContext->isOnDisk() ||
0169               topContext->m_dynamicData->isTemporaryDeclarationIndex(oldOwnIndex)));
0170     Q_UNUSED(oldOwnIndex);
0171 }
0172 
0173 QByteArray Declaration::comment() const
0174 {
0175     DUCHAIN_D(Declaration);
0176     if (!d->m_comment)
0177         return QByteArray();
0178 
0179     return LockedItemRepository::read<DeclarationComment>([d](const Repositories::StringRepository& repo) {
0180         return Repositories::arrayFromItem(repo.itemFromIndex(d->m_comment));
0181     });
0182 }
0183 
0184 void Declaration::setComment(const QByteArray& str)
0185 {
0186     DUCHAIN_D_DYNAMIC(Declaration);
0187     if (str.isEmpty()) {
0188         d->m_comment = 0;
0189         return;
0190     }
0191 
0192     const auto request = Repositories::StringRepositoryItemRequest(
0193         str.constData(), IndexedString::hashString(str.constData(), str.length()), str.length());
0194 
0195     d->m_comment = LockedItemRepository::write<DeclarationComment>(
0196         [&](Repositories::StringRepository& repo) { return repo.index(request); });
0197 }
0198 
0199 void Declaration::setComment(const QString& str)
0200 {
0201     setComment(str.toUtf8());
0202 }
0203 
0204 Identifier Declaration::identifier() const
0205 {
0206     //ENSURE_CAN_READ Commented out for performance reasons
0207     return d_func()->m_identifier.identifier();
0208 }
0209 
0210 const IndexedIdentifier& Declaration::indexedIdentifier() const
0211 {
0212     //ENSURE_CAN_READ Commented out for performance reasons
0213     return d_func()->m_identifier;
0214 }
0215 
0216 void Declaration::rebuildDynamicData(DUContext* parent, uint ownIndex)
0217 {
0218     DUChainBase::rebuildDynamicData(parent, ownIndex);
0219 
0220     m_context = parent;
0221     m_topContext = parent->topContext();
0222     m_indexInTopContext = ownIndex;
0223 }
0224 
0225 void Declaration::setIdentifier(const Identifier& identifier)
0226 {
0227     ENSURE_CAN_WRITE
0228         DUCHAIN_D_DYNAMIC(Declaration);
0229     bool wasInSymbolTable = d->m_inSymbolTable;
0230 
0231     setInSymbolTable(false);
0232 
0233     d->m_identifier = identifier;
0234 
0235     setInSymbolTable(wasInSymbolTable);
0236 }
0237 
0238 IndexedType Declaration::indexedType() const
0239 {
0240     return d_func()->m_type;
0241 }
0242 
0243 AbstractType::Ptr Declaration::abstractType() const
0244 {
0245     //ENSURE_CAN_READ Commented out for performance reasons
0246     return d_func()->m_type.abstractType();
0247 }
0248 
0249 void Declaration::setAbstractType(AbstractType::Ptr type)
0250 {
0251     ENSURE_CAN_WRITE
0252         DUCHAIN_D_DYNAMIC(Declaration);
0253 
0254     d->m_type = type ? type->indexed() : IndexedType();
0255 
0256     updateCodeModel();
0257 }
0258 
0259 Declaration* Declaration::specialize(const IndexedInstantiationInformation& /*specialization*/,
0260                                      const TopDUContext* topContext, int /*upDistance*/)
0261 {
0262     if (!topContext)
0263         return nullptr;
0264     return this;
0265 }
0266 
0267 QualifiedIdentifier Declaration::qualifiedIdentifier() const
0268 {
0269     ENSURE_CAN_READ
0270 
0271     QualifiedIdentifier ret;
0272     DUContext* ctx = m_context;
0273     if (ctx)
0274         ret = ctx->scopeIdentifier(true);
0275     ret.push(d_func()->m_identifier);
0276     return ret;
0277 }
0278 
0279 DUContext* Declaration::context() const
0280 {
0281     //ENSURE_CAN_READ Commented out for performance reasons
0282     return m_context;
0283 }
0284 
0285 bool Declaration::isAnonymous() const
0286 {
0287     return d_func()->m_anonymousInContext;
0288 }
0289 
0290 void Declaration::setContext(DUContext* context, bool anonymous)
0291 {
0292     Q_ASSERT(!context || context->topContext());
0293 
0294     DUCHAIN_D_DYNAMIC(Declaration);
0295 
0296     if (context == m_context && anonymous == d->m_anonymousInContext) {
0297         // skip costly operations below when the same context is set
0298         // this happens often when updating a TopDUContext from the cache
0299         return;
0300     }
0301 
0302     setInSymbolTable(false);
0303 
0304     //We don't need to clear, because it's not allowed to move from one top-context into another
0305 //   clearOwnIndex();
0306 
0307     if (m_context && context) {
0308         Q_ASSERT(m_context->topContext() == context->topContext());
0309     }
0310 
0311     if (m_context) {
0312         if (!d->m_anonymousInContext) {
0313             m_context->m_dynamicData->removeDeclaration(this);
0314         }
0315     }
0316 
0317     if (context)
0318         m_topContext = context->topContext();
0319     else
0320         m_topContext = nullptr;
0321 
0322     d->m_anonymousInContext = anonymous;
0323     m_context = context;
0324 
0325     if (context) {
0326         if (!m_indexInTopContext)
0327             allocateOwnIndex();
0328 
0329         if (!d->m_anonymousInContext) {
0330             context->m_dynamicData->addDeclaration(this);
0331         }
0332 
0333         if (context->inSymbolTable() && !anonymous)
0334             setInSymbolTable(true);
0335     }
0336 }
0337 
0338 void Declaration::clearOwnIndex()
0339 {
0340     if (!m_indexInTopContext)
0341         return;
0342 
0343     if (!context() || (!d_func()->m_anonymousInContext && !context()->isAnonymous())) {
0344         ENSURE_CAN_WRITE
0345     }
0346 
0347     if (m_indexInTopContext) {
0348         Q_ASSERT(m_topContext);
0349         m_topContext->m_dynamicData->clearDeclarationIndex(this);
0350     }
0351     m_indexInTopContext = 0;
0352 }
0353 
0354 void Declaration::allocateOwnIndex()
0355 {
0356     ///@todo Fix multithreading stuff with template instantiation, preferably using some internal mutexes
0357 //   if(context() && (!context()->isAnonymous() && !d_func()->m_anonymousInContext)) {
0358 //     ENSURE_CAN_WRITE
0359 //   }
0360 
0361     Q_ASSERT(m_topContext);
0362 
0363     m_indexInTopContext = m_topContext->m_dynamicData->allocateDeclarationIndex(this,
0364                                                                                 d_func()->m_anonymousInContext || !context() ||
0365                                                                                 context()->isAnonymous());
0366     Q_ASSERT(m_indexInTopContext);
0367 
0368     if (!m_topContext->m_dynamicData->declarationForIndex(m_indexInTopContext))
0369         qFatal("Could not re-retrieve declaration\nindex: %d", m_indexInTopContext);
0370 }
0371 
0372 const Declaration* Declaration::logicalDeclaration(const TopDUContext* topContext) const
0373 {
0374     ENSURE_CAN_READ
0375     if (isForwardDeclaration()) {
0376         const auto dec = static_cast<const ForwardDeclaration*>(this);
0377         Declaration* ret = dec->resolve(topContext);
0378         if (ret)
0379             return ret;
0380     }
0381     return this;
0382 }
0383 
0384 Declaration* Declaration::logicalDeclaration(const TopDUContext* topContext)
0385 {
0386     ENSURE_CAN_READ
0387     if (isForwardDeclaration()) {
0388         const auto dec = static_cast<const ForwardDeclaration*>(this);
0389         Declaration* ret = dec->resolve(topContext);
0390         if (ret)
0391             return ret;
0392     }
0393     return this;
0394 }
0395 
0396 DUContext* Declaration::logicalInternalContext(const TopDUContext* topContext) const
0397 {
0398     ENSURE_CAN_READ
0399 
0400     if (!isDefinition()) {
0401         Declaration* def = FunctionDefinition::definition(this);
0402         if (def)
0403             return def->internalContext();
0404     }
0405 
0406     if (d_func()->m_isTypeAlias) {
0407         ///If this is a type-alias, return the internal context of the actual type.
0408         TypeAliasType::Ptr t = type<TypeAliasType>();
0409         if (t) {
0410             AbstractType::Ptr target = t->type();
0411 
0412             auto* idType = dynamic_cast<IdentifiedType*>(target.data());
0413             if (idType) {
0414                 Declaration* decl = idType->declaration(topContext);
0415                 if (decl && decl != this) {
0416                     return decl->logicalInternalContext(topContext);
0417                 }
0418             }
0419         }
0420     }
0421 
0422     return internalContext();
0423 }
0424 
0425 DUContext* Declaration::internalContext() const
0426 {
0427 //   ENSURE_CAN_READ
0428     return d_func()->m_internalContext.context();
0429 }
0430 
0431 void Declaration::setInternalContext(DUContext* context)
0432 {
0433     if (this->context()) {
0434         ENSURE_CAN_WRITE
0435     }
0436     DUCHAIN_D_DYNAMIC(Declaration);
0437 
0438     if (context == d->m_internalContext.context())
0439         return;
0440 
0441     if (!m_topContext) {
0442         //Take the top-context from the other side. We need to allocate an index, so we can safely call setOwner(..)
0443         m_topContext = context->topContext();
0444         allocateOwnIndex();
0445     }
0446 
0447     DUContext* oldInternalContext = d->m_internalContext.context();
0448 
0449     d->m_internalContext = context;
0450 
0451     //Q_ASSERT( !oldInternalContext || oldInternalContext->owner() == this );
0452     if (oldInternalContext && oldInternalContext->owner() == this)
0453         oldInternalContext->setOwner(nullptr);
0454 
0455     if (context)
0456         context->setOwner(this);
0457 }
0458 
0459 bool Declaration::operator ==(const Declaration& other) const
0460 {
0461     ENSURE_CAN_READ
0462 
0463     return this == &other;
0464 }
0465 
0466 QString Declaration::toString() const
0467 {
0468     return QStringLiteral("%3 %4").arg(abstractType() ? abstractType()->toString() : QStringLiteral(
0469                                            "<notype>"), identifier().toString());
0470 }
0471 
0472 bool Declaration::isDefinition() const
0473 {
0474     ENSURE_CAN_READ
0475         DUCHAIN_D(Declaration);
0476 
0477     return d->m_isDefinition;
0478 }
0479 
0480 void Declaration::setDeclarationIsDefinition(bool dd)
0481 {
0482     ENSURE_CAN_WRITE
0483         DUCHAIN_D_DYNAMIC(Declaration);
0484     d->m_isDefinition = dd;
0485 }
0486 
0487 bool Declaration::isAutoDeclaration() const
0488 {
0489     return d_func()->m_isAutoDeclaration;
0490 }
0491 
0492 void Declaration::setAutoDeclaration(bool _auto)
0493 {
0494     d_func_dynamic()->m_isAutoDeclaration = _auto;
0495 }
0496 
0497 bool Declaration::isDeprecated() const
0498 {
0499     return d_func()->m_isDeprecated;
0500 }
0501 
0502 void Declaration::setDeprecated(bool deprecated)
0503 {
0504     d_func_dynamic()->m_isDeprecated = deprecated;
0505 }
0506 
0507 bool Declaration::alwaysForceDirect() const
0508 {
0509     return d_func()->m_alwaysForceDirect;
0510 }
0511 
0512 void Declaration::setAlwaysForceDirect(bool direct)
0513 {
0514     d_func_dynamic()->m_alwaysForceDirect = direct;
0515 }
0516 
0517 bool Declaration::isExplicitlyDeleted() const
0518 {
0519     return d_func()->m_isExplicitlyDeleted;
0520 }
0521 
0522 void Declaration::setExplicitlyDeleted(bool deleted)
0523 {
0524     d_func_dynamic()->m_isExplicitlyDeleted = deleted;
0525 }
0526 
0527 bool Declaration::isExplicitlyTyped() const
0528 {
0529     return d_func()->m_isExplicitlyTyped;
0530 }
0531 
0532 void Declaration::setExplicitlyTyped(bool explicitlyTyped)
0533 {
0534     d_func_dynamic()->m_isExplicitlyTyped = explicitlyTyped;
0535 }
0536 
0537 ///@todo see whether it would be useful to create an own TypeAliasDeclaration sub-class for this
0538 bool Declaration::isTypeAlias() const
0539 {
0540     DUCHAIN_D(Declaration);
0541     return d->m_isTypeAlias;
0542 }
0543 
0544 void Declaration::setIsTypeAlias(bool isTypeAlias)
0545 {
0546     DUCHAIN_D_DYNAMIC(Declaration);
0547     d->m_isTypeAlias = isTypeAlias;
0548 }
0549 
0550 IndexedInstantiationInformation Declaration::specialization() const
0551 {
0552     return IndexedInstantiationInformation();
0553 }
0554 
0555 void Declaration::activateSpecialization()
0556 {
0557     if (specialization().index()) {
0558         DeclarationId baseId(id());
0559         baseId.setSpecialization(IndexedInstantiationInformation());
0560         SpecializationStore::self().set(baseId, specialization());
0561     }
0562 }
0563 
0564 DeclarationId Declaration::id(bool forceDirect) const
0565 {
0566     ENSURE_CAN_READ
0567     if (inSymbolTable() && !forceDirect && !alwaysForceDirect())
0568         return DeclarationId(qualifiedIdentifier(), additionalIdentity(), specialization());
0569     else
0570         return DeclarationId(IndexedDeclaration(const_cast<Declaration*>(this)), specialization());
0571 }
0572 
0573 bool Declaration::inSymbolTable() const
0574 {
0575     DUCHAIN_D(Declaration);
0576     return d->m_inSymbolTable;
0577 }
0578 
0579 CodeModelItem::Kind kindForDeclaration(Declaration* decl)
0580 {
0581     CodeModelItem::Kind kind = CodeModelItem::Unknown;
0582 
0583     if (decl->kind() == Declaration::Namespace)
0584         return CodeModelItem::Namespace;
0585 
0586     if (decl->isFunctionDeclaration()) {
0587         kind = CodeModelItem::Function;
0588     }
0589 
0590     if (decl->kind() == Declaration::Type && (decl->type<StructureType>() || dynamic_cast<ClassDeclaration*>(decl)))
0591         kind = CodeModelItem::Class;
0592 
0593     if (kind == CodeModelItem::Unknown && decl->kind() == Declaration::Instance)
0594         kind = CodeModelItem::Variable;
0595 
0596     if (decl->isForwardDeclaration())
0597         kind = ( CodeModelItem::Kind )(kind | CodeModelItem::ForwardDeclaration);
0598 
0599     if (decl->context() && decl->context()->type() == DUContext::Class)
0600         kind = ( CodeModelItem::Kind )(kind | CodeModelItem::ClassMember);
0601 
0602     return kind;
0603 }
0604 
0605 void Declaration::updateCodeModel()
0606 {
0607     DUCHAIN_D(Declaration);
0608     if (!d->m_identifier.isEmpty() && d->m_inSymbolTable) {
0609         QualifiedIdentifier id(qualifiedIdentifier());
0610         CodeModel::self().updateItem(url(), id, kindForDeclaration(this));
0611     }
0612 }
0613 
0614 void Declaration::setInSymbolTable(bool inSymbolTable)
0615 {
0616     DUCHAIN_D_DYNAMIC(Declaration);
0617     if (!d->m_identifier.isEmpty()) {
0618         if (!d->m_inSymbolTable && inSymbolTable) {
0619             QualifiedIdentifier id(qualifiedIdentifier());
0620             PersistentSymbolTable::self().addDeclaration(id, this);
0621 
0622             CodeModel::self().addItem(url(), id, kindForDeclaration(this));
0623         } else if (d->m_inSymbolTable && !inSymbolTable) {
0624             QualifiedIdentifier id(qualifiedIdentifier());
0625             PersistentSymbolTable::self().removeDeclaration(id, this);
0626 
0627             CodeModel::self().removeItem(url(), id);
0628         }
0629     }
0630     d->m_inSymbolTable = inSymbolTable;
0631 }
0632 
0633 TopDUContext* Declaration::topContext() const
0634 {
0635     return m_topContext;
0636 }
0637 
0638 Declaration* Declaration::clonePrivate() const
0639 {
0640     return new Declaration(*this);
0641 }
0642 
0643 Declaration* Declaration::clone() const
0644 {
0645     Declaration* ret = clonePrivate();
0646     ret->d_func_dynamic()->m_inSymbolTable = false;
0647     return ret;
0648 }
0649 
0650 bool Declaration::isForwardDeclaration() const
0651 {
0652     return false;
0653 }
0654 
0655 bool Declaration::isFunctionDeclaration() const
0656 {
0657     return false;
0658 }
0659 
0660 uint Declaration::additionalIdentity() const
0661 {
0662     return 0;
0663 }
0664 
0665 bool Declaration::equalQualifiedIdentifier(const Declaration* rhs) const
0666 {
0667     ENSURE_CAN_READ
0668         DUCHAIN_D(Declaration);
0669     if (d->m_identifier != rhs->d_func()->m_identifier)
0670         return false;
0671 
0672     return m_context->equalScopeIdentifier(m_context);
0673 }
0674 
0675 QMap<IndexedString, QVector<RangeInRevision>> Declaration::uses() const
0676 {
0677     ENSURE_CAN_READ
0678     QMap<IndexedString, QMap<RangeInRevision, bool>> tempUses;
0679 
0680     //First, search for uses within the own context
0681     {
0682         QMap<RangeInRevision, bool>& ranges(tempUses[topContext()->url()]);
0683         const auto useRanges = allUses(topContext(), const_cast<Declaration*>(this));
0684         for (const RangeInRevision range : useRanges) {
0685             ranges[range] = true;
0686         }
0687     }
0688 
0689     DeclarationId _id = id();
0690     KDevVarLengthArray<IndexedTopDUContext> useContexts = DUChain::uses()->uses(_id);
0691     if (!_id.isDirect()) { // also check uses based on direct IDs
0692         KDevVarLengthArray<IndexedTopDUContext> directUseContexts = DUChain::uses()->uses(id(true));
0693         useContexts.append(directUseContexts.data(), directUseContexts.size());
0694     }
0695 
0696     for (const IndexedTopDUContext indexedContext : qAsConst(useContexts)) {
0697         TopDUContext* context = indexedContext.data();
0698         if (context) {
0699             QMap<RangeInRevision, bool>& ranges(tempUses[context->url()]);
0700             const auto useRanges = allUses(context, const_cast<Declaration*>(this));
0701             for (const RangeInRevision range : useRanges) {
0702                 ranges[range] = true;
0703             }
0704         }
0705     }
0706 
0707     QMap<IndexedString, QVector<RangeInRevision>> ret;
0708 
0709     for (QMap<IndexedString, QMap<RangeInRevision, bool>>::const_iterator it = tempUses.constBegin();
0710          it != tempUses.constEnd(); ++it) {
0711         if (!(*it).isEmpty()) {
0712             auto& list = ret[it.key()];
0713             list.reserve((*it).size());
0714             for (QMap<RangeInRevision, bool>::const_iterator it2 = (*it).constBegin(); it2 != (*it).constEnd(); ++it2)
0715                 list << it2.key();
0716         }
0717     }
0718 
0719     return ret;
0720 }
0721 
0722 bool hasDeclarationUse(DUContext* context, int declIdx)
0723 {
0724     bool ret = false;
0725     int usescount = context->usesCount();
0726     const Use* uses = context->uses();
0727 
0728     for (int i = 0; !ret && i < usescount; ++i) {
0729         ret = uses[i].m_declarationIndex == declIdx;
0730     }
0731 
0732     const auto childContexts = context->childContexts();
0733     for (DUContext* child : childContexts) {
0734         ret = ret || hasDeclarationUse(child, declIdx);
0735         if (ret)
0736             break;
0737     }
0738 
0739     return ret;
0740 }
0741 
0742 bool Declaration::hasUses() const
0743 {
0744     ENSURE_CAN_READ
0745     int idx = topContext()->indexForUsedDeclaration(const_cast<Declaration*>(this), false);
0746     bool ret = idx != std::numeric_limits<int>::max() && (idx >= 0 || hasDeclarationUse(topContext(), idx)); //hasLocalUses
0747     DeclarationId myId = id();
0748 
0749     if (!ret && DUChain::uses()->hasUses(myId)) {
0750         ret = true;
0751     }
0752 
0753     if (!ret && !myId.isDirect() && DUChain::uses()->hasUses(id(true))) {
0754         ret = true;
0755     }
0756 
0757     return ret;
0758 }
0759 
0760 QMap<IndexedString, QVector<KTextEditor::Range>> Declaration::usesCurrentRevision() const
0761 {
0762     ENSURE_CAN_READ
0763     QMap<IndexedString, QMap<KTextEditor::Range, bool>> tempUses;
0764 
0765     //First, search for uses within the own context
0766     {
0767         QMap<KTextEditor::Range, bool>& ranges(tempUses[topContext()->url()]);
0768         const auto useRanges = allUses(topContext(), const_cast<Declaration*>(this));
0769         for (const RangeInRevision range : useRanges) {
0770             ranges[topContext()->transformFromLocalRevision(range)] = true;
0771         }
0772     }
0773 
0774     DeclarationId _id = id();
0775     KDevVarLengthArray<IndexedTopDUContext> useContexts = DUChain::uses()->uses(_id);
0776     if (!_id.isDirect()) { // also check uses based on direct IDs
0777         KDevVarLengthArray<IndexedTopDUContext> directUseContexts = DUChain::uses()->uses(id(true));
0778         useContexts.append(directUseContexts.data(), directUseContexts.size());
0779     }
0780 
0781     for (const IndexedTopDUContext indexedContext : qAsConst(useContexts)) {
0782         TopDUContext* context = indexedContext.data();
0783         if (context) {
0784             QMap<KTextEditor::Range, bool>& ranges(tempUses[context->url()]);
0785             const auto useRanges = allUses(context, const_cast<Declaration*>(this));
0786             for (const RangeInRevision range : useRanges) {
0787                 ranges[context->transformFromLocalRevision(range)] = true;
0788             }
0789         }
0790     }
0791 
0792     QMap<IndexedString, QVector<KTextEditor::Range>> ret;
0793 
0794     for (QMap<IndexedString, QMap<KTextEditor::Range, bool>>::const_iterator it = tempUses.constBegin();
0795          it != tempUses.constEnd(); ++it) {
0796         if (!(*it).isEmpty()) {
0797             auto& list = ret[it.key()];
0798             list.reserve((*it).size());
0799             for (QMap<KTextEditor::Range, bool>::const_iterator it2 = (*it).constBegin(); it2 != (*it).constEnd();
0800                  ++it2)
0801                 list << it2.key();
0802         }
0803     }
0804 
0805     return ret;
0806 }
0807 }