• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdevelop API Reference
  • KDE Home
  • Contact Us
 

kdevplatform/language/duchain

  • sources
  • kfour-appscomplete
  • kdevelop
  • kdevplatform
  • language
  • duchain
ducontext.cpp
Go to the documentation of this file.
1 /* This is part of KDevelop
2  Copyright 2006 Hamish Rodda <[email protected]>
3  Copyright 2007-2009 David Nolden <[email protected]>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18  */
19 
20 #include "ducontext.h"
21 
22 #include <limits>
23 #include <algorithm>
24 
25 #include <QSet>
26 
27 #include "ducontextdata.h"
28 #include "declaration.h"
29 #include "duchain.h"
30 #include "duchainlock.h"
31 #include "use.h"
32 #include "identifier.h"
33 #include "topducontext.h"
34 #include "persistentsymboltable.h"
35 #include "aliasdeclaration.h"
36 #include "namespacealiasdeclaration.h"
37 #include "abstractfunctiondeclaration.h"
38 #include "duchainregister.h"
39 #include "topducontextdynamicdata.h"
40 #include "importers.h"
41 #include "uses.h"
42 #include "navigation/abstractdeclarationnavigationcontext.h"
43 #include "navigation/abstractnavigationwidget.h"
44 #include "ducontextdynamicdata.h"
45 #include <debug.h>
46 
47 // maximum depth for DUContext::findDeclarationsInternal searches
48 const uint maxParentDepth = 20;
49 
50 using namespace KTextEditor;
51 
52 #ifndef NDEBUG
53 #define ENSURE_CAN_WRITE_(x) {if (x->inDUChain()) { ENSURE_CHAIN_WRITE_LOCKED }}
54 #define ENSURE_CAN_READ_(x) {if (x->inDUChain()) { ENSURE_CHAIN_READ_LOCKED }}
55 #else
56 #define ENSURE_CAN_WRITE_(x)
57 #define ENSURE_CAN_READ_(x)
58 #endif
59 
60 QDebug operator<<(QDebug dbg, const KDevelop::DUContext::Import& import)
61 {
62  QDebugStateSaver saver(dbg);
63  dbg.nospace() << "Import(" << import.indexedContext().data() << ')';
64  return dbg;
65 }
66 
67 namespace KDevelop {
68 DEFINE_LIST_MEMBER_HASH(DUContextData, m_childContexts, LocalIndexedDUContext)
69 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importers, IndexedDUContext)
70 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importedContexts, DUContext::Import)
71 DEFINE_LIST_MEMBER_HASH(DUContextData, m_localDeclarations, LocalIndexedDeclaration)
72 DEFINE_LIST_MEMBER_HASH(DUContextData, m_uses, Use)
73 
74 REGISTER_DUCHAIN_ITEM(DUContext);
75 
76 DUChainVisitor::~DUChainVisitor()
77 {
78 }
79 
84 const Identifier& globalImportIdentifier()
85 {
86  static const Identifier globalImportIdentifierObject(QStringLiteral("{...import...}"));
87  return globalImportIdentifierObject;
88 }
89 
90 const Identifier& globalAliasIdentifier()
91 {
92  static const Identifier globalAliasIdentifierObject(QStringLiteral("{...alias...}"));
93  return globalAliasIdentifierObject;
94 }
95 
96 const IndexedIdentifier& globalIndexedImportIdentifier()
97 {
98  static const IndexedIdentifier id(globalImportIdentifier());
99  return id;
100 }
101 
102 const IndexedIdentifier& globalIndexedAliasIdentifier()
103 {
104  static const IndexedIdentifier id(globalAliasIdentifier());
105  return id;
106 }
107 
108 void DUContext::rebuildDynamicData(DUContext* parent, uint ownIndex)
109 {
110  Q_ASSERT(!parent || ownIndex);
111  m_dynamicData->m_topContext = parent ? parent->topContext() : static_cast<TopDUContext*>(this);
112  m_dynamicData->m_indexInTopContext = ownIndex;
113  m_dynamicData->m_parentContext = DUContextPointer(parent);
114  m_dynamicData->m_context = this;
115 
116  m_dynamicData->m_childContexts.clear();
117  m_dynamicData->m_childContexts.reserve(d_func()->m_childContextsSize());
118  FOREACH_FUNCTION(const LocalIndexedDUContext &ctx, d_func()->m_childContexts) {
119  m_dynamicData->m_childContexts << ctx.data(m_dynamicData->m_topContext);
120  }
121 
122  m_dynamicData->m_localDeclarations.clear();
123  m_dynamicData->m_localDeclarations.reserve(d_func()->m_localDeclarationsSize());
124  FOREACH_FUNCTION(const LocalIndexedDeclaration &idx, d_func()->m_localDeclarations) {
125  auto declaration = idx.data(m_dynamicData->m_topContext);
126  if (!declaration) {
127  qCWarning(LANGUAGE) << "child declaration number" << idx.localIndex() << "of" <<
128  d_func_dynamic()->m_localDeclarationsSize() << "is invalid";
129  continue;
130  }
131  m_dynamicData->m_localDeclarations << declaration;
132  }
133 
134  DUChainBase::rebuildDynamicData(parent, ownIndex);
135 }
136 
137 DUContextData::DUContextData()
138  : m_inSymbolTable(false)
139  , m_anonymousInParent(false)
140  , m_propagateDeclarations(false)
141 {
142  initializeAppendedLists();
143 }
144 
145 DUContextData::~DUContextData()
146 {
147  freeAppendedLists();
148 }
149 
150 DUContextData::DUContextData(const DUContextData& rhs)
151  : DUChainBaseData(rhs)
152  , m_inSymbolTable(rhs.m_inSymbolTable)
153  , m_anonymousInParent(rhs.m_anonymousInParent)
154  , m_propagateDeclarations(rhs.m_propagateDeclarations)
155 {
156  initializeAppendedLists();
157  copyListsFrom(rhs);
158  m_scopeIdentifier = rhs.m_scopeIdentifier;
159  m_contextType = rhs.m_contextType;
160  m_owner = rhs.m_owner;
161 }
162 
163 DUContextDynamicData::DUContextDynamicData(DUContext* d)
164  : m_topContext(nullptr)
165  , m_indexInTopContext(0)
166  , m_context(d)
167 {
168 }
169 
170 void DUContextDynamicData::scopeIdentifier(bool includeClasses, QualifiedIdentifier& target) const
171 {
172  if (m_parentContext)
173  m_parentContext->m_dynamicData->scopeIdentifier(includeClasses, target);
174 
175  if (includeClasses || d_func()->m_contextType != DUContext::Class)
176  target += d_func()->m_scopeIdentifier;
177 }
178 
179 bool DUContextDynamicData::imports(const DUContext* context, const TopDUContext* source,
180  QSet<const DUContextDynamicData*>* recursionGuard) const
181 {
182  if (this == context->m_dynamicData)
183  return true;
184 
185  if (recursionGuard->contains(this)) {
186  return false;
187  }
188  recursionGuard->insert(this);
189 
190  FOREACH_FUNCTION(const DUContext::Import& ctx, d_func()->m_importedContexts) {
191  DUContext* import = ctx.context(source);
192  if (import == context || (import && import->m_dynamicData->imports(context, source, recursionGuard)))
193  return true;
194  }
195 
196  return false;
197 }
198 
199 inline bool isContextTemporary(uint index)
200 {
201  return index > (0xffffffff / 2);
202 }
203 
204 void DUContextDynamicData::addDeclaration(Declaration* newDeclaration)
205 {
206  // The definition may not have its identifier set when it's assigned...
207  // allow dupes here, TODO catch the error elsewhere
208 
209  //If this context is temporary, added declarations should be as well, and viceversa
210  Q_ASSERT(isContextTemporary(m_indexInTopContext) == isContextTemporary(newDeclaration->ownIndex()));
211 
212  CursorInRevision start = newDeclaration->range().start;
213 
214  bool inserted = false;
216  for (int i = m_localDeclarations.size() - 1; i >= 0; --i) {
217  Declaration* child = m_localDeclarations[i];
218  Q_ASSERT(d_func()->m_localDeclarations()[i].data(m_topContext) == child);
219  if (child == newDeclaration)
220  return;
221  //TODO: All declarations in a macro will have the same empty range, and just get appended
222  //that may not be Good Enough in complex cases.
223  if (start >= child->range().start) {
224  m_localDeclarations.insert(i + 1, newDeclaration);
225  d_func_dynamic()->m_localDeclarationsList().insert(i + 1, newDeclaration);
226  Q_ASSERT(d_func()->m_localDeclarations()[i + 1].data(m_topContext) == newDeclaration);
227 
228  inserted = true;
229  break;
230  }
231  }
232 
233  if (!inserted) {
234  // We haven't found any child that is before this one, so prepend it
235  m_localDeclarations.insert(0, newDeclaration);
236  d_func_dynamic()->m_localDeclarationsList().insert(0, newDeclaration);
237  Q_ASSERT(d_func()->m_localDeclarations()[0].data(m_topContext) == newDeclaration);
238  }
239 }
240 
241 bool DUContextDynamicData::removeDeclaration(Declaration* declaration)
242 {
243  const int idx = m_localDeclarations.indexOf(declaration);
244  if (idx != -1) {
245  Q_ASSERT(d_func()->m_localDeclarations()[idx].data(m_topContext) == declaration);
246  m_localDeclarations.remove(idx);
247  d_func_dynamic()->m_localDeclarationsList().remove(idx);
248  return true;
249  } else {
250  Q_ASSERT(d_func_dynamic()->m_localDeclarationsList().indexOf(LocalIndexedDeclaration(declaration)) == -1);
251  return false;
252  }
253 }
254 
255 void DUContextDynamicData::addChildContext(DUContext* context)
256 {
257  // Internal, don't need to assert a lock
258  Q_ASSERT(!context->m_dynamicData->m_parentContext
259  || context->m_dynamicData->m_parentContext.data()->m_dynamicData == this);
260 
261  LocalIndexedDUContext indexed(context->m_dynamicData->m_indexInTopContext);
262 
263  //If this context is temporary, added declarations should be as well, and viceversa
264  Q_ASSERT(isContextTemporary(m_indexInTopContext) == isContextTemporary(indexed.localIndex()));
265 
266  bool inserted = false;
267 
268  int childCount = m_childContexts.size();
269 
270  for (int i = childCount - 1; i >= 0; --i) {
271  DUContext* child = m_childContexts[i];
272  Q_ASSERT(d_func_dynamic()->m_childContexts()[i] == LocalIndexedDUContext(child));
273  if (context == child)
274  return;
275  if (context->range().start >= child->range().start) {
276  m_childContexts.insert(i + 1, context);
277  d_func_dynamic()->m_childContextsList().insert(i + 1, indexed);
278  context->m_dynamicData->m_parentContext = m_context;
279  inserted = true;
280  break;
281  }
282  }
283 
284  if (!inserted) {
285  m_childContexts.insert(0, context);
286  d_func_dynamic()->m_childContextsList().insert(0, indexed);
287  context->m_dynamicData->m_parentContext = m_context;
288  }
289 }
290 
291 bool DUContextDynamicData::removeChildContext(DUContext* context)
292 {
293 // ENSURE_CAN_WRITE
294 
295  const int idx = m_childContexts.indexOf(context);
296  if (idx != -1) {
297  m_childContexts.remove(idx);
298  Q_ASSERT(d_func()->m_childContexts()[idx] == LocalIndexedDUContext(context));
299  d_func_dynamic()->m_childContextsList().remove(idx);
300  return true;
301  } else {
302  Q_ASSERT(d_func_dynamic()->m_childContextsList().indexOf(LocalIndexedDUContext(context)) == -1);
303  return false;
304  }
305 }
306 
307 void DUContextDynamicData::addImportedChildContext(DUContext* context)
308 {
309 // ENSURE_CAN_WRITE
310  DUContext::Import import(m_context, context);
311 
312  if (import.isDirect()) {
313  //Direct importers are registered directly within the data
314  if (d_func_dynamic()->m_importersList().contains(IndexedDUContext(context))) {
315  qCDebug(LANGUAGE) << m_context->scopeIdentifier(true).toString() << "importer added multiple times:" <<
316  context->scopeIdentifier(true).toString();
317  return;
318  }
319 
320  d_func_dynamic()->m_importersList().append(context);
321  } else {
322  //Indirect importers are registered separately
323  Importers::self().addImporter(import.indirectDeclarationId(), IndexedDUContext(context));
324  }
325 }
326 
327 //Can also be called with a context that is not in the list
328 void DUContextDynamicData::removeImportedChildContext(DUContext* context)
329 {
330 // ENSURE_CAN_WRITE
331  DUContext::Import import(m_context, context);
332 
333  if (import.isDirect()) {
334  d_func_dynamic()->m_importersList().removeOne(IndexedDUContext(context));
335  } else {
336  //Indirect importers are registered separately
337  Importers::self().removeImporter(import.indirectDeclarationId(), IndexedDUContext(context));
338  }
339 }
340 
341 int DUContext::depth() const
342 {
343  if (!parentContext()) {
344  return 0;
345  }
346 
347  return parentContext()->depth() + 1;
348 }
349 
350 DUContext::DUContext(DUContextData& data)
351  : DUChainBase(data)
352  , m_dynamicData(new DUContextDynamicData(this))
353 {
354 }
355 
356 DUContext::DUContext(const RangeInRevision& range, DUContext* parent, bool anonymous)
357  : DUChainBase(*new DUContextData(), range)
358  , m_dynamicData(new DUContextDynamicData(this))
359 {
360  d_func_dynamic()->setClassId(this);
361  if (parent)
362  m_dynamicData->m_topContext = parent->topContext();
363 
364  d_func_dynamic()->setClassId(this);
365  DUCHAIN_D_DYNAMIC(DUContext);
366  d->m_contextType = Other;
367  m_dynamicData->m_parentContext = nullptr;
368 
369  d->m_anonymousInParent = anonymous;
370  d->m_inSymbolTable = false;
371 
372  if (parent) {
373  m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this,
374  parent->isAnonymous() ||
375  anonymous);
376  Q_ASSERT(m_dynamicData->m_indexInTopContext);
377 
378  if (!anonymous)
379  parent->m_dynamicData->addChildContext(this);
380  else
381  m_dynamicData->m_parentContext = parent;
382  }
383 
384  if (parent && !anonymous && parent->inSymbolTable())
385  setInSymbolTable(true);
386 }
387 
388 bool DUContext::isAnonymous() const
389 {
390  return d_func()->m_anonymousInParent ||
391  (m_dynamicData->m_parentContext && m_dynamicData->m_parentContext->isAnonymous());
392 }
393 
394 void DUContext::initFromTopContext()
395 {
396  Q_ASSERT(dynamic_cast<TopDUContext*>(this));
397  m_dynamicData->m_topContext = static_cast<TopDUContext*>(this);
398 }
399 
400 DUContext::DUContext(DUContextData& dd, const RangeInRevision& range, DUContext* parent, bool anonymous)
401  : DUChainBase(dd, range)
402  , m_dynamicData(new DUContextDynamicData(this))
403 {
404  if (parent)
405  m_dynamicData->m_topContext = parent->topContext();
406  // else initTopContext must be called, doing a static_cast here is UB
407 
408  DUCHAIN_D_DYNAMIC(DUContext);
409  d->m_contextType = Other;
410  m_dynamicData->m_parentContext = nullptr;
411  d->m_inSymbolTable = false;
412  d->m_anonymousInParent = anonymous;
413  if (parent) {
414  m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this,
415  parent->isAnonymous() ||
416  anonymous);
417 
418  if (!anonymous)
419  parent->m_dynamicData->addChildContext(this);
420  else
421  m_dynamicData->m_parentContext = parent;
422  }
423 }
424 
425 DUContext::DUContext(DUContext& useDataFrom)
426  : DUChainBase(useDataFrom)
427  , m_dynamicData(useDataFrom.m_dynamicData)
428 {
429 }
430 
431 DUContext::~DUContext()
432 {
433  TopDUContext* top = topContext();
434 
435  if (top != this) {
436  const auto doCleanup = !top->deleting() || !top->isOnDisk();
437 
438  if (doCleanup) {
439  DUCHAIN_D_DYNAMIC(DUContext);
440 
441  if (d->m_owner.declaration())
442  d->m_owner.declaration()->setInternalContext(nullptr);
443 
444  while (d->m_importersSize() != 0) {
445  if (d->m_importers()[0].data())
446  d->m_importers()[0].data()->removeImportedParentContext(this);
447  else {
448  qCDebug(LANGUAGE) << "importer disappeared";
449  d->m_importersList().removeOne(d->m_importers()[0]);
450  }
451  }
452 
453  clearImportedParentContexts();
454  }
455 
456  deleteChildContextsRecursively();
457 
458  if (doCleanup)
459  deleteUses();
460 
461  deleteLocalDeclarations();
462 
463  //If the top-context is being delete, we don't need to spend time rebuilding the inner structure.
464  //That's expensive, especially when the data is not dynamic.
465  if (doCleanup && m_dynamicData->m_parentContext) {
466  m_dynamicData->m_parentContext->m_dynamicData->removeChildContext(this);
467  }
468 
469  top->m_dynamicData->clearContextIndex(this);
470 
471  Q_ASSERT(d_func()->isDynamic() ==
472  (doCleanup ||
473  top->m_dynamicData->isTemporaryContextIndex(m_dynamicData->m_indexInTopContext)));
474  }
475 
476  delete m_dynamicData;
477 }
478 
479 QVector<DUContext*> DUContext::childContexts() const
480 {
481  ENSURE_CAN_READ
482 
483  return m_dynamicData->m_childContexts;
484 }
485 
486 Declaration* DUContext::owner() const
487 {
488  ENSURE_CAN_READ
489  return d_func()->m_owner.declaration();
490 }
491 
492 void DUContext::setOwner(Declaration* owner)
493 {
494  ENSURE_CAN_WRITE
495  DUCHAIN_D_DYNAMIC(DUContext);
496  if (owner == d->m_owner.declaration())
497  return;
498 
499  Declaration* oldOwner = d->m_owner.declaration();
500 
501  d->m_owner = owner;
502 
503  //Q_ASSERT(!oldOwner || oldOwner->internalContext() == this);
504  if (oldOwner && oldOwner->internalContext() == this)
505  oldOwner->setInternalContext(nullptr);
506 
507  //The context set as internal context should always be the last opened context
508  if (owner)
509  owner->setInternalContext(this);
510 }
511 
512 DUContext* DUContext::parentContext() const
513 {
514  //ENSURE_CAN_READ Commented out for performance reasons
515 
516  return m_dynamicData->m_parentContext.data();
517 }
518 
519 void DUContext::setPropagateDeclarations(bool propagate)
520 {
521  ENSURE_CAN_WRITE
522  DUCHAIN_D_DYNAMIC(DUContext);
523 
524  if (propagate == d->m_propagateDeclarations)
525  return;
526 
527  d->m_propagateDeclarations = propagate;
528 }
529 
530 bool DUContext::isPropagateDeclarations() const
531 {
532  return d_func()->m_propagateDeclarations;
533 }
534 
535 QList<Declaration*> DUContext::findLocalDeclarations(const IndexedIdentifier& identifier,
536  const CursorInRevision& position,
537  const TopDUContext* topContext,
538  const AbstractType::Ptr& dataType,
539  SearchFlags flags) const
540 {
541  ENSURE_CAN_READ
542 
543  DeclarationList ret;
544  findLocalDeclarationsInternal(identifier,
545  position.isValid() ? position : range().end, dataType, ret,
546  topContext ? topContext : this->topContext(), flags);
547  return ret;
548 }
549 
550 QList<Declaration*> DUContext::findLocalDeclarations(const Identifier& identifier,
551  const CursorInRevision& position,
552  const TopDUContext* topContext,
553  const AbstractType::Ptr& dataType,
554  SearchFlags flags) const
555 {
556  return findLocalDeclarations(IndexedIdentifier(identifier), position, topContext, dataType, flags);
557 }
558 
559 namespace {
560 bool contextIsChildOrEqual(const DUContext* childContext, const DUContext* context)
561 {
562  if (childContext == context)
563  return true;
564 
565  if (childContext->parentContext())
566  return contextIsChildOrEqual(childContext->parentContext(), context);
567  else
568  return false;
569 }
570 
571 struct Checker
572 {
573  Checker(DUContext::SearchFlags flags, const AbstractType::Ptr& dataType,
574  const CursorInRevision& position, DUContext::ContextType ownType)
575  : m_flags(flags)
576  , m_dataType(dataType)
577  , m_position(position)
578  , m_ownType(ownType)
579  {
580  }
581 
582  Declaration* check(Declaration* declaration) const
583  {
585  if (m_ownType != DUContext::Class && m_ownType != DUContext::Template
586  && m_position.isValid() && m_position <= declaration->range().start) {
587  return nullptr;
588  }
589 
590  if (declaration->kind() == Declaration::Alias && !(m_flags & DUContext::DontResolveAliases)) {
591  //Apply alias declarations
592  auto* alias = static_cast<AliasDeclaration*>(declaration);
593  if (alias->aliasedDeclaration().isValid()) {
594  declaration = alias->aliasedDeclaration().declaration();
595  } else {
596  qCDebug(LANGUAGE) << "lost aliased declaration";
597  }
598  }
599 
600  if (declaration->kind() == Declaration::NamespaceAlias && !(m_flags & DUContext::NoFiltering)) {
601  return nullptr;
602  }
603 
604  if (( m_flags& DUContext::OnlyFunctions ) && !declaration->isFunctionDeclaration()) {
605  return nullptr;
606  }
607 
608  if (m_dataType && m_dataType->indexed() != declaration->indexedType()) {
609  return nullptr;
610  }
611 
612  return declaration;
613  }
614 
615  DUContext::SearchFlags m_flags;
616  const AbstractType::Ptr m_dataType;
617  const CursorInRevision m_position;
618  DUContext::ContextType m_ownType;
619 };
620 }
621 
622 void DUContext::findLocalDeclarationsInternal(const Identifier& identifier, const CursorInRevision& position,
623  const AbstractType::Ptr& dataType, DeclarationList& ret,
624  const TopDUContext* source, SearchFlags flags) const
625 {
626  findLocalDeclarationsInternal(IndexedIdentifier(identifier), position, dataType, ret, source, flags);
627 }
628 
629 void DUContext::findLocalDeclarationsInternal(const IndexedIdentifier& identifier,
630  const CursorInRevision& position,
631  const AbstractType::Ptr& dataType,
632  DeclarationList& ret, const TopDUContext* /*source*/,
633  SearchFlags flags) const
634 {
635  Checker checker(flags, dataType, position, type());
636 
637  DUCHAIN_D(DUContext);
638  if (d->m_inSymbolTable && !d->m_scopeIdentifier.isEmpty() && !identifier.isEmpty()) {
639  //This context is in the symbol table, use the symbol-table to speed up the search
640  QualifiedIdentifier id(scopeIdentifier(true) + identifier);
641 
642  TopDUContext* top = topContext();
643 
644  uint count;
645  const IndexedDeclaration* declarations;
646  PersistentSymbolTable::self().declarations(id, count, declarations);
647  for (uint a = 0; a < count; ++a) {
649  if (declarations[a].topContextIndex() == top->ownIndex()) {
650  Declaration* decl = declarations[a].declaration();
651  if (decl && contextIsChildOrEqual(decl->context(), this)) {
652  Declaration* checked = checker.check(decl);
653  if (checked) {
654  ret.append(checked);
655  }
656  }
657  }
658  }
659  } else {
660  //Iterate through all declarations
661  DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
662  while (it) {
663  Declaration* declaration = *it;
664  if (declaration && declaration->indexedIdentifier() == identifier) {
665  Declaration* checked = checker.check(declaration);
666  if (checked)
667  ret.append(checked);
668  }
669  ++it;
670  }
671  }
672 }
673 
674 bool DUContext::foundEnough(const DeclarationList& ret, SearchFlags flags) const
675 {
676  if (!ret.isEmpty() && !(flags & DUContext::NoFiltering))
677  return true;
678  else
679  return false;
680 }
681 
682 bool DUContext::findDeclarationsInternal(const SearchItem::PtrList& baseIdentifiers,
683  const CursorInRevision& position,
684  const AbstractType::Ptr& dataType,
685  DeclarationList& ret, const TopDUContext* source,
686  SearchFlags flags, uint depth) const
687 {
688  if (depth > maxParentDepth) {
689  qCDebug(LANGUAGE) << "maximum depth reached in" << scopeIdentifier(true);
690  return false;
691  }
692 
693  DUCHAIN_D(DUContext);
694  if (d->m_contextType != Namespace) {
695  // If we're in a namespace, delay all the searching into the top-context, because only that has the overview to pick the correct declarations.
696  for (auto& baseIdentifier : baseIdentifiers) {
697  if (!baseIdentifier->isExplicitlyGlobal && baseIdentifier->next.isEmpty()) {
698  // It makes no sense searching locally for qualified identifiers
699  findLocalDeclarationsInternal(baseIdentifier->identifier, position, dataType, ret, source, flags);
700  }
701  }
702 
703  if (foundEnough(ret, flags)) {
704  return true;
705  }
706  }
707 
709  SearchItem::PtrList aliasedIdentifiers;
710  //Because of namespace-imports and aliases, this identifier may need to be searched under multiple names
711  applyAliases(baseIdentifiers, aliasedIdentifiers, position, false,
712  type() != DUContext::Namespace && type() != DUContext::Global);
713 
714  if (d->m_importedContextsSize() != 0) {
716  SearchItem::PtrList nonGlobalIdentifiers;
717  for (const SearchItem::Ptr& identifier : qAsConst(aliasedIdentifiers)) {
718  if (!identifier->isExplicitlyGlobal) {
719  nonGlobalIdentifiers << identifier;
720  }
721  }
722 
723  if (!nonGlobalIdentifiers.isEmpty()) {
724  const auto& url = this->url();
725  for (int import = d->m_importedContextsSize() - 1; import >= 0; --import) {
726  if (position.isValid() && d->m_importedContexts()[import].position.isValid() &&
727  position < d->m_importedContexts()[import].position) {
728  continue;
729  }
730 
731  DUContext* context = d->m_importedContexts()[import].context(source);
732 
733  if (!context) {
734  continue;
735  } else if (context == this) {
736  qCDebug(LANGUAGE) << "resolved self as import:" << scopeIdentifier(true);
737  continue;
738  }
739 
740  if (!context->findDeclarationsInternal(nonGlobalIdentifiers,
741  url == context->url() ? position : context->range().end,
742  dataType, ret, source, flags | InImportedParentContext,
743  depth + 1)) {
744  return false;
745  }
746  }
747  }
748  }
749 
750  if (foundEnough(ret, flags)) {
751  return true;
752  }
753 
755  if (!(flags & DontSearchInParent) && shouldSearchInParent(flags) && m_dynamicData->m_parentContext) {
756  applyUpwardsAliases(aliasedIdentifiers, source);
757  return m_dynamicData->m_parentContext->findDeclarationsInternal(aliasedIdentifiers,
758  url() == m_dynamicData->m_parentContext->url() ? position : m_dynamicData->m_parentContext->range().end,
759  dataType, ret, source, flags, depth);
760  }
761  return true;
762 }
763 
764 QVector<QualifiedIdentifier> DUContext::fullyApplyAliases(const QualifiedIdentifier& id,
765  const TopDUContext* source) const
766 {
767  ENSURE_CAN_READ
768 
769  if (!source)
770  source = topContext();
771 
772  SearchItem::PtrList identifiers;
773  identifiers << SearchItem::Ptr(new SearchItem(id));
774 
775  const DUContext* current = this;
776  while (current) {
777  SearchItem::PtrList aliasedIdentifiers;
778  current->applyAliases(identifiers, aliasedIdentifiers, CursorInRevision::invalid(), true, false);
779  current->applyUpwardsAliases(identifiers, source);
780 
781  current = current->parentContext();
782  }
783 
784  QVector<QualifiedIdentifier> ret;
785  for (const SearchItem::Ptr& item : qAsConst(identifiers)) {
786  ret += item->toList();
787  }
788 
789  return ret;
790 }
791 
792 QList<Declaration*> DUContext::findDeclarations(const QualifiedIdentifier& identifier,
793  const CursorInRevision& position,
794  const AbstractType::Ptr& dataType,
795  const TopDUContext* topContext, SearchFlags flags) const
796 {
797  ENSURE_CAN_READ
798 
799  DeclarationList ret;
800  // optimize: we don't want to allocate the top node always
801  // so create it on stack but ref it so its not deleted by the smart pointer
802  SearchItem item(identifier);
803  item.ref.ref();
804 
805  SearchItem::PtrList identifiers{SearchItem::Ptr(&item)};
806 
807  findDeclarationsInternal(identifiers,
808  position.isValid() ? position : range().end, dataType, ret,
809  topContext ? topContext : this->topContext(), flags, 0);
810 
811  return ret;
812 }
813 
814 bool DUContext::imports(const DUContext* origin, const CursorInRevision& /*position*/) const
815 {
816  ENSURE_CAN_READ
817 
818  QSet<const DUContextDynamicData*> recursionGuard;
819  recursionGuard.reserve(8);
820  return m_dynamicData->imports(origin, topContext(), &recursionGuard);
821 }
822 
823 bool DUContext::addIndirectImport(const DUContext::Import& import)
824 {
825  ENSURE_CAN_WRITE
826  DUCHAIN_D_DYNAMIC(DUContext);
827 
828  for (unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
829  if (d->m_importedContexts()[a] == import) {
830  d->m_importedContextsList()[a].position = import.position;
831  return true;
832  }
833  }
834 
837 
838  d->m_importedContextsList().append(import);
839  return false;
840 }
841 
842 void DUContext::addImportedParentContext(DUContext* context, const CursorInRevision& position, bool anonymous,
843  bool /*temporary*/)
844 {
845  ENSURE_CAN_WRITE
846 
847  if (context == this) {
848  qCDebug(LANGUAGE) << "Tried to import self";
849  return;
850  }
851  if (!context) {
852  qCDebug(LANGUAGE) << "Tried to import invalid context";
853  return;
854  }
855 
856  Import import(context, this, position);
857  if (addIndirectImport(import))
858  return;
859 
860  if (!anonymous) {
861  ENSURE_CAN_WRITE_(context)
862  context->m_dynamicData->addImportedChildContext(this);
863  }
864 }
865 
866 void DUContext::removeImportedParentContext(DUContext* context)
867 {
868  ENSURE_CAN_WRITE
869  DUCHAIN_D_DYNAMIC(DUContext);
870 
871  Import import(context, this, CursorInRevision::invalid());
872 
873  for (unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
874  if (d->m_importedContexts()[a] == import) {
875  d->m_importedContextsList().remove(a);
876  break;
877  }
878  }
879 
880  if (!context)
881  return;
882 
883  context->m_dynamicData->removeImportedChildContext(this);
884 }
885 
886 KDevVarLengthArray<IndexedDUContext> DUContext::indexedImporters() const
887 {
888  KDevVarLengthArray<IndexedDUContext> ret;
889  if (owner())
890  ret = Importers::self().importers(owner()->id()); //Add indirect importers to the list
891 
892  FOREACH_FUNCTION(const IndexedDUContext &ctx, d_func()->m_importers)
893  ret.append(ctx);
894 
895  return ret;
896 }
897 
898 QVector<DUContext*> DUContext::importers() const
899 {
900  ENSURE_CAN_READ
901 
902  QVector<DUContext*> ret;
903  ret.reserve(d_func()->m_importersSize());
904  FOREACH_FUNCTION(const IndexedDUContext &ctx, d_func()->m_importers)
905  ret << ctx.context();
906 
907  if (owner()) {
908  //Add indirect importers to the list
909  const KDevVarLengthArray<IndexedDUContext> indirect = Importers::self().importers(owner()->id());
910  ret.reserve(ret.size() + indirect.size());
911  for (const IndexedDUContext ctx : indirect) {
912  ret << ctx.context();
913  }
914  }
915 
916  return ret;
917 }
918 
919 DUContext* DUContext::findContext(const CursorInRevision& position, DUContext* parent) const
920 {
921  ENSURE_CAN_READ
922 
923  if (!parent)
924  parent = const_cast<DUContext*>(this);
925 
926  for (DUContext* context : qAsConst(parent->m_dynamicData->m_childContexts)) {
927  if (context->range().contains(position)) {
928  DUContext* ret = findContext(position, context);
929  if (!ret) {
930  ret = context;
931  }
932 
933  return ret;
934  }
935  }
936 
937  return nullptr;
938 }
939 
940 bool DUContext::parentContextOf(DUContext* context) const
941 {
942  if (this == context)
943  return true;
944 
945  const auto& childContexts = m_dynamicData->m_childContexts;
946  return std::any_of(childContexts.begin(), childContexts.end(), [&](DUContext* child) {
947  return child->parentContextOf(context);
948  });
949 }
950 
951 QVector<QPair<Declaration*, int>> DUContext::allDeclarations(const CursorInRevision& position,
952  const TopDUContext* topContext,
953  bool searchInParents) const
954 {
955  ENSURE_CAN_READ
956 
957  QVector<QPair<Declaration*, int>> ret;
958 
959  QHash<const DUContext*, bool> hadContexts;
960  // Iterate back up the chain
961  mergeDeclarationsInternal(ret, position, hadContexts, topContext ? topContext : this->topContext(),
962  searchInParents);
963 
964  return ret;
965 }
966 
967 QVector<Declaration*> DUContext::localDeclarations(const TopDUContext* source) const
968 {
969  ENSURE_CAN_READ
970  // TODO: remove this parameter once we kill old-cpp
971  Q_UNUSED(source);
972  return m_dynamicData->m_localDeclarations;
973 }
974 
975 void DUContext::mergeDeclarationsInternal(QVector<QPair<Declaration*, int>>& definitions,
976  const CursorInRevision& position,
977  QHash<const DUContext*, bool>& hadContexts,
978  const TopDUContext* source,
979  bool searchInParents, int currentDepth) const
980 {
981  ENSURE_CAN_READ
982 
983  if ((currentDepth > 300 && currentDepth < 1000) || currentDepth > 1300) {
984  qCDebug(LANGUAGE) << "too much depth";
985  return;
986  }
987  DUCHAIN_D(DUContext);
988 
989  if (hadContexts.contains(this) && !searchInParents)
990  return;
991 
992  if (!hadContexts.contains(this)) {
993  hadContexts[this] = true;
994 
995  if ((type() == DUContext::Namespace || type() == DUContext::Global) && currentDepth < 1000)
996  currentDepth += 1000;
997 
998  {
999  DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
1000  while (it) {
1001  Declaration* decl = *it;
1002 
1003  if (decl && (!position.isValid() || decl->range().start <= position))
1004  definitions << qMakePair(decl, currentDepth);
1005  ++it;
1006  }
1007  }
1008 
1009  for (int a = d->m_importedContextsSize() - 1; a >= 0; --a) {
1010  const Import* import(&d->m_importedContexts()[a]);
1011  DUContext* context = import->context(source);
1012  while (!context && a > 0) {
1013  --a;
1014  import = &d->m_importedContexts()[a];
1015  context = import->context(source);
1016  }
1017  if (!context)
1018  break;
1019 
1020  if (context == this) {
1021  qCDebug(LANGUAGE) << "resolved self as import:" << scopeIdentifier(true);
1022  continue;
1023  }
1024 
1025  if (position.isValid() && import->position.isValid() && position < import->position)
1026  continue;
1027 
1028  context->mergeDeclarationsInternal(definitions,
1029  CursorInRevision::invalid(), hadContexts, source,
1030  searchInParents && context->shouldSearchInParent(
1031  InImportedParentContext) && context->parentContext()->type() == DUContext::Helper,
1032  currentDepth + 1);
1033  }
1034  }
1035 
1037  if (parentContext() && searchInParents)
1038  parentContext()->mergeDeclarationsInternal(definitions,
1039  parentContext()->type() == DUContext::Class ? parentContext()->range().end : position, hadContexts, source, searchInParents,
1040  currentDepth + 1);
1041 }
1042 
1043 void DUContext::deleteLocalDeclarations()
1044 {
1045  ENSURE_CAN_WRITE
1046  // It may happen that the deletion of one declaration triggers the deletion of another one
1047  // Therefore we copy the list of indexed declarations and work on those. Indexed declarations
1048  // will return zero for already deleted declarations.
1049  KDevVarLengthArray<LocalIndexedDeclaration> indexedLocal;
1050  if (d_func()->m_localDeclarations()) {
1051  indexedLocal.append(d_func()->m_localDeclarations(), d_func()->m_localDeclarationsSize());
1052  }
1053  const auto currentLocalDeclarations = m_dynamicData->m_localDeclarations;
1054  for (const LocalIndexedDeclaration& indexed : currentLocalDeclarations) {
1055  delete indexed.data(topContext());
1056  }
1057 
1058  m_dynamicData->m_localDeclarations.clear();
1059 }
1060 
1061 void DUContext::deleteChildContextsRecursively()
1062 {
1063  ENSURE_CAN_WRITE
1064 
1065  // note: operate on copy here because child ctx deletion changes m_dynamicData->m_childContexts
1066  const auto currentChildContexts = m_dynamicData->m_childContexts;
1067  qDeleteAll(currentChildContexts);
1068 
1069  m_dynamicData->m_childContexts.clear();
1070 }
1071 
1072 QVector<Declaration*> DUContext::clearLocalDeclarations()
1073 {
1074  auto copy = m_dynamicData->m_localDeclarations;
1075  for (Declaration* dec : qAsConst(copy)) {
1076  dec->setContext(nullptr);
1077  }
1078 
1079  return copy;
1080 }
1081 
1082 QualifiedIdentifier DUContext::scopeIdentifier(bool includeClasses) const
1083 {
1084  ENSURE_CAN_READ
1085 
1086  QualifiedIdentifier ret;
1087  m_dynamicData->scopeIdentifier(includeClasses, ret);
1088 
1089  return ret;
1090 }
1091 
1092 bool DUContext::equalScopeIdentifier(const DUContext* rhs) const
1093 {
1094  ENSURE_CAN_READ
1095 
1096  const DUContext* left = this;
1097  const DUContext* right = rhs;
1098 
1099  while (left || right) {
1100  if (!left || !right)
1101  return false;
1102 
1103  if (!(left->d_func()->m_scopeIdentifier == right->d_func()->m_scopeIdentifier))
1104  return false;
1105 
1106  left = left->parentContext();
1107  right = right->parentContext();
1108  }
1109 
1110  return true;
1111 }
1112 
1113 void DUContext::setLocalScopeIdentifier(const QualifiedIdentifier& identifier)
1114 {
1115  ENSURE_CAN_WRITE
1116  bool wasInSymbolTable = inSymbolTable();
1117  setInSymbolTable(false);
1118  d_func_dynamic()->m_scopeIdentifier = identifier;
1119  setInSymbolTable(wasInSymbolTable);
1120 }
1121 
1122 QualifiedIdentifier DUContext::localScopeIdentifier() const
1123 {
1124  //ENSURE_CAN_READ Commented out for performance reasons
1125 
1126  return d_func()->m_scopeIdentifier;
1127 }
1128 
1129 IndexedQualifiedIdentifier DUContext::indexedLocalScopeIdentifier() const
1130 {
1131  return d_func()->m_scopeIdentifier;
1132 }
1133 
1134 DUContext::ContextType DUContext::type() const
1135 {
1136  //ENSURE_CAN_READ This is disabled, because type() is called very often while searching, and it costs us performance
1137 
1138  return d_func()->m_contextType;
1139 }
1140 
1141 void DUContext::setType(ContextType type)
1142 {
1143  ENSURE_CAN_WRITE
1144 
1145  d_func_dynamic()->m_contextType = type;
1146 }
1147 
1148 QList<Declaration*> DUContext::findDeclarations(const Identifier& identifier, const CursorInRevision& position,
1149  const TopDUContext* topContext, SearchFlags flags) const
1150 {
1151  return findDeclarations(IndexedIdentifier(identifier), position, topContext, flags);
1152 }
1153 
1154 QList<Declaration*> DUContext::findDeclarations(const IndexedIdentifier& identifier, const CursorInRevision& position,
1155  const TopDUContext* topContext, SearchFlags flags) const
1156 {
1157  ENSURE_CAN_READ
1158 
1159  DeclarationList ret;
1160  SearchItem::PtrList identifiers;
1161  identifiers << SearchItem::Ptr(new SearchItem(false, identifier, SearchItem::PtrList()));
1162  findDeclarationsInternal(identifiers, position.isValid() ? position : range().end,
1163  AbstractType::Ptr(), ret, topContext ? topContext : this->topContext(), flags, 0);
1164  return ret;
1165 }
1166 
1167 void DUContext::deleteUse(int index)
1168 {
1169  ENSURE_CAN_WRITE
1170  DUCHAIN_D_DYNAMIC(DUContext);
1171  d->m_usesList().remove(index);
1172 }
1173 
1174 void DUContext::deleteUses()
1175 {
1176  ENSURE_CAN_WRITE
1177 
1178  DUCHAIN_D_DYNAMIC(DUContext);
1179  d->m_usesList().clear();
1180 }
1181 
1182 void DUContext::deleteUsesRecursively()
1183 {
1184  deleteUses();
1185 
1186  for (DUContext* childContext : qAsConst(m_dynamicData->m_childContexts)) {
1187  childContext->deleteUsesRecursively();
1188  }
1189 }
1190 
1191 bool DUContext::inDUChain() const
1192 {
1193  if (d_func()->m_anonymousInParent || !m_dynamicData->m_parentContext)
1194  return false;
1195 
1196  TopDUContext* top = topContext();
1197  return top && top->inDUChain();
1198 }
1199 
1200 DUContext* DUContext::specialize(const IndexedInstantiationInformation& /*specialization*/,
1201  const TopDUContext* topContext, int /*upDistance*/)
1202 {
1203  if (!topContext)
1204  return nullptr;
1205  return this;
1206 }
1207 
1208 CursorInRevision DUContext::importPosition(const DUContext* target) const
1209 {
1210  ENSURE_CAN_READ
1211  DUCHAIN_D(DUContext);
1212  Import import(const_cast<DUContext*>(target), this, CursorInRevision::invalid());
1213  for (unsigned int a = 0; a < d->m_importedContextsSize(); ++a)
1214  if (d->m_importedContexts()[a] == import)
1215  return d->m_importedContexts()[a].position;
1216 
1217  return CursorInRevision::invalid();
1218 }
1219 
1220 QVector<DUContext::Import> DUContext::importedParentContexts() const
1221 {
1222  ENSURE_CAN_READ
1223  QVector<DUContext::Import> ret;
1224  ret.reserve(d_func()->m_importedContextsSize());
1225  FOREACH_FUNCTION(const DUContext::Import& import, d_func()->m_importedContexts)
1226  ret << import;
1227  return ret;
1228 }
1229 
1230 void DUContext::applyAliases(const SearchItem::PtrList& baseIdentifiers, SearchItem::PtrList& identifiers,
1231  const CursorInRevision& position, bool canBeNamespace, bool onlyImports) const
1232 {
1233  DeclarationList imports;
1234  findLocalDeclarationsInternal(globalIndexedImportIdentifier(), position, AbstractType::Ptr(), imports,
1235  topContext(), DUContext::NoFiltering);
1236 
1237  if (imports.isEmpty() && onlyImports) {
1238  identifiers = baseIdentifiers;
1239  return;
1240  }
1241 
1242  for (const SearchItem::Ptr& identifier : baseIdentifiers) {
1243  bool addUnmodified = true;
1244 
1245  if (!identifier->isExplicitlyGlobal) {
1246  if (!imports.isEmpty()) {
1247  //We have namespace-imports.
1248  for (Declaration* importDecl : qAsConst(imports)) {
1249  //Search for the identifier with the import-identifier prepended
1250  if (dynamic_cast<NamespaceAliasDeclaration*>(importDecl)) {
1251  auto* alias = static_cast<NamespaceAliasDeclaration*>(importDecl);
1252  identifiers.append(SearchItem::Ptr(new SearchItem(alias->importIdentifier(), identifier)));
1253  } else {
1254  qCDebug(LANGUAGE) << "Declaration with namespace alias identifier has the wrong type" <<
1255  importDecl->url().str() << importDecl->range().castToSimpleRange();
1256  }
1257  }
1258  }
1259 
1260  if (!identifier->isEmpty() && (identifier->hasNext() || canBeNamespace)) {
1261  DeclarationList aliases;
1262  findLocalDeclarationsInternal(identifier->identifier, position,
1263  AbstractType::Ptr(), imports, nullptr, DUContext::NoFiltering);
1264 
1265  if (!aliases.isEmpty()) {
1266  //The first part of the identifier has been found as a namespace-alias.
1267  //In c++, we only need the first alias. However, just to be correct, follow them all for now.
1268  for (Declaration* aliasDecl : qAsConst(aliases)) {
1269  if (!dynamic_cast<NamespaceAliasDeclaration*>(aliasDecl))
1270  continue;
1271 
1272  addUnmodified = false; //The un-modified identifier can be ignored, because it will be replaced with the resolved alias
1273  auto* alias = static_cast<NamespaceAliasDeclaration*>(aliasDecl);
1274 
1275  //Create an identifier where namespace-alias part is replaced with the alias target
1276  identifiers.append(SearchItem::Ptr(new SearchItem(alias->importIdentifier(),
1277  identifier->next)));
1278  }
1279  }
1280  }
1281  }
1282 
1283  if (addUnmodified)
1284  identifiers.append(identifier);
1285  }
1286 }
1287 
1288 void DUContext::applyUpwardsAliases(SearchItem::PtrList& identifiers, const TopDUContext* /*source*/) const
1289 {
1290  if (type() == Namespace) {
1291  if (d_func()->m_scopeIdentifier.isEmpty())
1292  return;
1293 
1294  //Make sure we search for the items in all namespaces of the same name, by duplicating each one with the namespace-identifier prepended.
1295  //We do this by prepending items to the current identifiers that equal the local scope identifier.
1296  SearchItem::Ptr newItem(new SearchItem(d_func()->m_scopeIdentifier.identifier()));
1297 
1298  //This will exclude explicitly global identifiers
1299  newItem->addToEachNode(identifiers);
1300 
1301  if (!newItem->next.isEmpty()) {
1302  //Prepend the full scope before newItem
1303  DUContext* parent = m_dynamicData->m_parentContext.data();
1304  while (parent) {
1305  newItem = SearchItem::Ptr(new SearchItem(parent->d_func()->m_scopeIdentifier, newItem));
1306  parent = parent->m_dynamicData->m_parentContext.data();
1307  }
1308 
1309  newItem->isExplicitlyGlobal = true;
1310  identifiers.insert(0, newItem);
1311  }
1312  }
1313 }
1314 
1315 bool DUContext::shouldSearchInParent(SearchFlags flags) const
1316 {
1317  return (parentContext() && parentContext()->type() == DUContext::Helper && (flags & InImportedParentContext))
1318  || !(flags & InImportedParentContext);
1319 }
1320 
1321 const Use* DUContext::uses() const
1322 {
1323  ENSURE_CAN_READ
1324 
1325  return d_func()->m_uses();
1326 }
1327 
1328 bool DUContext::declarationHasUses(Declaration* decl)
1329 {
1330  return DUChain::uses()->hasUses(decl->id());
1331 }
1332 
1333 int DUContext::usesCount() const
1334 {
1335  return d_func()->m_usesSize();
1336 }
1337 
1338 bool usesRangeLessThan(const Use& left, const Use& right)
1339 {
1340  return left.m_range.start < right.m_range.start;
1341 }
1342 
1343 int DUContext::createUse(int declarationIndex, const RangeInRevision& range, int insertBefore)
1344 {
1345  DUCHAIN_D_DYNAMIC(DUContext);
1346  ENSURE_CAN_WRITE
1347 
1348  Use use(range, declarationIndex);
1349  if (insertBefore == -1) {
1350  //Find position where to insert
1351  const unsigned int size = d->m_usesSize();
1352  const Use* uses = d->m_uses();
1353  const Use* lowerBound = std::lower_bound(uses, uses + size, use, usesRangeLessThan);
1354  insertBefore = lowerBound - uses;
1355  // comment out to test this:
1356  /*
1357  unsigned int a = 0;
1358  for(; a < size && range.start > uses[a].m_range.start; ++a) {
1359  }
1360  Q_ASSERT(a == insertBefore);
1361  */
1362  }
1363 
1364  d->m_usesList().insert(insertBefore, use);
1365 
1366  return insertBefore;
1367 }
1368 
1369 void DUContext::changeUseRange(int useIndex, const RangeInRevision& range)
1370 {
1371  ENSURE_CAN_WRITE
1372  d_func_dynamic()->m_usesList()[useIndex].m_range = range;
1373 }
1374 
1375 void DUContext::setUseDeclaration(int useNumber, int declarationIndex)
1376 {
1377  ENSURE_CAN_WRITE
1378  d_func_dynamic()->m_usesList()[useNumber].m_declarationIndex = declarationIndex;
1379 }
1380 
1381 DUContext* DUContext::findContextAt(const CursorInRevision& position, bool includeRightBorder) const
1382 {
1383  ENSURE_CAN_READ
1384 
1385 // qCDebug(LANGUAGE) << "searching" << position << "in:" << scopeIdentifier(true).toString() << range() << includeRightBorder;
1386 
1387  if (!range().contains(position) && (!includeRightBorder || range().end != position)) {
1388 // qCDebug(LANGUAGE) << "mismatch";
1389  return nullptr;
1390  }
1391 
1392  const auto childContexts = m_dynamicData->m_childContexts;
1393  for (int a = childContexts.size() - 1; a >= 0; --a) {
1394  if (DUContext* specific = childContexts[a]->findContextAt(position, includeRightBorder)) {
1395  return specific;
1396  }
1397  }
1398 
1399  return const_cast<DUContext*>(this);
1400 }
1401 
1402 Declaration* DUContext::findDeclarationAt(const CursorInRevision& position) const
1403 {
1404  ENSURE_CAN_READ
1405 
1406  if (!range().contains(position))
1407  return nullptr;
1408 
1409  for (Declaration* child : qAsConst(m_dynamicData->m_localDeclarations)) {
1410  if (child->range().contains(position)) {
1411  return child;
1412  }
1413  }
1414 
1415  return nullptr;
1416 }
1417 
1418 DUContext* DUContext::findContextIncluding(const RangeInRevision& range) const
1419 {
1420  ENSURE_CAN_READ
1421 
1422  if (!this->range().contains(range))
1423  return nullptr;
1424 
1425  for (DUContext* child : qAsConst(m_dynamicData->m_childContexts)) {
1426  if (DUContext* specific = child->findContextIncluding(range)) {
1427  return specific;
1428  }
1429  }
1430 
1431  return const_cast<DUContext*>(this);
1432 }
1433 
1434 int DUContext::findUseAt(const CursorInRevision& position) const
1435 {
1436  ENSURE_CAN_READ
1437 
1438  if (!range().contains(position))
1439  return -1;
1440 
1441  for (unsigned int a = 0; a < d_func()->m_usesSize(); ++a)
1442  if (d_func()->m_uses()[a].m_range.contains(position))
1443  return a;
1444 
1445  return -1;
1446 }
1447 
1448 bool DUContext::inSymbolTable() const
1449 {
1450  return d_func()->m_inSymbolTable;
1451 }
1452 
1453 void DUContext::setInSymbolTable(bool inSymbolTable)
1454 {
1455  d_func_dynamic()->m_inSymbolTable = inSymbolTable;
1456 }
1457 
1458 void DUContext::clearImportedParentContexts()
1459 {
1460  ENSURE_CAN_WRITE
1461  DUCHAIN_D_DYNAMIC(DUContext);
1462 
1463  while (d->m_importedContextsSize() != 0) {
1464  DUContext* ctx = d->m_importedContexts()[0].context(nullptr, false);
1465  if (ctx)
1466  ctx->m_dynamicData->removeImportedChildContext(this);
1467 
1468  d->m_importedContextsList().removeOne(d->m_importedContexts()[0]);
1469  }
1470 }
1471 
1472 void DUContext::cleanIfNotEncountered(const QSet<DUChainBase*>& encountered)
1473 {
1474  ENSURE_CAN_WRITE
1475 
1476  // It may happen that the deletion of one declaration triggers the deletion of another one
1477  // Therefore we copy the list of indexed declarations and work on those. Indexed declarations
1478  // will return zero for already deleted declarations.
1479  KDevVarLengthArray<LocalIndexedDeclaration> indexedLocal;
1480  if (d_func()->m_localDeclarations()) {
1481  indexedLocal.append(d_func()->m_localDeclarations(), d_func()->m_localDeclarationsSize());
1482  }
1483  const auto currentLocalDeclarations = m_dynamicData->m_localDeclarations;
1484  for (const LocalIndexedDeclaration& indexed : currentLocalDeclarations) {
1485  auto dec = indexed.data(topContext());
1486  if (dec && !encountered.contains(dec) && (!dec->isAutoDeclaration() || !dec->hasUses())) {
1487  delete dec;
1488  }
1489  }
1490 
1491  const auto currentChildContexts = m_dynamicData->m_childContexts;
1492  for (DUContext* childContext : currentChildContexts) {
1493  if (!encountered.contains(childContext)) {
1494  delete childContext;
1495  }
1496  }
1497 }
1498 
1499 TopDUContext* DUContext::topContext() const
1500 {
1501  return m_dynamicData->m_topContext;
1502 }
1503 
1504 AbstractNavigationWidget* DUContext::createNavigationWidget(Declaration* decl, TopDUContext* topContext,
1505  AbstractNavigationWidget::DisplayHints hints) const
1506 {
1507  if (decl) {
1508  auto* widget = new AbstractNavigationWidget;
1509  widget->setDisplayHints(hints);
1510  auto* context = new AbstractDeclarationNavigationContext(DeclarationPointer(decl),
1511  TopDUContextPointer(topContext));
1512  widget->setContext(NavigationContextPointer(context));
1513  return widget;
1514  } else {
1515  return nullptr;
1516  }
1517 }
1518 
1519 QVector<RangeInRevision> allUses(DUContext* context, int declarationIndex, bool noEmptyUses)
1520 {
1521  QVector<RangeInRevision> ret;
1522  for (int a = 0; a < context->usesCount(); ++a)
1523  if (context->uses()[a].m_declarationIndex == declarationIndex)
1524  if (!noEmptyUses || !context->uses()[a].m_range.isEmpty())
1525  ret << context->uses()[a].m_range;
1526 
1527  const auto childContexts = context->childContexts();
1528  for (DUContext* child : childContexts) {
1529  ret += allUses(child, declarationIndex, noEmptyUses);
1530  }
1531 
1532  return ret;
1533 }
1534 
1535 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, const Ptr& nextItem, int start)
1536  : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false)
1537 {
1538  if (!id.isEmpty()) {
1539  if (id.count() > start)
1540  identifier = id.indexedAt(start);
1541 
1542  if (id.count() > start + 1)
1543  addNext(Ptr(new SearchItem(id, nextItem, start + 1)));
1544  else if (nextItem)
1545  next.append(nextItem);
1546  } else if (nextItem) {
1548  isExplicitlyGlobal = nextItem->isExplicitlyGlobal;
1549  identifier = nextItem->identifier;
1550  next = nextItem->next;
1551  }
1552 }
1553 
1554 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, const PtrList& nextItems, int start)
1555  : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false)
1556 {
1557  if (id.count() > start)
1558  identifier = id.indexedAt(start);
1559 
1560  if (id.count() > start + 1)
1561  addNext(Ptr(new SearchItem(id, nextItems, start + 1)));
1562  else
1563  next = nextItems;
1564 }
1565 
1566 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, const IndexedIdentifier& id, const PtrList& nextItems)
1567  : isExplicitlyGlobal(explicitlyGlobal)
1568  , identifier(id)
1569  , next(nextItems)
1570 {
1571 }
1572 
1573 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, const IndexedIdentifier& id, const Ptr& nextItem)
1574  : isExplicitlyGlobal(explicitlyGlobal)
1575  , identifier(id)
1576 {
1577  next.append(nextItem);
1578 }
1579 
1580 bool DUContext::SearchItem::match(const QualifiedIdentifier& id, int offset) const
1581 {
1582  if (id.isEmpty()) {
1583  if (identifier.isEmpty() && next.isEmpty())
1584  return true;
1585  else
1586  return false;
1587  }
1588 
1589  if (id.at(offset) != identifier) //The identifier is different
1590  return false;
1591 
1592  if (offset == id.count() - 1) {
1593  if (next.isEmpty())
1594  return true; //match
1595  else
1596  return false; //id is too short
1597  }
1598 
1599  for (int a = 0; a < next.size(); ++a)
1600  if (next[a]->match(id, offset + 1))
1601  return true;
1602 
1603  return false;
1604 }
1605 
1606 bool DUContext::SearchItem::isEmpty() const
1607 {
1608  return identifier.isEmpty();
1609 }
1610 
1611 bool DUContext::SearchItem::hasNext() const
1612 {
1613  return !next.isEmpty();
1614 }
1615 
1616 QVector<QualifiedIdentifier> DUContext::SearchItem::toList(const QualifiedIdentifier& prefix) const
1617 {
1618  QVector<QualifiedIdentifier> ret;
1619 
1620  QualifiedIdentifier id = prefix;
1621  if (id.isEmpty())
1622  id.setExplicitlyGlobal(isExplicitlyGlobal);
1623  if (!identifier.isEmpty())
1624  id.push(identifier);
1625 
1626  if (next.isEmpty()) {
1627  ret << id;
1628  } else {
1629  for (int a = 0; a < next.size(); ++a)
1630  ret += next[a]->toList(id);
1631  }
1632  return ret;
1633 }
1634 
1635 void DUContext::SearchItem::addNext(const SearchItem::Ptr& other)
1636 {
1637  next.append(other);
1638 }
1639 
1640 void DUContext::SearchItem::addToEachNode(const SearchItem::Ptr& other)
1641 {
1642  if (other->isExplicitlyGlobal)
1643  return;
1644 
1645  next.append(other);
1646  for (int a = 0; a < next.size() - 1; ++a)
1647  next[a]->addToEachNode(other);
1648 }
1649 
1650 void DUContext::SearchItem::addToEachNode(const SearchItem::PtrList& other)
1651 {
1652  int added = 0;
1653  for (const SearchItem::Ptr& o : other) {
1654  if (!o->isExplicitlyGlobal) {
1655  next.append(o);
1656  ++added;
1657  }
1658  }
1659 
1660  for (int a = 0; a < next.size() - added; ++a)
1661  next[a]->addToEachNode(other);
1662 }
1663 
1664 DUContext::Import::Import(DUContext* _context, const DUContext* importer, const CursorInRevision& _position)
1665  : position(_position)
1666 {
1667  if (_context && _context->owner() &&
1668  (_context->owner()->specialization().index() ||
1669  (importer && importer->topContext() != _context->topContext()))) {
1670  m_declaration = _context->owner()->id();
1671  } else {
1672  m_context = _context;
1673  }
1674 }
1675 
1676 DUContext::Import::Import(const DeclarationId& id, const CursorInRevision& _position)
1677  : position(_position)
1678  , m_declaration(id)
1679 {
1680 }
1681 
1682 DUContext* DUContext::Import::context(const TopDUContext* topContext, bool instantiateIfRequired) const
1683 {
1684  if (m_declaration.isValid()) {
1685  Declaration* decl = m_declaration.declaration(topContext, instantiateIfRequired);
1686  //This first case rests on the assumption that no context will ever import a function's expression context
1687  //More accurately, that no specialized or cross-topContext imports will, but if the former assumption fails the latter will too
1688  if (auto* functionDecl = dynamic_cast<AbstractFunctionDeclaration*>(decl)) {
1689  if (functionDecl->internalFunctionContext()) {
1690  return functionDecl->internalFunctionContext();
1691  } else {
1692  qCWarning(LANGUAGE) << "Import of function declaration without internal function context encountered!";
1693  }
1694  }
1695  if (decl)
1696  return decl->logicalInternalContext(topContext);
1697  else
1698  return nullptr;
1699  } else {
1700  return m_context.data();
1701  }
1702 }
1703 
1704 bool DUContext::Import::isDirect() const
1705 {
1706  return m_context.isValid();
1707 }
1708 
1709 void DUContext::visit(DUChainVisitor& visitor)
1710 {
1711  ENSURE_CAN_READ
1712 
1713  visitor.visit(this);
1714 
1715  for (Declaration* decl : qAsConst(m_dynamicData->m_localDeclarations)) {
1716  visitor.visit(decl);
1717  }
1718 
1719  for (DUContext* childContext : qAsConst(m_dynamicData->m_childContexts)) {
1720  childContext->visit(visitor);
1721  }
1722 }
1723 
1724 static bool sortByRange(const DUChainBase* lhs, const DUChainBase* rhs)
1725 {
1726  return lhs->range() < rhs->range();
1727 }
1728 
1729 void DUContext::resortLocalDeclarations()
1730 {
1731  ENSURE_CAN_WRITE
1732 
1733  std::sort(m_dynamicData->m_localDeclarations.begin(), m_dynamicData->m_localDeclarations.end(), sortByRange);
1734 
1735  auto top = topContext();
1736  auto& declarations = d_func_dynamic()->m_localDeclarationsList();
1737  std::sort(declarations.begin(), declarations.end(),
1738  [top](const LocalIndexedDeclaration& lhs, const LocalIndexedDeclaration& rhs) {
1739  return lhs.data(top)->range() < rhs.data(top)->range();
1740  });
1741 }
1742 
1743 void DUContext::resortChildContexts()
1744 {
1745  ENSURE_CAN_WRITE
1746 
1747  std::sort(m_dynamicData->m_childContexts.begin(), m_dynamicData->m_childContexts.end(), sortByRange);
1748 
1749  auto top = topContext();
1750  auto& contexts = d_func_dynamic()->m_childContextsList();
1751  std::sort(contexts.begin(), contexts.end(),
1752  [top](const LocalIndexedDUContext& lhs, const LocalIndexedDUContext& rhs) {
1753  return lhs.data(top)->range() < rhs.data(top)->range();
1754  });
1755 }
1756 }
KDevelop::DUContextDynamicData::m_indexInTopContext
uint m_indexInTopContext
Definition: ducontextdynamicdata.h:78
duchainlock.h
QList::append
void append(const T &value)
KDevelop::m_importers
KDEVPLATFORMLANGUAGE_EXPORT m_importers
Definition: ducontextdata.h:56
KDevelop::DUContext::resortChildContexts
void resortChildContexts()
Resort the child contexts by their range.
Definition: ducontext.cpp:1743
KDevelop::IndexedIdentifier::isEmpty
bool isEmpty() const
Definition: identifier.cpp:181
KDevelop::DUContext::resortLocalDeclarations
void resortLocalDeclarations()
Resort the local declarations by their range.
Definition: ducontext.cpp:1729
KDevelop::TopDUContextDynamicData::isTemporaryContextIndex
bool isTemporaryContextIndex(uint index) const
Definition: topducontextdynamicdata.cpp:826
QSet
KDevelop::DUContext::inSymbolTable
bool inSymbolTable() const
Returns whether this context is listed in the symbol table (Namespaces and classes)
Definition: ducontext.cpp:1448
KDevelop::DUContext::findDeclarations
QList< Declaration * > findDeclarations(const QualifiedIdentifier &identifier, const CursorInRevision &position=CursorInRevision::invalid(), const AbstractType::Ptr &dataType=AbstractType::Ptr(), const TopDUContext *topContext=nullptr, SearchFlags flags=NoSearchFlags) const
Searches for and returns a declaration with a given identifier in this context, which is currently ac...
Definition: ducontext.cpp:792
KDevelop::DUContext::SearchItem::Ptr
QExplicitlySharedDataPointer< SearchItem > Ptr
Definition: ducontext.h:705
KDevelop::DUContext::indexedImporters
KDevVarLengthArray< IndexedDUContext > indexedImporters() const
Returns the list of indexed importers.
Definition: ducontext.cpp:886
KDevelop::DUContext::Import::position
CursorInRevision position
Definition: ducontext.h:307
operator<<
QDebug operator<<(QDebug dbg, const KDevelop::DUContext::Import &import)
Definition: ducontext.cpp:60
KDevelop::DUContext::Global
A context that declares functions, namespaces or classes.
Definition: ducontext.h:103
KDevelop::PersistentSymbolTable::self
static PersistentSymbolTable & self()
Definition: persistentsymboltable.cpp:494
KDevelop::DUContext::SearchItem::identifier
IndexedIdentifier identifier
Definition: ducontext.h:760
KDevelop::DUContext::SearchItem::addNext
void addNext(const Ptr &other)
Definition: ducontext.cpp:1635
KDevelop::Declaration::Alias
This is an alias-declaration.
Definition: declaration.h:67
KDevelop::DUContextDynamicData::removeChildContext
bool removeChildContext(DUContext *context)
Removes the context from childContexts.
Definition: ducontext.cpp:291
KDevelop::DUContext::deleteUses
virtual void deleteUses()
Clear and delete all uses in this context.
Definition: ducontext.cpp:1174
KDevelop::TopDUContext::ownIndex
uint ownIndex() const
Definition: topducontext.cpp:537
KDevelop::DUContext::setUseDeclaration
void setUseDeclaration(int useIndex, int declarationIndex)
Assigns the declaration represented by declarationIndex to the use with index useIndex.
Definition: ducontext.cpp:1375
KDevelop::DUContext::imports
virtual bool imports(const DUContext *origin, const CursorInRevision &position=CursorInRevision::invalid()) const
Returns true if this context imports.
Definition: ducontext.cpp:814
KDevelop::DUContext::DontResolveAliases
Disables the resolution of alias declarations in the returned list.
Definition: ducontext.h:134
KDevelop::AbstractType::Ptr
TypePtr< AbstractType > Ptr
Definition: abstracttype.h:91
KDevelop::DUContext::depth
int depth() const
Calculate the depth of this context, from the top level context in the file.
Definition: ducontext.cpp:341
KDevelop::AbstractDeclarationNavigationContext
Definition: abstractdeclarationnavigationcontext.h:33
KDevelop::DUContext::SearchItem::SearchItem
SearchItem(const QualifiedIdentifier &id, const Ptr &nextItem=Ptr(), int start=0)
Constructs a representation of the given id qualified identifier, starting at its index start.
Definition: ducontext.cpp:1535
KDevelop::DUContext::declarationHasUses
static bool declarationHasUses(Declaration *decl)
Determines whether the given declaration has uses or not.
Definition: ducontext.cpp:1328
KDevelop::DUChainBase
Base class for definition-use chain objects.
Definition: duchainbase.h:131
KDevelop::DUContext::SearchItem::PtrList
KDevVarLengthArray< Ptr, 256 > PtrList
Definition: ducontext.h:706
KDevelop::DUContext::setInSymbolTable
void setInSymbolTable(bool inSymbolTable)
Move this object into/out of the symbol table.
Definition: ducontext.cpp:1453
DEFINE_LIST_MEMBER_HASH
#define DEFINE_LIST_MEMBER_HASH(container, member, type)
Definition: appendedlist.h:218
KDevelop::DUContext::findContextAt
DUContext * findContextAt(const CursorInRevision &position, bool includeBorders=false) const
Find the context which most specifically covers position.
Definition: ducontext.cpp:1381
KDevelop::isContextTemporary
bool isContextTemporary(uint index)
Definition: ducontext.cpp:199
KDevelop::Declaration::indexedIdentifier
const IndexedIdentifier & indexedIdentifier() const
Access this declaration's identifier.
Definition: declaration.cpp:210
QDebug::nospace
QDebug & nospace()
KDevelop::DUContext::addImportedParentContext
virtual void addImportedParentContext(DUContext *context, const CursorInRevision &position=CursorInRevision::invalid(), bool anonymous=false, bool temporary=false)
Adds an imported context.
Definition: ducontext.cpp:842
QSet::reserve
void reserve(int size)
KDevelop::DUContext::deleteUsesRecursively
virtual void deleteUsesRecursively()
Recursively delete all uses in this context and all its child-contexts.
Definition: ducontext.cpp:1182
KDevelop::DUContext::createUse
int createUse(int declarationIndex, const RangeInRevision &range, int insertBefore=-1)
Creates a new use of the declaration given through declarationIndex.
Definition: ducontext.cpp:1343
KDevelop::DUContextDynamicData::m_childContexts
QVector< DUContext * > m_childContexts
Definition: ducontextdynamicdata.h:83
ducontextdynamicdata.h
KDevelop::DUContext::changeUseRange
void changeUseRange(int useIndex, const RangeInRevision &range)
Definition: ducontext.cpp:1369
KDevelop::DUContext::shouldSearchInParent
virtual bool shouldSearchInParent(SearchFlags flags) const
This is called whenever the search needs to do the decision whether it should be continued in the par...
Definition: ducontext.cpp:1315
KDevelop::DUContext::SearchItem
Represents multiple qualified identifiers in a way that is better to manipulate and allows applying n...
Definition: ducontext.h:702
KDevelop::DUContext::parentContextOf
bool parentContextOf(DUContext *context) const
Iterates the tree to see if the provided context is a subcontext of this context.
Definition: ducontext.cpp:940
KDevelop::Use::m_declarationIndex
int m_declarationIndex
Definition: use.h:61
KDevelop::DUContext::SearchItem::addToEachNode
void addToEachNode(const Ptr &item)
Appends the given item to every item that can be reached from this item, and not only to the end item...
Definition: ducontext.cpp:1640
QDebug
KDevelop::DUContext::ContextType
ContextType
Definition: ducontext.h:102
m_flags
DUContext::SearchFlags m_flags
Definition: ducontext.cpp:615
KDevelop::DUContext::deleteUse
void deleteUse(int index)
Deletes the use number index.
Definition: ducontext.cpp:1167
KDevelop::IndexedIdentifier
A helper-class to store an identifier by index in a type-safe way.
Definition: identifier.h:55
KDevelop::DUContextDynamicData::addChildContext
void addChildContext(DUContext *context)
Adds a child context.
Definition: ducontext.cpp:255
KDevelop::LocalIndexedDeclaration::data
Declaration * data(TopDUContext *top) const
Definition: localindexeddeclaration.cpp:37
QList
KDevelop::DUContext::~DUContext
~DUContext() override
Destructor.
Definition: ducontext.cpp:431
KDevelop::DUContext::Template
A context that declares template-parameters.
Definition: ducontext.h:107
KDevelop::DUContext::createNavigationWidget
virtual AbstractNavigationWidget * createNavigationWidget(Declaration *decl=nullptr, TopDUContext *topContext=nullptr, AbstractNavigationWidget::DisplayHints hints=AbstractNavigationWidget::NoHints) const
Can be specialized by languages to create a navigation/information-widget.
Definition: ducontext.cpp:1504
KDevelop::TypePtr< AbstractType >
DUContextData
KDevelop::DUContext::findDeclarationsInternal
virtual bool findDeclarationsInternal(const SearchItem::PtrList &identifiers, const CursorInRevision &position, const AbstractType::Ptr &dataType, DeclarationList &ret, const TopDUContext *source, SearchFlags flags, uint depth) const
This is a more complex interface to the declaration search engine.
Definition: ducontext.cpp:682
KDevelop::IndexedDUContext::context
DUContext * context() const
Duchain must be read locked.
Definition: indexedducontext.cpp:56
topducontext.h
KDevelop::DUContext::clearImportedParentContexts
virtual void clearImportedParentContexts()
Clear all imported parent contexts.
Definition: ducontext.cpp:1458
KDevelop::IndexedQualifiedIdentifier
A helper-class to store an identifier by index in a type-safe way.
Definition: identifier.h:95
KDevelop::Declaration
Represents a single declaration in a definition-use chain.
Definition: declaration.h:51
KDevelop::DUContext::setOwner
void setOwner(Declaration *decl)
Sets the declaration/definition, and also updates it's internal context (they are strictly paired tog...
Definition: ducontext.cpp:492
aliasdeclaration.h
QExplicitlySharedDataPointer
Definition: topducontext.h:28
KDevelop::Uses::hasUses
bool hasUses(const DeclarationId &id) const
Checks whether the given DeclarationID is is used.
Definition: uses.cpp:189
KDevelop::DUContextDynamicData::VisibleDeclarationIterator
Definition: ducontextdynamicdata.h:114
KDevelop::DUContext::equalScopeIdentifier
bool equalScopeIdentifier(const DUContext *rhs) const
Returns true if this context has the same scope identifier as the given one.
Definition: ducontext.cpp:1092
KDevelop::DUContext::specialize
virtual DUContext * specialize(const IndexedInstantiationInformation &specialization, const TopDUContext *topContext, int upDistance=0)
Retrieve the context which is specialized with the given specialization as seen from the given topCon...
Definition: ducontext.cpp:1200
KDevelop::PersistentSymbolTable::declarations
void declarations(const IndexedQualifiedIdentifier &id, uint &count, const IndexedDeclaration *&declarations) const
Retrieves all the declarations for a given IndexedQualifiedIdentifier in an efficient way.
Definition: persistentsymboltable.cpp:399
KDevelop::DUContext::topContext
TopDUContext * topContext() const override
Find the top context.
Definition: ducontext.cpp:1499
KDevelop::DUContext::removeImportedParentContext
virtual void removeImportedParentContext(DUContext *context)
Removes a child context.
Definition: ducontext.cpp:866
KDevelop::Use
Represents a position in a document where a specific declaration is used.
Definition: use.h:47
KDevelop::DUContext::setLocalScopeIdentifier
void setLocalScopeIdentifier(const QualifiedIdentifier &identifier)
Scope identifier, used to qualify the identifiers occurring in each context This must not be called o...
Definition: ducontext.cpp:1113
KDevelop::LocalIndexedDUContext
Represents a DUContext within a TopDUContext, without storing the TopDUContext(It must be given to da...
Definition: localindexedducontext.h:33
KDevelop::AbstractNavigationWidget
This class deleted itself when its part is deleted, so always use a QPointer when referencing it.
Definition: abstractnavigationwidget.h:38
KDevelop::DUContext::importedParentContexts
virtual QVector< Import > importedParentContexts() const
Returns the list of imported parent contexts for this context.
Definition: ducontext.cpp:1220
KDevelop::DUContext::Import::isDirect
bool isDirect() const
Returns true if this import is direct.
Definition: ducontext.cpp:1704
KDevelop::QualifiedIdentifier::setExplicitlyGlobal
void setExplicitlyGlobal(bool eg)
Definition: identifier.cpp:893
KDevelop::DUContextDynamicData::m_localDeclarations
QVector< Declaration * > m_localDeclarations
Definition: ducontextdynamicdata.h:85
KDevelop::globalIndexedImportIdentifier
const IndexedIdentifier & globalIndexedImportIdentifier()
This is the identifier that can be used to search namespace-import declarations, and should be used t...
Definition: ducontext.cpp:96
KDevelop::LocalIndexedDUContext::data
DUContext * data(TopDUContext *top) const
Definition: localindexedducontext.cpp:52
KDevelop::Use::m_range
RangeInRevision m_range
Definition: use.h:60
KDevelop::IndexedDeclaration
Represents a declaration only by its global indices.
Definition: indexeddeclaration.h:33
KDevelop::DUContext::findUseAt
int findUseAt(const CursorInRevision &position) const
Find the use which encompasses position, if one exists.
Definition: ducontext.cpp:1434
ENSURE_CAN_WRITE
#define ENSURE_CAN_WRITE
Like the ENSURE_CHAIN_WRITE_LOCKED and .._READ_LOCKED, except that this should be used in items that ...
Definition: duchainlock.h:184
KDevelop::allUses
QVector< RangeInRevision > allUses(DUContext *context, int declarationIndex, bool noEmptyUses)
Collects all uses of the given declarationIndex.
Definition: ducontext.cpp:1519
KDevelop::DUContext::Import::context
DUContext * context(const TopDUContext *topContext, bool instantiateIfRequired=true) const
Definition: ducontext.cpp:1682
FOREACH_FUNCTION
#define FOREACH_FUNCTION(item, container)
Foreach macro that takes a container and a function-name, and will iterate through the vector returne...
Definition: appendedlist.h:213
KDevelop::DUContext::deleteChildContextsRecursively
void deleteChildContextsRecursively()
Clears and deletes all child contexts recursively.
Definition: ducontext.cpp:1061
KDevelop::DUContextDynamicData::m_context
DUContext * m_context
Definition: ducontextdynamicdata.h:80
KDevelop::DUContextDynamicData::addDeclaration
void addDeclaration(Declaration *declaration)
Definition: ducontext.cpp:204
declaration.h
KDevelop::DUContext::inDUChain
virtual bool inDUChain() const
Returns true if this declaration is accessible through the du-chain, and thus cannot be edited withou...
Definition: ducontext.cpp:1191
ducontextdata.h
KDevelop::TopDUContextDynamicData::allocateContextIndex
uint allocateContextIndex(DUContext *ctx, bool temporary)
Allocates an index for the given context in this top-context.
Definition: topducontextdynamicdata.cpp:806
KDevelop::DUContext::importers
virtual QVector< DUContext * > importers() const
Returns the list of contexts importing this context.
Definition: ducontext.cpp:898
KDevelop::DUChainBase::url
virtual IndexedString url() const
Definition: duchainbase.cpp:68
KDevelop::DUContext::InImportedParentContext
Internal, do not use from outside.
Definition: ducontext.h:118
KDevelop::DUContext::findContextIncluding
DUContext * findContextIncluding(const RangeInRevision &range) const
Find the context which most specifically covers range.
Definition: ducontext.cpp:1418
identifier.h
DUCHAIN_D
#define DUCHAIN_D(Class)
Definition: duchainbase.h:47
KDevelop::Importers::importers
KDevVarLengthArray< IndexedDUContext > importers(const DeclarationId &id) const
Gets the top-contexts of all users assigned to the declaration-id.
Definition: importers.cpp:189
KDevelop::DUChainBase::range
RangeInRevision range() const
Returns the range assigned to this object, in the document revision when this document was last parse...
Definition: duchainbase.cpp:152
KDevelop::AbstractNavigationWidget::setDisplayHints
void setDisplayHints(DisplayHints hints)
Definition: abstractnavigationwidget.cpp:182
KDevelop::DUContext::OnlyFunctions
When this is given, only function-declarations are returned.
Definition: ducontext.h:128
KDevelop::DUContext::clearLocalDeclarations
QVector< Declaration * > clearLocalDeclarations()
Clears all local declarations.
Definition: ducontext.cpp:1072
KDevVarLengthArray
KDevelop::m_localDeclarations
KDEVPLATFORMLANGUAGE_EXPORT IndexedDUContext KDEVPLATFORMLANGUAGE_EXPORT m_localDeclarations
Definition: ducontextdata.h:58
KDevelop::DUContext::NoFiltering
Should be set when no filtering at all is wished, not even filtering that is natural for the underlyi...
Definition: ducontext.h:126
KDevelop::Importers::self
static Importers & self()
Definition: importers.cpp:210
KDevelop::TopDUContext
The top context in a definition-use chain for one source file.
Definition: topducontext.h:113
KDevelop::Declaration::specialization
virtual IndexedInstantiationInformation specialization() const
TODO document.
Definition: declaration.cpp:550
KDevelop::DUChain::uses
static Uses * uses()
Returns the structure that manages mapping between declarations, and which top level contexts contain...
Definition: duchain.cpp:1689
KDevelop::DUContext::localScopeIdentifier
QualifiedIdentifier localScopeIdentifier() const
Scope identifier, used to qualify the identifiers occurring in each context.
Definition: ducontext.cpp:1122
use.h
KDevelop::IndexedDeclaration::declaration
Declaration * declaration() const
Definition: indexeddeclaration.cpp:44
KDevelop::Importers::removeImporter
void removeImporter(const DeclarationId &id, const IndexedDUContext &use)
Removes the given top-context from the list of uses.
Definition: importers.cpp:163
KDevelop::Declaration::context
DUContext * context() const
Access the parent context of this declaration.
Definition: declaration.cpp:279
QList::isEmpty
bool isEmpty() const
KDevelop::DUContext::SearchItem::isEmpty
bool isEmpty() const
Definition: ducontext.cpp:1606
KDevelop::DUContext::Helper
A helper context.
Definition: ducontext.h:109
KDevelop::DeclarationId
Allows clearly identifying a Declaration.
Definition: declarationid.h:50
KDevelop::DUContext::Other
Represents executable code, like for example within a compound-statement.
Definition: ducontext.h:113
KDevelop::DUContext::indexedLocalScopeIdentifier
IndexedQualifiedIdentifier indexedLocalScopeIdentifier() const
Same as localScopeIdentifier(), but faster.
Definition: ducontext.cpp:1129
KDevelop::TopDUContextDynamicData::clearContextIndex
void clearContextIndex(DUContext *ctx)
Definition: topducontextdynamicdata.cpp:869
KDevelop::DUContextDynamicData::m_parentContext
DUContextPointer m_parentContext
Definition: ducontextdynamicdata.h:74
KDevelop::DUContext::mergeDeclarationsInternal
virtual void mergeDeclarationsInternal(QVector< QPair< Declaration *, int >> &definitions, const CursorInRevision &position, QHash< const DUContext *, bool > &hadContexts, const TopDUContext *source, bool searchInParents=true, int currentDepth=0) const
Merges definitions and their inheritance-depth up all branches of the definition-use chain into one h...
Definition: ducontext.cpp:975
m_ownType
DUContext::ContextType m_ownType
Definition: ducontext.cpp:618
KDevelop::Declaration::setInternalContext
void setInternalContext(DUContext *context)
Set the internal context for this declaration.
Definition: declaration.cpp:431
KDevelop::Identifier
Represents a single unqualified identifier.
Definition: identifier.h:150
KDevelop::DUContext::fullyApplyAliases
QVector< QualifiedIdentifier > fullyApplyAliases(const QualifiedIdentifier &id, const TopDUContext *source) const
Returns the qualified identifier id with all aliases (for example namespace imports) applied.
Definition: ducontext.cpp:764
QVector::reserve
void reserve(int size)
KTextEditor
Definition: duchainbase.h:29
KDevelop::DUContext::Class
A context that declares class members.
Definition: ducontext.h:105
KDevelop::DUContext::DontSearchInParent
IF this flag is set, findDeclarations(..) will not search for the identifier in parent-contexts(which...
Definition: ducontext.h:120
KDevelop::NavigationContextPointer
QExplicitlySharedDataPointer< AbstractNavigationContext > NavigationContextPointer
Definition: abstractnavigationcontext.h:62
KDevelop::DUContext::findDeclarationAt
Declaration * findDeclarationAt(const CursorInRevision &position) const
Find a child declaration that has a rang that covers the given position.
Definition: ducontext.cpp:1402
maxParentDepth
const uint maxParentDepth
Definition: ducontext.cpp:48
KDevelop::DUContext::isAnonymous
bool isAnonymous() const
Whether this context, or any of its parent contexts, has been inserte anonymously into the du-chain.
Definition: ducontext.cpp:388
KDevelop::globalImportIdentifier
const Identifier & globalImportIdentifier()
We leak here, to prevent a possible crash during destruction, as the destructor of Identifier is not ...
Definition: ducontext.cpp:84
QSet::contains
bool contains(const T &value) const
KDevelop::Declaration::id
virtual DeclarationId id(bool forceDirect=false) const
Definition: declaration.cpp:564
KDevelop::QualifiedIdentifier::toString
QString toString(IdentifierStringFormattingOptions options=NoOptions) const
Definition: identifier.cpp:798
KDevelop::DUContext::childContexts
QVector< DUContext * > childContexts() const
Returns the list of immediate child contexts for this context.
Definition: ducontext.cpp:479
KDevelop::DUChainVisitor::visit
virtual void visit(DUContext *context)=0
KDevelop::DUContext::importPosition
virtual CursorInRevision importPosition(const DUContext *target) const
If the given context is directly imported into this one, and addImportedParentContext(....
Definition: ducontext.cpp:1208
KDevelop::TopDUContext::inDUChain
bool inDUChain() const override
Returns true if this object is registered in the du-chain. If it is not, all sub-objects(context,...
Definition: topducontext.cpp:1114
KDevelop::Declaration::ownIndex
uint ownIndex() const
Returns an index that uniquely identifies this declaration within its surrounding top-context.
Definition: declaration.cpp:114
REGISTER_DUCHAIN_ITEM
#define REGISTER_DUCHAIN_ITEM(Class)
You must add this into your source-files for every DUChainBase based class For this to work,...
Definition: duchainregister.h:235
persistentsymboltable.h
KDevelop::DUContext::findLocalDeclarations
QList< Declaration * > findLocalDeclarations(const IndexedIdentifier &identifier, const CursorInRevision &position=CursorInRevision::invalid(), const TopDUContext *topContext=nullptr, const AbstractType::Ptr &dataType=AbstractType::Ptr(), SearchFlags flags=NoSearchFlags) const
Returns the type of any identifier defined in this context, or null if one is not found.
Definition: ducontext.cpp:535
KDevelop::usesRangeLessThan
bool usesRangeLessThan(const Use &left, const Use &right)
Definition: ducontext.cpp:1338
KDevelop::LocalIndexedDeclaration
Represents a declaration only by its index within the top-context.
Definition: localindexeddeclaration.h:32
KDevelop::DUContextDynamicData
This class contains data that is only runtime-dependent and does not need to be stored to disk.
Definition: ducontextdynamicdata.h:46
KDevelop::DUChainVisitor
Definition: ducontext.h:49
namespacealiasdeclaration.h
KDevelop::DUContext::visit
virtual void visit(DUChainVisitor &visitor)
Visits all duchain objects in the whole duchain.
Definition: ducontext.cpp:1709
KDevelop::QualifiedIdentifier
Represents a qualified identifier.
Definition: identifier.h:245
KDevelop::DUContext::findLocalDeclarationsInternal
void findLocalDeclarationsInternal(const Identifier &identifier, const CursorInRevision &position, const AbstractType::Ptr &dataType, DeclarationList &ret, const TopDUContext *source, SearchFlags flags) const
Definition: ducontext.cpp:622
abstractfunctiondeclaration.h
KDevelop::DUContext::cleanIfNotEncountered
void cleanIfNotEncountered(const QSet< DUChainBase * > &encountered)
Delete and remove all slaves (uses, declarations, definitions, contexts) that are not in the given se...
Definition: ducontext.cpp:1472
importers.h
topducontextdynamicdata.h
duchain.h
KDevelop::DUContext::deleteLocalDeclarations
void deleteLocalDeclarations()
Clears all local declarations.
Definition: ducontext.cpp:1043
KDevelop::DUContext::addIndirectImport
bool addIndirectImport(const DUContext::Import &import)
Adds an imported context, which may be indirect.
Definition: ducontext.cpp:823
KDevelop::Declaration::logicalInternalContext
virtual DUContext * logicalInternalContext(const TopDUContext *topContext) const
Determine the logical internal context for the resolved form of this declaration.
Definition: declaration.cpp:396
KDevelop::DUContextPointer
DUChainPointer< DUContext > DUContextPointer
Definition: duchainpointer.h:198
KDevelop::Declaration::NamespaceAlias
This is a namespace-alias.
Definition: declaration.h:66
KDevelop::TopDUContextPointer
DUChainPointer< TopDUContext > TopDUContextPointer
Definition: duchainpointer.h:199
m_dataType
const AbstractType::Ptr m_dataType
Definition: ducontext.cpp:616
uses.h
KDevelop
Definition: abstractfunctiondeclaration.cpp:27
KDevelop::sortByRange
static bool sortByRange(const DUChainBase *lhs, const DUChainBase *rhs)
Definition: ducontext.cpp:1724
QSet::insert
const_iterator insert(const T &value)
KDevelop::DUContext::allDeclarations
QVector< QPair< Declaration *, int > > allDeclarations(const CursorInRevision &position, const TopDUContext *topContext, bool searchInParents=true) const
Return a list of all reachable declarations for a given cursor position in a given url.
Definition: ducontext.cpp:951
KDevelop::DUContext
A single context in source code, represented as a node in a directed acyclic graph.
Definition: ducontext.h:72
KDevelop::DUContext::Namespace
A context that declares namespace members.
Definition: ducontext.h:104
KDevelop::TopDUContext::deleting
bool deleting() const
Returns true if this object is being deleted, otherwise false.
Definition: topducontext.cpp:958
KDevelop::globalAliasIdentifier
const Identifier & globalAliasIdentifier()
This is the identifier that can be used to search namespace-alias declarations.
Definition: ducontext.cpp:90
KDevelop::DUContext::Import::Import
Import()
Definition: ducontext.h:263
KDevelop::DUContext::usesCount
int usesCount() const
Returns the count of uses that can be accessed through uses()
Definition: ducontext.cpp:1333
KDevelop::DUContext::foundEnough
virtual bool foundEnough(const DeclarationList &decls, SearchFlags flags) const
After one scope was searched, this function is asked whether more results should be collected.
Definition: ducontext.cpp:674
KDevelop::DUChainPointer::data
Type * data() const
Definition: duchainpointer.h:173
KDevelop::DUContext::SearchItem::next
PtrList next
Definition: ducontext.h:761
ENSURE_CAN_READ
#define ENSURE_CAN_READ
Definition: duchainlock.h:185
KDevelop::DUContext::isPropagateDeclarations
bool isPropagateDeclarations() const
Definition: ducontext.cpp:530
abstractdeclarationnavigationcontext.h
QVector::toList
QList< T > toList() const
QVector
KDevelop::Declaration::internalContext
DUContext * internalContext() const
Retrieve the context that is opened by this declaration, if one exists.
Definition: declaration.cpp:425
KDevelop::DUContext::DUContext
DUContext(const RangeInRevision &range, DUContext *parent=nullptr, bool anonymous=false)
Constructor.
Definition: ducontext.cpp:356
KDevelop::DUContext::SearchItem::toList
QVector< QualifiedIdentifier > toList(const QualifiedIdentifier &prefix=QualifiedIdentifier()) const
Definition: ducontext.cpp:1616
KDevelop::DUContext::owner
Declaration * owner() const
If this context was opened by a declaration or definition, this returns that item.
Definition: ducontext.cpp:486
KDevelop::DUContext::uses
const Use * uses() const
Uses: A "Use" represents any position in a document where a Declaration is used literally.
Definition: ducontext.cpp:1321
ENSURE_CAN_WRITE_
#define ENSURE_CAN_WRITE_(x)
Definition: ducontext.cpp:53
KDevelop::DUContextDynamicData::m_topContext
TopDUContext * m_topContext
Definition: ducontextdynamicdata.h:76
duchainregister.h
KDevelop::DUContextDynamicData::scopeIdentifier
void scopeIdentifier(bool includeClasses, QualifiedIdentifier &target) const
Definition: ducontext.cpp:170
QHash::contains
bool contains(const Key &key) const
KDevelop::globalIndexedAliasIdentifier
const IndexedIdentifier & globalIndexedAliasIdentifier()
This is the identifier that can be used to search namespace-alias declarations.
Definition: ducontext.cpp:102
KDevelop::Importers::addImporter
void addImporter(const DeclarationId &id, const IndexedDUContext &use)
Adds a top-context to the users-list of the given id.
Definition: importers.cpp:136
KDevelop::DUContext::localDeclarations
virtual QVector< Declaration * > localDeclarations(const TopDUContext *source=nullptr) const
Returns all local declarations.
Definition: ducontext.cpp:967
KDevelop::DUContextDynamicData::imports
bool imports(const DUContext *context, const TopDUContext *source, QSet< const DUContextDynamicData * > *recursionGuard) const
Returns true if this context is imported by the given one, on any level.
Definition: ducontext.cpp:179
KDevelop::DUContext::type
ContextType type() const
Definition: ducontext.cpp:1134
KDevelop::DUContext::setType
void setType(ContextType type)
Definition: ducontext.cpp:1141
KDevelop::DeclarationPointer
DUChainPointer< Declaration > DeclarationPointer
Definition: duchainpointer.h:200
QHash
ducontext.h
abstractnavigationwidget.h
KDevelop::TopDUContext::isOnDisk
bool isOnDisk() const
Whether this top-context has a stored version on disk.
Definition: topducontext.cpp:1125
KDevelop::DUContext::applyUpwardsAliases
virtual void applyUpwardsAliases(SearchItem::PtrList &identifiers, const TopDUContext *source) const
Applies the aliases that need to be applied when moving the search from this context up to the parent...
Definition: ducontext.cpp:1288
QPair
KDevelop::TopDUContext::m_dynamicData
class TopDUContextDynamicData * m_dynamicData
Definition: topducontext.h:381
KDevelop::DUContext::applyAliases
void applyAliases(const SearchItem::PtrList &identifiers, SearchItem::PtrList &targetIdentifiers, const CursorInRevision &position, bool canBeNamespace, bool onlyImports=false) const
Applies namespace-imports and namespace-aliases and returns possible absolute identifiers that need t...
Definition: ducontext.cpp:1230
KDevelop::DUContextDynamicData::addImportedChildContext
void addImportedChildContext(DUContext *context)
Definition: ducontext.cpp:307
KDevelop::DUContext::SearchItem::hasNext
bool hasNext() const
Definition: ducontext.cpp:1611
KDevelop::DUContext::SearchItem::isExplicitlyGlobal
bool isExplicitlyGlobal
Definition: ducontext.h:759
KDevelop::DUContext::SearchItem::match
bool match(const QualifiedIdentifier &id, int offset=0) const
Returns true if the given identifier matches one of the identifiers represented by this SearchItem.
Definition: ducontext.cpp:1580
m_position
const CursorInRevision m_position
Definition: ducontext.cpp:617
KDevelop::DUContext::parentContext
DUContext * parentContext() const
Returns the immediate parent context of this context.
Definition: ducontext.cpp:512
KDevelop::DUContextDynamicData::removeImportedChildContext
void removeImportedChildContext(DUContext *context)
Definition: ducontext.cpp:328
KDevelop::DUContext::scopeIdentifier
QualifiedIdentifier scopeIdentifier(bool includeClasses=false) const
Calculate the fully qualified scope identifier.
Definition: ducontext.cpp:1082
KDevelop::DUContext::setPropagateDeclarations
void setPropagateDeclarations(bool propagate)
If this is set to true, all declarations that are added to this context will also be visible in the p...
Definition: ducontext.cpp:519
DUCHAIN_D_DYNAMIC
#define DUCHAIN_D_DYNAMIC(Class)
Definition: duchainbase.h:48
KDevelop::DUContext::findContext
DUContext * findContext(const CursorInRevision &position, DUContext *parent=nullptr) const
Searches for the most specific context for the given cursor position in the given url.
Definition: ducontext.cpp:919
KDevelop::DUContextDynamicData::removeDeclaration
bool removeDeclaration(Declaration *declaration)
Removes the declaration from localDeclarations.
Definition: ducontext.cpp:241
KDevelop::IndexedDUContext
Represents a context only by its global indices.
Definition: indexedducontext.h:35
KDevelop::DUContext::Import
Represents an imported parent context.
Definition: ducontext.h:256
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Mar 7 2021 23:29:30 by doxygen 1.8.16 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kdevplatform/language/duchain

Skip menu "kdevplatform/language/duchain"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdevelop API Reference

Skip menu "kdevelop API Reference"
  • kdevplatform
  •   debugger
  •   documentation
  •   interfaces
  •   language
  •     assistant
  •     backgroundparser
  •     checks
  •     classmodel
  •     codecompletion
  •     codegen
  •     duchain
  •     editor
  •     highlighting
  •     interfaces
  •     util
  •   outputview
  •   project
  •   serialization
  •   shell
  •   sublime
  •   tests
  •   util
  •   vcs

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal