1 /*
2 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
3 SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6 */
7
8 #include "declaration.h"
9 #include "declarationdata.h"
10
11 #include <QByteArray>
12
13 #include <limits>
14
15 #include "topducontext.h"
16 #include "topducontextdynamicdata.h"
17 #include "use.h"
18 #include "forwarddeclaration.h"
19 #include "duchain.h"
20 #include "duchainlock.h"
21 #include "ducontextdata.h"
22 #include "declarationid.h"
23 #include "uses.h"
24 #include <serialization/indexedstring.h>
25 #include "duchainregister.h"
26 #include "persistentsymboltable.h"
27 #include "types/identifiedtype.h"
28 #include "types/structuretype.h"
29 #include "functiondefinition.h"
30 #include "codemodel.h"
31 #include "specializationstore.h"
32 #include "types/typeutils.h"
33 #include "types/typealiastype.h"
34 #include "classdeclaration.h"
35 #include "serialization/stringrepository.h"
36 #include "ducontextdynamicdata.h"
37
38 namespace KDevelop {
39 REGISTER_DUCHAIN_ITEM(Declaration);
40
DeclarationData()41 DeclarationData::DeclarationData()
42 : m_isDefinition(false)
43 , m_inSymbolTable(false)
44 , m_isTypeAlias(false)
45 , m_anonymousInContext(false)
46 , m_isDeprecated(false)
47 , m_alwaysForceDirect(false)
48 , m_isAutoDeclaration(false)
49 , m_isExplicitlyDeleted(false)
50 , m_isExplicitlyTyped(false)
51 {
52 }
53
54 ///@todo Use reference counting
commentRepository()55 static Repositories::StringRepository& commentRepository()
56 {
57 static Repositories::StringRepository commentRepositoryObject(QStringLiteral("Comment Repository"));
58 return commentRepositoryObject;
59 }
60
initDeclarationRepositories()61 void initDeclarationRepositories()
62 {
63 commentRepository();
64 }
65
kind() const66 Declaration::Kind Declaration::kind() const
67 {
68 DUCHAIN_D(Declaration);
69 return d->m_kind;
70 }
71
setKind(Kind kind)72 void Declaration::setKind(Kind kind)
73 {
74 DUCHAIN_D_DYNAMIC(Declaration);
75 d->m_kind = kind;
76 updateCodeModel();
77 }
78
inDUChain() const79 bool Declaration::inDUChain() const
80 {
81 DUCHAIN_D(Declaration);
82 if (d->m_anonymousInContext)
83 return false;
84 if (!context())
85 return false;
86 TopDUContext* top = topContext();
87 return top && top->inDUChain();
88 }
89
Declaration(const RangeInRevision & range,DUContext * context)90 Declaration::Declaration(const RangeInRevision& range, DUContext* context)
91 : DUChainBase(*new DeclarationData, range)
92 {
93 d_func_dynamic()->setClassId(this);
94 m_topContext = nullptr;
95 m_context = nullptr;
96 m_indexInTopContext = 0;
97
98 if (context)
99 setContext(context);
100 }
101
ownIndex() const102 uint Declaration::ownIndex() const
103 {
104 ENSURE_CAN_READ
105 return m_indexInTopContext;
106 }
107
Declaration(const Declaration & rhs)108 Declaration::Declaration(const Declaration& rhs)
109 : DUChainBase(*new DeclarationData(*rhs.d_func()))
110 {
111 }
112
Declaration(DeclarationData & dd)113 Declaration::Declaration(DeclarationData& dd) : DUChainBase(dd)
114 {
115 }
116
Declaration(DeclarationData & dd,const RangeInRevision & range)117 Declaration::Declaration(DeclarationData& dd, const RangeInRevision& range)
118 : DUChainBase(dd, range)
119 {
120 }
121
persistentlyDestroying() const122 bool Declaration::persistentlyDestroying() const
123 {
124 TopDUContext* topContext = this->topContext();
125 return !topContext->deleting() || !topContext->isOnDisk();
126 }
127
~Declaration()128 Declaration::~Declaration()
129 {
130 uint oldOwnIndex = m_indexInTopContext;
131
132 TopDUContext* topContext = this->topContext();
133
134 //Only perform the actions when the top-context isn't being deleted, or when it hasn't been stored to disk
135 if (persistentlyDestroying()) {
136 DUCHAIN_D_DYNAMIC(Declaration);
137
138 // Inserted by the builder after construction has finished.
139 if (d->m_internalContext.context())
140 d->m_internalContext.context()->setOwner(nullptr);
141
142 setInSymbolTable(false);
143 }
144
145 // If the parent-context already has dynamic data, like for example any temporary context,
146 // always delete the declaration, to not create crashes within more complex code like C++ template stuff.
147 if (context() && !d_func()->m_anonymousInContext) {
148 if (!topContext->deleting() || !topContext->isOnDisk() || context()->d_func()->isDynamic())
149 context()->m_dynamicData->removeDeclaration(this);
150 }
151
152 clearOwnIndex();
153
154 if (!topContext->deleting() || !topContext->isOnDisk()) {
155 setContext(nullptr);
156
157 setAbstractType(AbstractType::Ptr());
158 }
159 Q_ASSERT(d_func()->isDynamic() ==
160 (!topContext->deleting() || !topContext->isOnDisk() ||
161 topContext->m_dynamicData->isTemporaryDeclarationIndex(oldOwnIndex)));
162 Q_UNUSED(oldOwnIndex);
163 }
164
comment() const165 QByteArray Declaration::comment() const
166 {
167 DUCHAIN_D(Declaration);
168 if (!d->m_comment)
169 return nullptr;
170 else
171 return Repositories::arrayFromItem(commentRepository().itemFromIndex(d->m_comment));
172 }
173
setComment(const QByteArray & str)174 void Declaration::setComment(const QByteArray& str)
175 {
176 DUCHAIN_D_DYNAMIC(Declaration);
177 if (str.isEmpty())
178 d->m_comment = 0;
179 else
180 d->m_comment =
181 commentRepository().index(Repositories::StringRepositoryItemRequest(str.constData(),
182 IndexedString::hashString(str.constData(),
183 str.length()),
184 str.length()));
185 }
186
setComment(const QString & str)187 void Declaration::setComment(const QString& str)
188 {
189 setComment(str.toUtf8());
190 }
191
identifier() const192 Identifier Declaration::identifier() const
193 {
194 //ENSURE_CAN_READ Commented out for performance reasons
195 return d_func()->m_identifier.identifier();
196 }
197
indexedIdentifier() const198 const IndexedIdentifier& Declaration::indexedIdentifier() const
199 {
200 //ENSURE_CAN_READ Commented out for performance reasons
201 return d_func()->m_identifier;
202 }
203
rebuildDynamicData(DUContext * parent,uint ownIndex)204 void Declaration::rebuildDynamicData(DUContext* parent, uint ownIndex)
205 {
206 DUChainBase::rebuildDynamicData(parent, ownIndex);
207
208 m_context = parent;
209 m_topContext = parent->topContext();
210 m_indexInTopContext = ownIndex;
211 }
212
setIdentifier(const Identifier & identifier)213 void Declaration::setIdentifier(const Identifier& identifier)
214 {
215 ENSURE_CAN_WRITE
216 DUCHAIN_D_DYNAMIC(Declaration);
217 bool wasInSymbolTable = d->m_inSymbolTable;
218
219 setInSymbolTable(false);
220
221 d->m_identifier = identifier;
222
223 setInSymbolTable(wasInSymbolTable);
224 }
225
indexedType() const226 IndexedType Declaration::indexedType() const
227 {
228 return d_func()->m_type;
229 }
230
abstractType() const231 AbstractType::Ptr Declaration::abstractType() const
232 {
233 //ENSURE_CAN_READ Commented out for performance reasons
234 return d_func()->m_type.abstractType();
235 }
236
setAbstractType(AbstractType::Ptr type)237 void Declaration::setAbstractType(AbstractType::Ptr type)
238 {
239 ENSURE_CAN_WRITE
240 DUCHAIN_D_DYNAMIC(Declaration);
241
242 d->m_type = type ? type->indexed() : IndexedType();
243
244 updateCodeModel();
245 }
246
specialize(const IndexedInstantiationInformation &,const TopDUContext * topContext,int)247 Declaration* Declaration::specialize(const IndexedInstantiationInformation& /*specialization*/,
248 const TopDUContext* topContext, int /*upDistance*/)
249 {
250 if (!topContext)
251 return nullptr;
252 return this;
253 }
254
qualifiedIdentifier() const255 QualifiedIdentifier Declaration::qualifiedIdentifier() const
256 {
257 ENSURE_CAN_READ
258
259 QualifiedIdentifier ret;
260 DUContext* ctx = m_context;
261 if (ctx)
262 ret = ctx->scopeIdentifier(true);
263 ret.push(d_func()->m_identifier);
264 return ret;
265 }
266
context() const267 DUContext* Declaration::context() const
268 {
269 //ENSURE_CAN_READ Commented out for performance reasons
270 return m_context;
271 }
272
isAnonymous() const273 bool Declaration::isAnonymous() const
274 {
275 return d_func()->m_anonymousInContext;
276 }
277
setContext(DUContext * context,bool anonymous)278 void Declaration::setContext(DUContext* context, bool anonymous)
279 {
280 Q_ASSERT(!context || context->topContext());
281
282 DUCHAIN_D_DYNAMIC(Declaration);
283
284 if (context == m_context && anonymous == d->m_anonymousInContext) {
285 // skip costly operations below when the same context is set
286 // this happens often when updating a TopDUContext from the cache
287 return;
288 }
289
290 setInSymbolTable(false);
291
292 //We don't need to clear, because it's not allowed to move from one top-context into another
293 // clearOwnIndex();
294
295 if (m_context && context) {
296 Q_ASSERT(m_context->topContext() == context->topContext());
297 }
298
299 if (m_context) {
300 if (!d->m_anonymousInContext) {
301 m_context->m_dynamicData->removeDeclaration(this);
302 }
303 }
304
305 if (context)
306 m_topContext = context->topContext();
307 else
308 m_topContext = nullptr;
309
310 d->m_anonymousInContext = anonymous;
311 m_context = context;
312
313 if (context) {
314 if (!m_indexInTopContext)
315 allocateOwnIndex();
316
317 if (!d->m_anonymousInContext) {
318 context->m_dynamicData->addDeclaration(this);
319 }
320
321 if (context->inSymbolTable() && !anonymous)
322 setInSymbolTable(true);
323 }
324 }
325
clearOwnIndex()326 void Declaration::clearOwnIndex()
327 {
328 if (!m_indexInTopContext)
329 return;
330
331 if (!context() || (!d_func()->m_anonymousInContext && !context()->isAnonymous())) {
332 ENSURE_CAN_WRITE
333 }
334
335 if (m_indexInTopContext) {
336 Q_ASSERT(m_topContext);
337 m_topContext->m_dynamicData->clearDeclarationIndex(this);
338 }
339 m_indexInTopContext = 0;
340 }
341
allocateOwnIndex()342 void Declaration::allocateOwnIndex()
343 {
344 ///@todo Fix multithreading stuff with template instantiation, preferably using some internal mutexes
345 // if(context() && (!context()->isAnonymous() && !d_func()->m_anonymousInContext)) {
346 // ENSURE_CAN_WRITE
347 // }
348
349 Q_ASSERT(m_topContext);
350
351 m_indexInTopContext = m_topContext->m_dynamicData->allocateDeclarationIndex(this,
352 d_func()->m_anonymousInContext || !context() ||
353 context()->isAnonymous());
354 Q_ASSERT(m_indexInTopContext);
355
356 if (!m_topContext->m_dynamicData->declarationForIndex(m_indexInTopContext))
357 qFatal("Could not re-retrieve declaration\nindex: %d", m_indexInTopContext);
358 }
359
logicalDeclaration(const TopDUContext * topContext) const360 const Declaration* Declaration::logicalDeclaration(const TopDUContext* topContext) const
361 {
362 ENSURE_CAN_READ
363 if (isForwardDeclaration()) {
364 const auto dec = static_cast<const ForwardDeclaration*>(this);
365 Declaration* ret = dec->resolve(topContext);
366 if (ret)
367 return ret;
368 }
369 return this;
370 }
371
logicalDeclaration(const TopDUContext * topContext)372 Declaration* Declaration::logicalDeclaration(const TopDUContext* topContext)
373 {
374 ENSURE_CAN_READ
375 if (isForwardDeclaration()) {
376 const auto dec = static_cast<const ForwardDeclaration*>(this);
377 Declaration* ret = dec->resolve(topContext);
378 if (ret)
379 return ret;
380 }
381 return this;
382 }
383
logicalInternalContext(const TopDUContext * topContext) const384 DUContext* Declaration::logicalInternalContext(const TopDUContext* topContext) const
385 {
386 ENSURE_CAN_READ
387
388 if (!isDefinition()) {
389 Declaration* def = FunctionDefinition::definition(this);
390 if (def)
391 return def->internalContext();
392 }
393
394 if (d_func()->m_isTypeAlias) {
395 ///If this is a type-alias, return the internal context of the actual type.
396 TypeAliasType::Ptr t = type<TypeAliasType>();
397 if (t) {
398 AbstractType::Ptr target = t->type();
399
400 auto* idType = dynamic_cast<IdentifiedType*>(target.data());
401 if (idType) {
402 Declaration* decl = idType->declaration(topContext);
403 if (decl && decl != this) {
404 return decl->logicalInternalContext(topContext);
405 }
406 }
407 }
408 }
409
410 return internalContext();
411 }
412
internalContext() const413 DUContext* Declaration::internalContext() const
414 {
415 // ENSURE_CAN_READ
416 return d_func()->m_internalContext.context();
417 }
418
setInternalContext(DUContext * context)419 void Declaration::setInternalContext(DUContext* context)
420 {
421 if (this->context()) {
422 ENSURE_CAN_WRITE
423 }
424 DUCHAIN_D_DYNAMIC(Declaration);
425
426 if (context == d->m_internalContext.context())
427 return;
428
429 if (!m_topContext) {
430 //Take the top-context from the other side. We need to allocate an index, so we can safely call setOwner(..)
431 m_topContext = context->topContext();
432 allocateOwnIndex();
433 }
434
435 DUContext* oldInternalContext = d->m_internalContext.context();
436
437 d->m_internalContext = context;
438
439 //Q_ASSERT( !oldInternalContext || oldInternalContext->owner() == this );
440 if (oldInternalContext && oldInternalContext->owner() == this)
441 oldInternalContext->setOwner(nullptr);
442
443 if (context)
444 context->setOwner(this);
445 }
446
operator ==(const Declaration & other) const447 bool Declaration::operator ==(const Declaration& other) const
448 {
449 ENSURE_CAN_READ
450
451 return this == &other;
452 }
453
toString() const454 QString Declaration::toString() const
455 {
456 return QStringLiteral("%3 %4").arg(abstractType() ? abstractType()->toString() : QStringLiteral(
457 "<notype>"), identifier().toString());
458 }
459
isDefinition() const460 bool Declaration::isDefinition() const
461 {
462 ENSURE_CAN_READ
463 DUCHAIN_D(Declaration);
464
465 return d->m_isDefinition;
466 }
467
setDeclarationIsDefinition(bool dd)468 void Declaration::setDeclarationIsDefinition(bool dd)
469 {
470 ENSURE_CAN_WRITE
471 DUCHAIN_D_DYNAMIC(Declaration);
472 d->m_isDefinition = dd;
473 }
474
isAutoDeclaration() const475 bool Declaration::isAutoDeclaration() const
476 {
477 return d_func()->m_isAutoDeclaration;
478 }
479
setAutoDeclaration(bool _auto)480 void Declaration::setAutoDeclaration(bool _auto)
481 {
482 d_func_dynamic()->m_isAutoDeclaration = _auto;
483 }
484
isDeprecated() const485 bool Declaration::isDeprecated() const
486 {
487 return d_func()->m_isDeprecated;
488 }
489
setDeprecated(bool deprecated)490 void Declaration::setDeprecated(bool deprecated)
491 {
492 d_func_dynamic()->m_isDeprecated = deprecated;
493 }
494
alwaysForceDirect() const495 bool Declaration::alwaysForceDirect() const
496 {
497 return d_func()->m_alwaysForceDirect;
498 }
499
setAlwaysForceDirect(bool direct)500 void Declaration::setAlwaysForceDirect(bool direct)
501 {
502 d_func_dynamic()->m_alwaysForceDirect = direct;
503 }
504
isExplicitlyDeleted() const505 bool Declaration::isExplicitlyDeleted() const
506 {
507 return d_func()->m_isExplicitlyDeleted;
508 }
509
setExplicitlyDeleted(bool deleted)510 void Declaration::setExplicitlyDeleted(bool deleted)
511 {
512 d_func_dynamic()->m_isExplicitlyDeleted = deleted;
513 }
514
isExplicitlyTyped() const515 bool Declaration::isExplicitlyTyped() const
516 {
517 return d_func()->m_isExplicitlyTyped;
518 }
519
setExplicitlyTyped(bool explicitlyTyped)520 void Declaration::setExplicitlyTyped(bool explicitlyTyped)
521 {
522 d_func_dynamic()->m_isExplicitlyTyped = explicitlyTyped;
523 }
524
525 ///@todo see whether it would be useful to create an own TypeAliasDeclaration sub-class for this
isTypeAlias() const526 bool Declaration::isTypeAlias() const
527 {
528 DUCHAIN_D(Declaration);
529 return d->m_isTypeAlias;
530 }
531
setIsTypeAlias(bool isTypeAlias)532 void Declaration::setIsTypeAlias(bool isTypeAlias)
533 {
534 DUCHAIN_D_DYNAMIC(Declaration);
535 d->m_isTypeAlias = isTypeAlias;
536 }
537
specialization() const538 IndexedInstantiationInformation Declaration::specialization() const
539 {
540 return IndexedInstantiationInformation();
541 }
542
activateSpecialization()543 void Declaration::activateSpecialization()
544 {
545 if (specialization().index()) {
546 DeclarationId baseId(id());
547 baseId.setSpecialization(IndexedInstantiationInformation());
548 SpecializationStore::self().set(baseId, specialization());
549 }
550 }
551
id(bool forceDirect) const552 DeclarationId Declaration::id(bool forceDirect) const
553 {
554 ENSURE_CAN_READ
555 if (inSymbolTable() && !forceDirect && !alwaysForceDirect())
556 return DeclarationId(qualifiedIdentifier(), additionalIdentity(), specialization());
557 else
558 return DeclarationId(IndexedDeclaration(const_cast<Declaration*>(this)), specialization());
559 }
560
inSymbolTable() const561 bool Declaration::inSymbolTable() const
562 {
563 DUCHAIN_D(Declaration);
564 return d->m_inSymbolTable;
565 }
566
kindForDeclaration(Declaration * decl)567 CodeModelItem::Kind kindForDeclaration(Declaration* decl)
568 {
569 CodeModelItem::Kind kind = CodeModelItem::Unknown;
570
571 if (decl->kind() == Declaration::Namespace)
572 return CodeModelItem::Namespace;
573
574 if (decl->isFunctionDeclaration()) {
575 kind = CodeModelItem::Function;
576 }
577
578 if (decl->kind() == Declaration::Type && (decl->type<StructureType>() || dynamic_cast<ClassDeclaration*>(decl)))
579 kind = CodeModelItem::Class;
580
581 if (kind == CodeModelItem::Unknown && decl->kind() == Declaration::Instance)
582 kind = CodeModelItem::Variable;
583
584 if (decl->isForwardDeclaration())
585 kind = ( CodeModelItem::Kind )(kind | CodeModelItem::ForwardDeclaration);
586
587 if (decl->context() && decl->context()->type() == DUContext::Class)
588 kind = ( CodeModelItem::Kind )(kind | CodeModelItem::ClassMember);
589
590 return kind;
591 }
592
updateCodeModel()593 void Declaration::updateCodeModel()
594 {
595 DUCHAIN_D(Declaration);
596 if (!d->m_identifier.isEmpty() && d->m_inSymbolTable) {
597 QualifiedIdentifier id(qualifiedIdentifier());
598 CodeModel::self().updateItem(url(), id, kindForDeclaration(this));
599 }
600 }
601
setInSymbolTable(bool inSymbolTable)602 void Declaration::setInSymbolTable(bool inSymbolTable)
603 {
604 DUCHAIN_D_DYNAMIC(Declaration);
605 if (!d->m_identifier.isEmpty()) {
606 if (!d->m_inSymbolTable && inSymbolTable) {
607 QualifiedIdentifier id(qualifiedIdentifier());
608 PersistentSymbolTable::self().addDeclaration(id, this);
609
610 CodeModel::self().addItem(url(), id, kindForDeclaration(this));
611 } else if (d->m_inSymbolTable && !inSymbolTable) {
612 QualifiedIdentifier id(qualifiedIdentifier());
613 PersistentSymbolTable::self().removeDeclaration(id, this);
614
615 CodeModel::self().removeItem(url(), id);
616 }
617 }
618 d->m_inSymbolTable = inSymbolTable;
619 }
620
topContext() const621 TopDUContext* Declaration::topContext() const
622 {
623 return m_topContext;
624 }
625
clonePrivate() const626 Declaration* Declaration::clonePrivate() const
627 {
628 return new Declaration(*this);
629 }
630
clone() const631 Declaration* Declaration::clone() const
632 {
633 Declaration* ret = clonePrivate();
634 ret->d_func_dynamic()->m_inSymbolTable = false;
635 return ret;
636 }
637
isForwardDeclaration() const638 bool Declaration::isForwardDeclaration() const
639 {
640 return false;
641 }
642
isFunctionDeclaration() const643 bool Declaration::isFunctionDeclaration() const
644 {
645 return false;
646 }
647
additionalIdentity() const648 uint Declaration::additionalIdentity() const
649 {
650 return 0;
651 }
652
equalQualifiedIdentifier(const Declaration * rhs) const653 bool Declaration::equalQualifiedIdentifier(const Declaration* rhs) const
654 {
655 ENSURE_CAN_READ
656 DUCHAIN_D(Declaration);
657 if (d->m_identifier != rhs->d_func()->m_identifier)
658 return false;
659
660 return m_context->equalScopeIdentifier(m_context);
661 }
662
uses() const663 QMap<IndexedString, QVector<RangeInRevision>> Declaration::uses() const
664 {
665 ENSURE_CAN_READ
666 QMap<IndexedString, QMap<RangeInRevision, bool>> tempUses;
667
668 //First, search for uses within the own context
669 {
670 QMap<RangeInRevision, bool>& ranges(tempUses[topContext()->url()]);
671 const auto useRanges = allUses(topContext(), const_cast<Declaration*>(this));
672 for (const RangeInRevision range : useRanges) {
673 ranges[range] = true;
674 }
675 }
676
677 DeclarationId _id = id();
678 KDevVarLengthArray<IndexedTopDUContext> useContexts = DUChain::uses()->uses(_id);
679 if (!_id.isDirect()) { // also check uses based on direct IDs
680 KDevVarLengthArray<IndexedTopDUContext> directUseContexts = DUChain::uses()->uses(id(true));
681 useContexts.append(directUseContexts.data(), directUseContexts.size());
682 }
683
684 for (const IndexedTopDUContext indexedContext : qAsConst(useContexts)) {
685 TopDUContext* context = indexedContext.data();
686 if (context) {
687 QMap<RangeInRevision, bool>& ranges(tempUses[context->url()]);
688 const auto useRanges = allUses(context, const_cast<Declaration*>(this));
689 for (const RangeInRevision range : useRanges) {
690 ranges[range] = true;
691 }
692 }
693 }
694
695 QMap<IndexedString, QVector<RangeInRevision>> ret;
696
697 for (QMap<IndexedString, QMap<RangeInRevision, bool>>::const_iterator it = tempUses.constBegin();
698 it != tempUses.constEnd(); ++it) {
699 if (!(*it).isEmpty()) {
700 auto& list = ret[it.key()];
701 list.reserve((*it).size());
702 for (QMap<RangeInRevision, bool>::const_iterator it2 = (*it).constBegin(); it2 != (*it).constEnd(); ++it2)
703 list << it2.key();
704 }
705 }
706
707 return ret;
708 }
709
hasDeclarationUse(DUContext * context,int declIdx)710 bool hasDeclarationUse(DUContext* context, int declIdx)
711 {
712 bool ret = false;
713 int usescount = context->usesCount();
714 const Use* uses = context->uses();
715
716 for (int i = 0; !ret && i < usescount; ++i) {
717 ret = uses[i].m_declarationIndex == declIdx;
718 }
719
720 const auto childContexts = context->childContexts();
721 for (DUContext* child : childContexts) {
722 ret = ret || hasDeclarationUse(child, declIdx);
723 if (ret)
724 break;
725 }
726
727 return ret;
728 }
729
hasUses() const730 bool Declaration::hasUses() const
731 {
732 ENSURE_CAN_READ
733 int idx = topContext()->indexForUsedDeclaration(const_cast<Declaration*>(this), false);
734 bool ret = idx != std::numeric_limits<int>::max() && (idx >= 0 || hasDeclarationUse(topContext(), idx)); //hasLocalUses
735 DeclarationId myId = id();
736
737 if (!ret && DUChain::uses()->hasUses(myId)) {
738 ret = true;
739 }
740
741 if (!ret && !myId.isDirect() && DUChain::uses()->hasUses(id(true))) {
742 ret = true;
743 }
744
745 return ret;
746 }
747
usesCurrentRevision() const748 QMap<IndexedString, QVector<KTextEditor::Range>> Declaration::usesCurrentRevision() const
749 {
750 ENSURE_CAN_READ
751 QMap<IndexedString, QMap<KTextEditor::Range, bool>> tempUses;
752
753 //First, search for uses within the own context
754 {
755 QMap<KTextEditor::Range, bool>& ranges(tempUses[topContext()->url()]);
756 const auto useRanges = allUses(topContext(), const_cast<Declaration*>(this));
757 for (const RangeInRevision range : useRanges) {
758 ranges[topContext()->transformFromLocalRevision(range)] = true;
759 }
760 }
761
762 DeclarationId _id = id();
763 KDevVarLengthArray<IndexedTopDUContext> useContexts = DUChain::uses()->uses(_id);
764 if (!_id.isDirect()) { // also check uses based on direct IDs
765 KDevVarLengthArray<IndexedTopDUContext> directUseContexts = DUChain::uses()->uses(id(true));
766 useContexts.append(directUseContexts.data(), directUseContexts.size());
767 }
768
769 for (const IndexedTopDUContext indexedContext : qAsConst(useContexts)) {
770 TopDUContext* context = indexedContext.data();
771 if (context) {
772 QMap<KTextEditor::Range, bool>& ranges(tempUses[context->url()]);
773 const auto useRanges = allUses(context, const_cast<Declaration*>(this));
774 for (const RangeInRevision range : useRanges) {
775 ranges[context->transformFromLocalRevision(range)] = true;
776 }
777 }
778 }
779
780 QMap<IndexedString, QVector<KTextEditor::Range>> ret;
781
782 for (QMap<IndexedString, QMap<KTextEditor::Range, bool>>::const_iterator it = tempUses.constBegin();
783 it != tempUses.constEnd(); ++it) {
784 if (!(*it).isEmpty()) {
785 auto& list = ret[it.key()];
786 list.reserve((*it).size());
787 for (QMap<KTextEditor::Range, bool>::const_iterator it2 = (*it).constBegin(); it2 != (*it).constEnd();
788 ++it2)
789 list << it2.key();
790 }
791 }
792
793 return ret;
794 }
795 }
796