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 }