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