Add AbstractDeclarationNavigationContext, and move the html-method from
[kdevelopdvcssupport.git] / language / duchain / ducontext.cpp
blob830f13b8b3f530aae9c9d9ec0a45de0df2a48492
1 /* This is part of KDevelop
2 Copyright 2006 Hamish Rodda <rodda@kde.org>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
19 #include "ducontext.h"
21 #include <limits>
23 #include <QMutableLinkedListIterator>
24 #include <QSet>
26 #include <ktexteditor/document.h>
27 #include <ktexteditor/smartinterface.h>
29 #include "../editor/editorintegrator.h"
31 #include "ducontextdata.h"
32 #include "declaration.h"
33 #include "duchain.h"
34 #include "duchainlock.h"
35 #include "use.h"
36 #include "identifier.h"
37 #include "topducontext.h"
38 #include "persistentsymboltable.h"
39 #include "aliasdeclaration.h"
40 #include "namespacealiasdeclaration.h"
41 #include "abstractfunctiondeclaration.h"
42 #include "indexedstring.h"
43 #include "duchainregister.h"
44 #include "topducontextdynamicdata.h"
45 #include "arrayhelpers.h"
46 #include "codemodel.h"
48 ///It is fine to use one global static mutex here
50 using namespace KTextEditor;
52 //Stored statically for performance-reasons
54 #ifndef NDEBUG
55 #define ENSURE_CAN_WRITE_(x) {if(x->inDUChain()) { ENSURE_CHAIN_WRITE_LOCKED }}
56 #define ENSURE_CAN_READ_(x) {if(x->inDUChain()) { ENSURE_CHAIN_READ_LOCKED }}
57 #else
58 #define ENSURE_CAN_WRITE_(x)
59 #define ENSURE_CAN_READ_(x)
60 #endif
62 namespace KDevelop
64 QMutex DUContextDynamicData::m_localDeclarationsMutex(QMutex::Recursive);
66 template<class Container>
67 bool removeOneImport(Container& container, const DUContext* value) {
68 for(int a = 0; a < container.size(); ++a) {
69 if(container[a].context() == value) {
70 removeFromArray(container, a);
71 return true;
74 return false;
77 DEFINE_LIST_MEMBER_HASH(DUContextData, m_childContexts, LocalIndexedDUContext)
78 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importers, IndexedDUContext)
79 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importedContexts, DUContext::Import)
80 DEFINE_LIST_MEMBER_HASH(DUContextData, m_localDeclarations, LocalIndexedDeclaration)
81 DEFINE_LIST_MEMBER_HASH(DUContextData, m_uses, Use)
83 REGISTER_DUCHAIN_ITEM(DUContext);
85 const Identifier globalImportIdentifier("{...import...}");
87 void DUContext::rebuildDynamicData(DUContext* parent, uint ownIndex) {
89 Q_ASSERT(!parent || ownIndex);
90 m_dynamicData->m_topContext = parent ? parent->topContext() : static_cast<TopDUContext*>(this);
91 m_dynamicData->m_indexInTopContext = ownIndex;
92 m_dynamicData->m_parentContext = DUContextPointer(parent);
93 m_dynamicData->m_context = this;
95 DUChainBase::rebuildDynamicData(parent, ownIndex);
98 DUContextData::DUContextData()
99 : m_inSymbolTable(false), m_anonymousInParent(false), m_propagateDeclarations(false)
101 initializeAppendedLists();
104 DUContextData::~DUContextData() {
105 freeAppendedLists();
108 DUContextData::DUContextData(const DUContextData& rhs) : DUChainBaseData(rhs), m_inSymbolTable(rhs.m_inSymbolTable), m_anonymousInParent(rhs.m_anonymousInParent), m_propagateDeclarations(rhs.m_propagateDeclarations) {
109 initializeAppendedLists();
110 copyListsFrom(rhs);
111 m_scopeIdentifier = rhs.m_scopeIdentifier;
112 m_contextType = rhs.m_contextType;
113 m_owner = rhs.m_owner;
116 DUContextDynamicData::DUContextDynamicData(DUContext* d)
117 : m_topContext(0), m_hasLocalDeclarationsHash(false), m_indexInTopContext(0), m_context(d), m_rangesChanged(true)
121 void DUContextDynamicData::scopeIdentifier(bool includeClasses, QualifiedIdentifier& target) const {
122 if (m_parentContext)
123 m_parentContext->m_dynamicData->scopeIdentifier(includeClasses, target);
125 if (includeClasses || m_context->d_func()->m_contextType != DUContext::Class)
126 target += m_context->d_func()->m_scopeIdentifier;
129 bool DUContextDynamicData::isThisImportedBy(const DUContext* context) const {
130 if( this == context->m_dynamicData )
131 return true;
133 FOREACH_FUNCTION( IndexedDUContext ctx, m_context->d_func()->m_importers ) {
134 if( IndexedTopDUContext(ctx.topContextIndex()).isLoaded() && ctx.context() && ctx.context()->m_dynamicData->isThisImportedBy(context) )
135 return true;
138 return false;
141 IndexedDUContext::IndexedDUContext(uint topContext, uint contextIndex) : m_topContext(topContext), m_contextIndex(contextIndex) {
144 IndexedDUContext::IndexedDUContext(DUContext* ctx) {
145 if(ctx) {
146 m_topContext = ctx->topContext()->ownIndex();
147 m_contextIndex = ctx->m_dynamicData->m_indexInTopContext;
148 }else{
149 m_topContext = 0;
150 m_contextIndex = 0;
154 IndexedTopDUContext IndexedDUContext::indexedTopContext() const {
155 return IndexedTopDUContext(m_topContext);
158 LocalIndexedDUContext::LocalIndexedDUContext(uint contextIndex) : m_contextIndex(contextIndex) {
161 LocalIndexedDUContext::LocalIndexedDUContext(DUContext* ctx) {
162 if(ctx) {
163 m_contextIndex = ctx->m_dynamicData->m_indexInTopContext;
164 }else{
165 m_contextIndex = 0;
169 bool LocalIndexedDUContext::isLoaded(TopDUContext* top) const {
170 if(!m_contextIndex)
171 return false;
172 else
173 return top->m_dynamicData->isContextForIndexLoaded(m_contextIndex);
176 DUContext* LocalIndexedDUContext::data(TopDUContext* top) const {
177 if(!m_contextIndex)
178 return 0;
179 else
180 return top->m_dynamicData->getContextForIndex(m_contextIndex);
183 DUContext* IndexedDUContext::context() const {
184 ENSURE_CHAIN_READ_LOCKED
185 if(!m_topContext)
186 return 0;
188 TopDUContext* ctx = DUChain::self()->chainForIndex(m_topContext);
189 if(!ctx)
190 return 0;
192 if(!m_contextIndex)
193 return ctx;
195 return ctx->m_dynamicData->getContextForIndex(m_contextIndex);
198 void DUContext::synchronizeUsesFromSmart() const
200 DUCHAIN_D(DUContext);
202 if(m_dynamicData->m_rangesForUses.isEmpty() || !m_dynamicData->m_rangesChanged)
203 return;
205 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.count()) == d->m_usesSize());
207 for(unsigned int a = 0; a < d->m_usesSize(); a++)
208 if(m_dynamicData->m_rangesForUses[a]) ///@todo somehow signalize the change
209 const_cast<Use&>(d->m_uses()[a]).m_range = SimpleRange(*m_dynamicData->m_rangesForUses[a]);
211 m_dynamicData->m_rangesChanged = false;
214 void DUContext::synchronizeUsesToSmart() const
216 DUCHAIN_D(DUContext);
217 if(m_dynamicData->m_rangesForUses.isEmpty())
218 return;
219 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.count()) == d->m_usesSize());
221 // TODO: file close race? from here
222 KTextEditor::SmartInterface *iface = qobject_cast<KTextEditor::SmartInterface*>( smartRange()->document() );
223 Q_ASSERT(iface);
225 // TODO: file close race to here
226 QMutexLocker l(iface->smartMutex());
228 for(unsigned int a = 0; a < d->m_usesSize(); a++) {
229 if(a % 10 == 0) { //Unlock the smart-lock time by time, to increase responsiveness
230 l.unlock();
231 l.relock();
233 if(m_dynamicData->m_rangesForUses[a]) {
234 m_dynamicData->m_rangesForUses[a]->start() = d->m_uses()[a].m_range.start.textCursor();
235 m_dynamicData->m_rangesForUses[a]->end() = d->m_uses()[a].m_range.end.textCursor();
236 }else{
237 kDebug() << "bad smart-range";
242 void DUContext::rangePositionChanged(KTextEditor::SmartRange* range)
244 if(range != smartRange())
245 m_dynamicData->m_rangesChanged = true;
248 void DUContext::rangeDeleted(KTextEditor::SmartRange* range)
250 if(range == smartRange()) {
251 DocumentRangeObject::rangeDeleted(range);
252 } else {
253 range->removeWatcher(this);
254 int index = m_dynamicData->m_rangesForUses.indexOf(range);
255 if(index != -1) {
256 d_func_dynamic()->m_usesList()[index].m_range = SimpleRange(*range);
257 m_dynamicData->m_rangesForUses[index] = 0;
260 if(m_dynamicData->m_rangesForUses.count(0) == m_dynamicData->m_rangesForUses.size())
261 m_dynamicData->m_rangesForUses.clear();
265 void DUContextDynamicData::enableLocalDeclarationsHash(DUContext* ctx, const Identifier& currentIdentifier, Declaration* currentDecl)
267 m_hasLocalDeclarationsHash = true;
269 FOREACH_FUNCTION(LocalIndexedDeclaration indexedDecl, ctx->d_func()->m_localDeclarations) {
270 Declaration* decl = indexedDecl.data(m_topContext);
271 Q_ASSERT(decl);
272 if(currentDecl != decl)
273 m_localDeclarationsHash.insert( decl->identifier(), DeclarationPointer(decl) );
274 else
275 m_localDeclarationsHash.insert( currentIdentifier, DeclarationPointer(decl) );
278 FOREACH_FUNCTION(LocalIndexedDUContext child, ctx->d_func()->m_childContexts) {
279 DUContext* childCtx = child.data(m_topContext);
280 Q_ASSERT(childCtx);
281 if(childCtx->d_func()->m_propagateDeclarations)
282 enableLocalDeclarationsHash(childCtx, currentIdentifier, currentDecl);
286 void DUContextDynamicData::disableLocalDeclarationsHash()
288 m_hasLocalDeclarationsHash = false;
289 m_localDeclarationsHash.clear();
292 bool DUContextDynamicData::needsLocalDeclarationsHash()
294 ///@todo Do this again, it brings a large performance boost
295 //For now disable the hash, until we make sure that all declarations needed for the hash are loaded first
296 //including those in propagating sub-contexts.
297 //Then, also make sure that we create the declaration hash after loading if needed
298 return false;
300 if(m_context->d_func()->m_localDeclarationsSize() > 15)
301 return true;
303 uint propagatingChildContexts = 0;
305 FOREACH_FUNCTION(LocalIndexedDUContext child, m_context->d_func()->m_childContexts) {
306 DUContext* childCtx = child.data(m_topContext);
307 Q_ASSERT(childCtx);
308 if(childCtx->d_func()->m_propagateDeclarations)
309 ++propagatingChildContexts;
312 return propagatingChildContexts > 4;
315 void DUContextDynamicData::addDeclarationToHash(const Identifier& identifier, Declaration* declaration)
317 if(m_hasLocalDeclarationsHash)
318 m_localDeclarationsHash.insert( identifier, DeclarationPointer(declaration) );
320 if( m_context->d_func()->m_propagateDeclarations && m_parentContext )
321 m_parentContext->m_dynamicData->addDeclarationToHash(identifier, declaration);
323 if(!m_hasLocalDeclarationsHash && needsLocalDeclarationsHash())
324 enableLocalDeclarationsHash(m_context, identifier, declaration);
327 void DUContextDynamicData::removeDeclarationFromHash(const Identifier& identifier, Declaration* declaration)
329 if(m_hasLocalDeclarationsHash)
330 m_localDeclarationsHash.remove( identifier, DeclarationPointer(declaration) );
332 if( m_context->d_func()->m_propagateDeclarations && m_parentContext )
333 m_parentContext->m_dynamicData->removeDeclarationFromHash(identifier, declaration);
335 if(m_hasLocalDeclarationsHash && !needsLocalDeclarationsHash())
336 disableLocalDeclarationsHash();
339 void DUContextDynamicData::addDeclaration( Declaration * newDeclaration )
341 // The definition may not have its identifier set when it's assigned... allow dupes here, TODO catch the error elsewhere
343 QMutexLocker lock(&m_localDeclarationsMutex);
345 // m_localDeclarations.append(newDeclaration);
347 if(m_indexInTopContext < (0xffffffff/2)) {
348 //If this context is not temporary, added declarations shouldn't be either
349 Q_ASSERT(newDeclaration->ownIndex() < (0xffffffff/2));
351 if(m_indexInTopContext > (0xffffffff/2)) {
352 //If this context is temporary, added declarations should be as well
353 Q_ASSERT(newDeclaration->ownIndex() > (0xffffffff/2));
356 SimpleCursor start = newDeclaration->range().start;
358 bool inserted = false;
359 for (int i = m_context->d_func_dynamic()->m_localDeclarationsSize()-1; i >= 0; --i) {
360 Declaration* child = m_context->d_func_dynamic()->m_localDeclarations()[i].data(m_topContext);
361 Q_ASSERT(child);
362 if(child == newDeclaration)
363 return;
364 if (start > child->range().start) {
365 insertToArray(m_context->d_func_dynamic()->m_localDeclarationsList(), newDeclaration, i+1);
366 inserted = true;
367 break;
370 if( !inserted )
371 m_context->d_func_dynamic()->m_localDeclarationsList().append(newDeclaration);
373 addDeclarationToHash(newDeclaration->identifier(), newDeclaration);
376 //DUChain::contextChanged(m_context, DUChainObserver::Addition, DUChainObserver::LocalDeclarations, newDeclaration);
379 bool DUContextDynamicData::removeDeclaration(Declaration* declaration)
381 QMutexLocker lock(&m_localDeclarationsMutex);
383 if(!m_topContext->deleting()) //We can save a lot of time by just not caring about the hash while deleting
384 removeDeclarationFromHash(declaration->identifier(), declaration);
386 if( removeOne(m_context->d_func_dynamic()->m_localDeclarationsList(), LocalIndexedDeclaration(declaration)) ) {
387 //DUChain::contextChanged(m_context, DUChainObserver::Removal, DUChainObserver::LocalDeclarations, declaration);
388 return true;
389 }else {
390 return false;
394 void DUContext::changingIdentifier( Declaration* decl, const Identifier& from, const Identifier& to ) {
395 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
396 m_dynamicData->removeDeclarationFromHash(from, decl);
397 m_dynamicData->addDeclarationToHash(to, decl);
400 void DUContextDynamicData::addChildContext( DUContext * context )
402 // Internal, don't need to assert a lock
403 Q_ASSERT(!context->m_dynamicData->m_parentContext || context->m_dynamicData->m_parentContext.data()->m_dynamicData == this );
405 LocalIndexedDUContext indexed(context->m_dynamicData->m_indexInTopContext);
407 if(m_indexInTopContext < (0xffffffff/2)) {
408 //If this context is not temporary, added declarations shouldn't be either
409 Q_ASSERT(indexed.localIndex() < (0xffffffff/2));
411 if(m_indexInTopContext > (0xffffffff/2)) {
412 //If this context is temporary, added declarations should be as well
413 Q_ASSERT(indexed.localIndex() > (0xffffffff/2));
416 bool inserted = false;
418 int childCount = m_context->d_func()->m_childContextsSize();
420 //Optimization: In most cases while parsing, the new child-context will be added to the end, so check if it is the case.
421 if(m_context->d_func()->m_childContextsSize() != 0) {
422 if(m_context->d_func()->m_childContexts()[childCount-1].data(m_topContext)->range().start <= context->range().start)
423 goto insertAtEnd;
426 for (int i = 0; i < childCount; ++i) {
427 DUContext* child = m_context->d_func()->m_childContexts()[i].data(m_topContext);
428 if (context == child)
429 return;
430 if (context->range().start < child->range().start) {
431 insertToArray(m_context->d_func_dynamic()->m_childContextsList(), indexed, i);
432 context->m_dynamicData->m_parentContext = m_context;
433 inserted = true;
434 break;
438 insertAtEnd:
439 if( !inserted ) {
440 m_context->d_func_dynamic()->m_childContextsList().append(indexed);
441 context->m_dynamicData->m_parentContext = m_context;
444 if(context->d_func()->m_propagateDeclarations) {
445 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
446 disableLocalDeclarationsHash();
447 if(needsLocalDeclarationsHash())
448 enableLocalDeclarationsHash(m_context);
451 //DUChain::contextChanged(m_context, DUChainObserver::Addition, DUChainObserver::ChildContexts, context);
454 bool DUContextDynamicData::removeChildContext( DUContext* context ) {
455 // ENSURE_CAN_WRITE
457 if( removeOne(m_context->d_func_dynamic()->m_childContextsList(), LocalIndexedDUContext(context)) )
458 return true;
459 else
460 return false;
463 void DUContextDynamicData::addImportedChildContext( DUContext * context )
465 // ENSURE_CAN_WRITE
466 Q_ASSERT(!arrayContains(m_context->d_func_dynamic()->m_importersList(), IndexedDUContext(context)));
468 m_context->d_func_dynamic()->m_importersList().append(context);
470 //DUChain::contextChanged(m_context, DUChainObserver::Addition, DUChainObserver::ImportedChildContexts, context);
473 //Can also be called with a context that is not in the list
474 void DUContextDynamicData::removeImportedChildContext( DUContext * context )
476 // ENSURE_CAN_WRITE
477 removeOne(m_context->d_func_dynamic()->m_importersList(), IndexedDUContext(context));
478 //if( != 0 )
479 //DUChain::contextChanged(m_context, DUChainObserver::Removal, DUChainObserver::ImportedChildContexts, context);
482 int DUContext::depth() const
484 { if (!parentContext()) return 0; return parentContext()->depth() + 1; }
487 DUContext::DUContext(DUContextData& data) : DUChainBase(data), m_dynamicData(new DUContextDynamicData(this)) {
491 DUContext::DUContext(const SimpleRange& range, DUContext* parent, bool anonymous)
492 : DUChainBase(*new DUContextData(), range), m_dynamicData(new DUContextDynamicData(this))
494 d_func_dynamic()->setClassId(this);
495 if(parent)
496 m_dynamicData->m_topContext = parent->topContext();
497 else
498 m_dynamicData->m_topContext = static_cast<TopDUContext*>(this);
500 d_func_dynamic()->setClassId(this);
501 DUCHAIN_D_DYNAMIC(DUContext);
502 d->m_contextType = Other;
503 m_dynamicData->m_parentContext = 0;
505 d->m_anonymousInParent = anonymous;
506 d->m_inSymbolTable = false;
508 if (parent) {
509 m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this, parent->isAnonymous() || anonymous);
510 Q_ASSERT(m_dynamicData->m_indexInTopContext);
512 if( !anonymous )
513 parent->m_dynamicData->addChildContext(this);
514 else
515 m_dynamicData->m_parentContext = parent;
518 if(parent && !anonymous && parent->inSymbolTable())
519 setInSymbolTable(true);
522 bool DUContext::isAnonymous() const {
523 return d_func()->m_anonymousInParent || (m_dynamicData->m_parentContext && m_dynamicData->m_parentContext->isAnonymous());
526 DUContext::DUContext( DUContextData& dd, const SimpleRange& range, DUContext * parent, bool anonymous )
527 : DUChainBase(dd, range), m_dynamicData(new DUContextDynamicData(this))
529 if(parent)
530 m_dynamicData->m_topContext = parent->topContext();
531 else
532 m_dynamicData->m_topContext = static_cast<TopDUContext*>(this);
534 DUCHAIN_D_DYNAMIC(DUContext);
535 d->m_contextType = Other;
536 m_dynamicData->m_parentContext = 0;
537 d->m_inSymbolTable = false;
538 d->m_anonymousInParent = anonymous;
539 if (parent) {
540 m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this, parent->isAnonymous() || anonymous);
542 if( !anonymous )
543 parent->m_dynamicData->addChildContext(this);
544 else
545 m_dynamicData->m_parentContext = parent;
549 DUContext::DUContext(DUContext& useDataFrom)
550 : DUChainBase(useDataFrom), m_dynamicData(useDataFrom.m_dynamicData)
554 DUContext::~DUContext( )
556 ///@todo Don't create dynamic versions of the data while destroying!
557 DUCHAIN_D_DYNAMIC(DUContext);
558 TopDUContext* top = topContext();
560 if(!top->deleting() || !top->isOnDisk()) {
561 QualifiedIdentifier id(scopeIdentifier(true));
562 if(d->m_inSymbolTable && parentContext()) {
563 PersistentSymbolTable::self().removeContext(id, this);
565 //We put namespaces into the code-model
566 if(d->m_contextType == DUContext::Namespace)
567 CodeModel::self().removeItem(url(), id);
570 if(d->m_owner.declaration())
571 d->m_owner.declaration()->setInternalContext(0);
573 while( d->m_importersSize() != 0 )
574 d->m_importers()[0].data()->removeImportedParentContext(this);
576 while( d->m_importedContextsSize() != 0 )
577 if( d->m_importedContexts()[0].context() )
578 removeImportedParentContext(d->m_importedContexts()[0].context());
579 else
580 removeOneImport(d->m_importedContextsList(), 0);
583 deleteChildContextsRecursively();
585 deleteUses();
587 deleteLocalDeclarations();
589 if (m_dynamicData->m_parentContext)
590 m_dynamicData->m_parentContext->m_dynamicData->removeChildContext(this);
591 //DUChain::contextChanged(this, DUChainObserver::Deletion, DUChainObserver::NotApplicable);
593 if(top)
594 top->m_dynamicData->clearContextIndex(this);
597 QVector< DUContext * > DUContext::childContexts( ) const
599 ENSURE_CAN_READ
601 QVector< DUContext * > ret;
602 FOREACH_FUNCTION(LocalIndexedDUContext ctx, d_func()->m_childContexts)
603 ret << ctx.data(topContext());
604 return ret;
607 Declaration* DUContext::owner() const {
608 ENSURE_CAN_READ
609 return d_func()->m_owner.declaration();
612 void DUContext::setOwner(Declaration* owner) {
613 ENSURE_CAN_WRITE
614 DUCHAIN_D_DYNAMIC(DUContext);
615 if( owner == d->m_owner.declaration() )
616 return;
618 Declaration* oldOwner = d->m_owner.declaration();
620 d->m_owner = owner;
622 //Q_ASSERT(!oldOwner || oldOwner->internalContext() == this);
623 if( oldOwner && oldOwner->internalContext() == this )
624 oldOwner->setInternalContext(0);
627 //The context set as internal context should always be the last opened context
628 if( owner )
629 owner->setInternalContext(this);
632 DUContext* DUContext::parentContext( ) const
634 //ENSURE_CAN_READ Commented out for performance reasons
636 return m_dynamicData->m_parentContext.data();
639 void DUContext::setPropagateDeclarations(bool propagate)
641 ENSURE_CAN_WRITE
642 DUCHAIN_D_DYNAMIC(DUContext);
643 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
645 m_dynamicData->m_parentContext->m_dynamicData->disableLocalDeclarationsHash();
647 d->m_propagateDeclarations = propagate;
649 if(m_dynamicData->m_parentContext->m_dynamicData->needsLocalDeclarationsHash())
650 m_dynamicData->m_parentContext->m_dynamicData->enableLocalDeclarationsHash(m_dynamicData->m_parentContext.data());
653 bool DUContext::isPropagateDeclarations() const
655 return d_func()->m_propagateDeclarations;
658 QList<Declaration*> DUContext::findLocalDeclarations( const Identifier& identifier, const SimpleCursor & position, const TopDUContext* topContext, const AbstractType::Ptr& dataType, SearchFlags flags ) const
660 ENSURE_CAN_READ
662 DeclarationList ret;
663 findLocalDeclarationsInternal(identifier, position.isValid() ? position : range().end, dataType, ret, topContext ? topContext : this->topContext(), flags);
664 return arrayToList(ret);
667 void DUContext::findLocalDeclarationsInternal( const Identifier& identifier, const SimpleCursor & position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* /*source*/, SearchFlags flags ) const
669 IndexedIdentifier indexedIdentifier(identifier);
671 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
673 struct Checker {
674 Checker(SearchFlags flags, const AbstractType::Ptr& dataType, const SimpleCursor & position, DUContext::ContextType ownType) : m_flags(flags), m_dataType(dataType), m_position(position), m_ownType(ownType) {
677 Declaration* check(Declaration* declaration) {
678 if( declaration->kind() == Declaration::Alias ) {
679 //Apply alias declarations
680 AliasDeclaration* alias = static_cast<AliasDeclaration*>(declaration);
681 if(alias->aliasedDeclaration().isValid()) {
682 declaration = alias->aliasedDeclaration().declaration();
683 } else {
684 kDebug() << "lost aliased declaration";
688 if( declaration->kind() == Declaration::NamespaceAlias )
689 return 0;
691 if((m_flags & OnlyFunctions) && !declaration->isFunctionDeclaration())
692 return 0;
694 if (!m_dataType || m_dataType == declaration->abstractType())
695 if (m_ownType == Class || m_ownType == Template || m_position > declaration->range().start || !m_position.isValid()) ///@todo This is C++-specific
696 return declaration;
697 return 0;
700 SearchFlags m_flags;
701 const AbstractType::Ptr& m_dataType;
702 const SimpleCursor& m_position;
703 DUContext::ContextType m_ownType;
706 Checker checker(flags, dataType, position, type());
708 if(!m_dynamicData->m_hasLocalDeclarationsHash) {
709 //Use a special hash that contains all declarations visible in this context
710 DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
711 while(it) {
712 Declaration* declaration = *it;
713 if(declaration->indexedIdentifier() == indexedIdentifier) {
714 Declaration* checked = checker.check(declaration);
715 if(checked)
716 ret.append(checked);
718 ++it;
720 }else if(d_func()->m_inSymbolTable) {
721 //This context is in the symbol table, use the symbol-table to speed up the search
722 QualifiedIdentifier id(scopeIdentifier(true) + identifier);
724 TopDUContext* top = topContext();
726 uint count;
727 const IndexedDeclaration* declarations;
728 PersistentSymbolTable::self().declarations(id, count, declarations);
729 for(uint a = 0; a < count; ++a) {
730 if(declarations[a].topContextIndex() == top->ownIndex()) {
731 Declaration* decl = LocalIndexedDeclaration(declarations[a].localIndex()).data(top);
732 if(decl) {
733 Declaration* checked = checker.check(decl);
734 if(checked)
735 ret.append(checked);
739 }else{
740 //Iterate through all declarations
741 QHash<Identifier, DeclarationPointer>::const_iterator it = m_dynamicData->m_localDeclarationsHash.find(identifier);
742 QHash<Identifier, DeclarationPointer>::const_iterator end = m_dynamicData->m_localDeclarationsHash.end();
744 for( ; it != end && it.key() == identifier; ++it ) {
745 Declaration* declaration = (*it).data();
747 if( !declaration ) {
748 //This should never happen, but let's see
749 kDebug(9505) << "DUContext::findLocalDeclarationsInternal: Invalid declaration in local-declaration-hash";
750 continue;
753 Declaration* checked = checker.check(declaration);
754 if(checked)
755 ret.append(checked);
761 bool DUContext::foundEnough( const DeclarationList& ret ) const {
762 if( !ret.isEmpty() )
763 return true;
764 else
765 return false;
768 bool DUContext::findDeclarationsInternal( const SearchItem::PtrList & baseIdentifiers, const SimpleCursor & position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source, SearchFlags flags ) const
770 DUCHAIN_D(DUContext);
771 if( d_func()->m_contextType != Namespace ) { //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.
772 for(int a = 0; a < baseIdentifiers.size(); ++a)
773 if(!baseIdentifiers[a]->isExplicitlyGlobal && baseIdentifiers[a]->next.isEmpty()) //It makes no sense searching locally for qualified identifiers
774 findLocalDeclarationsInternal(baseIdentifiers[a]->identifier, position, dataType, ret, source, flags);
776 if( foundEnough(ret) )
777 return true;
780 ///Step 1: Apply namespace-aliases and -imports
781 SearchItem::PtrList aliasedIdentifiers;
782 //Because of namespace-imports and aliases, this identifier may need to be searched under multiple names
783 if( d_func()->m_contextType == Namespace )
784 applyAliases(baseIdentifiers, aliasedIdentifiers, position, false);
785 else
786 aliasedIdentifiers = baseIdentifiers;
789 if( d->m_importedContextsSize() != 0 ) {
790 ///Step 2: Give identifiers that are not marked as explicitly-global to imported contexts(explicitly global ones are treatead in TopDUContext)
791 SearchItem::PtrList nonGlobalIdentifiers;
792 FOREACH_ARRAY( const SearchItem::Ptr& identifier, aliasedIdentifiers )
793 if( !identifier->isExplicitlyGlobal )
794 nonGlobalIdentifiers << identifier;
796 if( !nonGlobalIdentifiers.isEmpty() ) {
797 for(int import = d->m_importedContextsSize()-1; import >= 0; --import ) {
798 DUContext* context = d->m_importedContexts()[import].context();
800 while( !context && import > 0 ) {
801 --import;
804 if(context == this) {
805 kDebug() << "resolved self as import:" << scopeIdentifier(true);
806 continue;
809 if( !context )
810 break;
812 if( position.isValid() && d->m_importedContexts()[import].position.isValid() && position < d->m_importedContexts()[import].position )
813 continue;
815 if( !context->findDeclarationsInternal(nonGlobalIdentifiers, url() == context->url() ? position : context->range().end, dataType, ret, source, flags | InImportedParentContext) )
816 return false;
821 if( foundEnough(ret) )
822 return true;
824 ///Step 3: Continue search in parent-context
825 if (!(flags & DontSearchInParent) && shouldSearchInParent(flags) && m_dynamicData->m_parentContext) {
826 applyUpwardsAliases(aliasedIdentifiers);
827 return m_dynamicData->m_parentContext->findDeclarationsInternal(aliasedIdentifiers, url() == m_dynamicData->m_parentContext->url() ? position : m_dynamicData->m_parentContext->range().end, dataType, ret, source, flags);
829 return true;
832 QList<Declaration*> DUContext::findDeclarations( const QualifiedIdentifier & identifier, const SimpleCursor & position, const AbstractType::Ptr& dataType, const TopDUContext* topContext, SearchFlags flags) const
834 ENSURE_CAN_READ
836 DeclarationList ret;
837 SearchItem::PtrList identifiers;
838 identifiers << SearchItem::Ptr(new SearchItem(identifier));
840 findDeclarationsInternal(identifiers, position.isValid() ? position : range().end, dataType, ret, topContext ? topContext : this->topContext(), flags);
842 return arrayToList(ret);
845 bool DUContext::imports(const DUContext* origin, const SimpleCursor& /*position*/ ) const
847 ENSURE_CAN_READ
849 return origin->m_dynamicData->isThisImportedBy(this);
853 void DUContext::addImportedParentContext( DUContext * context, const SimpleCursor& position, bool anonymous, bool /*temporary*/ )
855 ENSURE_CAN_WRITE
856 DUCHAIN_D_DYNAMIC(DUContext);
858 if(context == this) {
859 kDebug(9007) << "Tried to import self";
860 return;
863 for(unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
864 if(d->m_importedContexts()[a].context() == context) {
865 d->m_importedContextsList()[a].position = position;
866 return;
870 if( !anonymous ) {
871 ENSURE_CAN_WRITE_(context)
872 context->m_dynamicData->addImportedChildContext(this);
875 ///Do not sort the imported contexts by their own line-number, it makes no sense.
876 ///Contexts added first, aka template-contexts, should stay in first place, so they are searched first.
878 d->m_importedContextsList().append(Import(context, position));
880 //DUChain::contextChanged(this, DUChainObserver::Addition, DUChainObserver::ImportedParentContexts, context);
883 void DUContext::removeImportedParentContext( DUContext * context )
885 ENSURE_CAN_WRITE
886 DUCHAIN_D_DYNAMIC(DUContext);
888 for(unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
889 if(d->m_importedContexts()[a].context() == context) {
890 removeFromArray(d->m_importedContextsList(), a);
891 break;
895 if( !context )
896 return;
898 context->m_dynamicData->removeImportedChildContext(this);
900 //DUChain::contextChanged(this, DUChainObserver::Removal, DUChainObserver::ImportedParentContexts, context);
903 QVector<DUContext*> DUContext::importers() const
905 ENSURE_CAN_READ
907 QVector<DUContext*> ret;
908 FOREACH_FUNCTION(IndexedDUContext ctx, d_func()->m_importers)
909 ret << ctx.context();
911 return ret;
914 DUContext * DUContext::findContext( const SimpleCursor& position, DUContext* parent) const
916 ENSURE_CAN_READ
918 if (!parent)
919 parent = const_cast<DUContext*>(this);
921 FOREACH_FUNCTION(LocalIndexedDUContext context, parent->d_func()->m_childContexts)
922 if (context.data(topContext())->range().contains(position)) {
923 DUContext* ret = findContext(position, context.data(topContext()));
924 if (!ret)
925 ret = context.data(topContext());
927 return ret;
930 return 0;
933 bool DUContext::parentContextOf(DUContext* context) const
935 if (this == context)
936 return true;
938 FOREACH_FUNCTION(LocalIndexedDUContext child, d_func()->m_childContexts) {
939 if (child.data(topContext())->parentContextOf(context))
940 return true;
943 return false;
946 QList<Declaration*> DUContext::allLocalDeclarations(const Identifier& identifier) const
948 IndexedIdentifier indexedIdentifier(identifier);
950 ENSURE_CAN_READ
951 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
953 QList<Declaration*> ret;
955 if(m_dynamicData->m_hasLocalDeclarationsHash) {
956 QHash<Identifier, DeclarationPointer>::const_iterator it = m_dynamicData->m_localDeclarationsHash.find(identifier);
957 QHash<Identifier, DeclarationPointer>::const_iterator end = m_dynamicData->m_localDeclarationsHash.end();
959 for( ; it != end && it.key() == identifier; ++it )
960 ret << (*it).data();
961 }else{
962 DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
963 while(it) {
964 Declaration* decl = *it;
965 if(decl->indexedIdentifier() == indexedIdentifier)
966 ret << decl;
967 ++it;
970 return ret;
973 QList< QPair<Declaration*, int> > DUContext::allDeclarations(const SimpleCursor& position, const TopDUContext* topContext, bool searchInParents) const
975 ENSURE_CAN_READ
977 QList< QPair<Declaration*, int> > ret;
979 QHash<const DUContext*, bool> hadContexts;
980 // Iterate back up the chain
981 mergeDeclarationsInternal(ret, position, hadContexts, topContext ? topContext : this->topContext(), searchInParents);
983 return ret;
986 QVector<Declaration*> DUContext::localDeclarations() const
988 ENSURE_CAN_READ
990 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
991 QVector<Declaration*> ret;
992 FOREACH_FUNCTION(LocalIndexedDeclaration decl, d_func()->m_localDeclarations) {
993 ret << decl.data(topContext());
994 Q_ASSERT(ret.back()->context() == this);
995 ret.back()->identifier().isEmpty();
998 return ret;
1001 void DUContext::mergeDeclarationsInternal(QList< QPair<Declaration*, int> >& definitions, const SimpleCursor& position, QHash<const DUContext*, bool>& hadContexts, const TopDUContext* source, bool searchInParents, int currentDepth) const
1003 DUCHAIN_D(DUContext);
1004 if(hadContexts.contains(this))
1005 return;
1006 hadContexts[this] = true;
1008 if( (type() == DUContext::Namespace || type() == DUContext::Global) && currentDepth < 1000 )
1009 currentDepth += 1000;
1012 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
1013 DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
1014 while(it) {
1015 Declaration* decl = *it;
1017 if ( decl && (!position.isValid() || decl->range().start <= position) )
1018 definitions << qMakePair(decl, currentDepth);
1019 ++it;
1023 for(int a = d->m_importedContextsSize()-1; a >= 0; --a) {
1024 const Import* import(&d->m_importedContexts()[a]);
1025 DUContext* context = import->context();
1026 while( !context && a > 0 ) {
1027 --a;
1028 import = &d->m_importedContexts()[a];
1029 context = import->context();
1031 if( !context )
1032 break;
1034 if(context == this) {
1035 kDebug() << "resolved self as import:" << scopeIdentifier(true);
1036 continue;
1040 if( position.isValid() && import->position.isValid() && position < import->position )
1041 continue;
1043 context->mergeDeclarationsInternal(definitions, SimpleCursor::invalid(), hadContexts, source, false, currentDepth+1);
1046 if (searchInParents && parentContext()) ///Only respect the position if the parent-context is not a class(@todo this is language-dependent)
1047 parentContext()->mergeDeclarationsInternal(definitions, parentContext()->type() == DUContext::Class ? parentContext()->range().end : position, hadContexts, source, true, currentDepth+1);
1050 void DUContext::deleteLocalDeclarations()
1052 ENSURE_CAN_WRITE
1053 KDevVarLengthArray<LocalIndexedDeclaration> declarations;
1055 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
1056 FOREACH_FUNCTION(const LocalIndexedDeclaration& decl, d_func()->m_localDeclarations)
1057 declarations.append(decl);
1060 TopDUContext* top = topContext();
1061 //If we are deleting something that is not stored to disk, we need to create + delete the declarations,
1062 //so their destructor unregisters from the persistent symbol table and from TopDUContextDynamicData
1063 FOREACH_ARRAY(LocalIndexedDeclaration decl, declarations)
1064 if(decl.isLoaded(top) || !top->deleting() || !top->isOnDisk())
1065 delete decl.data(top);
1068 void DUContext::deleteChildContextsRecursively()
1070 ENSURE_CAN_WRITE
1071 DUCHAIN_D_DYNAMIC(DUContext);
1072 QVector<LocalIndexedDUContext> children;
1073 FOREACH_FUNCTION(LocalIndexedDUContext ctx, d->m_childContexts)
1074 children << ctx;
1076 TopDUContext* top = topContext();
1077 //If we are deleting a context that is already stored to disk, we don't need to load not yet loaded child-contexts.
1078 //Else we need to, so the declarations are unregistered from symbol-table and from TopDUContextDynamicData in their destructor
1079 foreach(LocalIndexedDUContext ctx, children)
1080 if(ctx.isLoaded(top) || !top->deleting() || !top->isOnDisk())
1081 delete ctx.data(top);
1084 QVector< Declaration * > DUContext::clearLocalDeclarations( )
1086 QVector< Declaration * > ret = localDeclarations();
1087 foreach (Declaration* dec, ret)
1088 dec->setContext(0);
1089 return ret;
1092 QualifiedIdentifier DUContext::scopeIdentifier(bool includeClasses) const
1094 ENSURE_CAN_READ
1096 QualifiedIdentifier ret;
1097 m_dynamicData->scopeIdentifier(includeClasses, ret);
1099 return ret;
1102 bool DUContext::equalScopeIdentifier(const DUContext* rhs) const
1104 ENSURE_CAN_READ
1106 const DUContext* left = this;
1107 const DUContext* right = rhs;
1109 while(left || right) {
1110 if(!left || !right)
1111 return false;
1113 if(!(left->d_func()->m_scopeIdentifier == right->d_func()->m_scopeIdentifier))
1114 return false;
1116 left = left->parentContext();
1117 right = right->parentContext();
1120 return true;
1123 void DUContext::setLocalScopeIdentifier(const QualifiedIdentifier & identifier)
1125 ENSURE_CAN_WRITE
1126 //Q_ASSERT(d_func()->m_childContexts.isEmpty() && d_func()->m_localDeclarations.isEmpty());
1127 bool wasInSymbolTable = inSymbolTable();
1128 setInSymbolTable(false);
1129 d_func_dynamic()->m_scopeIdentifier = identifier;
1130 setInSymbolTable(wasInSymbolTable);
1131 //DUChain::contextChanged(this, DUChainObserver::Change, DUChainObserver::Identifier);
1134 const QualifiedIdentifier DUContext::localScopeIdentifier() const
1136 //ENSURE_CAN_READ Commented out for performance reasons
1138 return d_func()->m_scopeIdentifier;
1141 DUContext::ContextType DUContext::type() const
1143 //ENSURE_CAN_READ This is disabled, because type() is called very often while searching, and it costs us performance
1145 return d_func()->m_contextType;
1148 void DUContext::setType(ContextType type)
1150 ENSURE_CAN_WRITE
1152 bool wasNamespaceInCodeModel = d_func()->m_inSymbolTable && d_func()->m_contextType == DUContext::Namespace && d_func()->m_scopeIdentifier.isValid();
1154 d_func_dynamic()->m_contextType = type;
1156 bool shouldBeNamespaceInCodeModel = d_func()->m_inSymbolTable && d_func()->m_contextType == DUContext::Namespace && d_func()->m_scopeIdentifier.isValid();
1158 if(wasNamespaceInCodeModel && shouldBeNamespaceInCodeModel) {
1159 //We're fine
1160 }else if(!wasNamespaceInCodeModel && shouldBeNamespaceInCodeModel) {
1161 //Add
1162 QualifiedIdentifier id(scopeIdentifier(true));
1163 CodeModel::self().addItem(url(), id, CodeModelItem::Namespace);
1164 }else if(wasNamespaceInCodeModel && !shouldBeNamespaceInCodeModel) {
1165 //Remove
1166 QualifiedIdentifier id(scopeIdentifier(true));
1167 CodeModel::self().removeItem(url(), id);
1170 //DUChain::contextChanged(this, DUChainObserver::Change, DUChainObserver::ContextType);
1173 QList<Declaration*> DUContext::findDeclarations(const Identifier& identifier, const SimpleCursor& position, const TopDUContext* topContext, SearchFlags flags) const
1175 ENSURE_CAN_READ
1177 DeclarationList ret;
1178 SearchItem::PtrList identifiers;
1179 identifiers << SearchItem::Ptr(new SearchItem(QualifiedIdentifier(identifier)));
1180 findDeclarationsInternal(identifiers, position.isValid() ? position : range().end, AbstractType::Ptr(), ret, topContext ? topContext : this->topContext(), flags);
1181 return arrayToList(ret);
1184 void DUContext::deleteUse(int index)
1186 ENSURE_CAN_WRITE
1187 DUCHAIN_D_DYNAMIC(DUContext);
1188 removeFromArray(d->m_usesList(), index);
1190 if(!m_dynamicData->m_rangesForUses.isEmpty()) {
1191 if(m_dynamicData->m_rangesForUses[index]) {
1192 EditorIntegrator editor;
1193 editor.setCurrentUrl(url(), (bool)smartRange());
1194 LockedSmartInterface iface = editor.smart();
1195 if (iface) {
1196 m_dynamicData->m_rangesForUses[index]->removeWatcher(this);
1197 EditorIntegrator::releaseRange(m_dynamicData->m_rangesForUses[index]);
1200 m_dynamicData->m_rangesForUses.remove(index);
1204 void DUContext::deleteUses()
1206 ENSURE_CAN_WRITE
1207 DUCHAIN_D_DYNAMIC(DUContext);
1209 d->m_usesList().clear();
1211 clearUseSmartRanges();
1214 bool DUContext::inDUChain() const {
1215 if( d_func()->m_anonymousInParent )
1216 return false;
1218 TopDUContext* top = topContext();
1219 return top && top->inDuChain();
1222 DUContext* DUContext::specialize(uint /*specialization*/, const TopDUContext* /*topContext*/, int /*upDistance*/) {
1223 return this;
1226 SimpleCursor DUContext::importPosition(const DUContext* target) const
1228 ENSURE_CAN_READ
1229 DUCHAIN_D(DUContext);
1230 for(unsigned int a = 0; a < d->m_importedContextsSize(); ++a)
1231 if(d->m_importedContexts()[a].context() == target)
1232 return d->m_importedContexts()[a].position;
1233 return SimpleCursor::invalid();
1236 QVector<DUContext::Import> DUContext::importedParentContexts() const
1238 ENSURE_CAN_READ
1239 QVector<DUContext::Import> ret;
1240 FOREACH_FUNCTION(const DUContext::Import& import, d_func()->m_importedContexts)
1241 ret << import;
1242 return ret;
1245 QList<DUContext*> DUContext::findContexts(ContextType contextType, const QualifiedIdentifier& identifier, const SimpleCursor& position, SearchFlags flags) const
1247 ENSURE_CAN_READ
1249 QList<DUContext*> ret;
1250 SearchItem::PtrList identifiers;
1251 identifiers << SearchItem::Ptr(new SearchItem(identifier));
1253 findContextsInternal(contextType, identifiers, position.isValid() ? position : range().end, ret, flags);
1254 return ret;
1257 void DUContext::applyAliases(const SearchItem::PtrList& baseIdentifiers, SearchItem::PtrList& identifiers, const SimpleCursor& position, bool canBeNamespace) const {
1259 QList<Declaration*> imports = allLocalDeclarations(globalImportIdentifier);
1261 FOREACH_ARRAY( const SearchItem::Ptr& identifier, baseIdentifiers ) {
1262 bool addUnmodified = true;
1264 if( !identifier->isExplicitlyGlobal ) {
1266 if( !imports.isEmpty() )
1268 //We have namespace-imports.
1269 foreach( Declaration* importDecl, imports )
1271 if( importDecl->range().end > position )
1272 continue;
1273 //Search for the identifier with the import-identifier prepended
1274 Q_ASSERT(dynamic_cast<NamespaceAliasDeclaration*>(importDecl));
1275 NamespaceAliasDeclaration* alias = static_cast<NamespaceAliasDeclaration*>(importDecl);
1276 identifiers.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier(), identifier ) ) ) ;
1280 if( !identifier->isEmpty() && (identifier->hasNext() || canBeNamespace) ) {
1281 QList<Declaration*> aliases = allLocalDeclarations(identifier->identifier);
1282 if(!aliases.isEmpty()) {
1283 //The first part of the identifier has been found as a namespace-alias.
1284 //In c++, we only need the first alias. However, just to be correct, follow them all for now.
1285 foreach( Declaration* aliasDecl, aliases )
1287 if( aliasDecl->range().end > position )
1288 continue;
1289 if(!dynamic_cast<NamespaceAliasDeclaration*>(aliasDecl))
1290 continue;
1292 addUnmodified = false; //The un-modified identifier can be ignored, because it will be replaced with the resolved alias
1293 NamespaceAliasDeclaration* alias = static_cast<NamespaceAliasDeclaration*>(aliasDecl);
1295 //Create an identifier where namespace-alias part is replaced with the alias target
1296 identifiers.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier(), identifier->next ) ) ) ;
1302 if( addUnmodified )
1303 identifiers.append(identifier);
1307 void DUContext::applyUpwardsAliases(SearchItem::PtrList& identifiers) const {
1309 if(type() == Namespace) {
1310 QualifiedIdentifier localId = d_func()->m_scopeIdentifier;
1311 if(localId.isEmpty())
1312 return;
1314 //Make sure we search for the items in all namespaces of the same name, by duplicating each one with the namespace-identifier prepended.
1315 //We do this by prepending items to the current identifiers that equal the local scope identifier.
1316 SearchItem::Ptr newItem( new SearchItem(localId) );
1318 //This will exclude explictly global identifiers
1319 newItem->addToEachNode( identifiers );
1321 if(!newItem->next.isEmpty()) {
1322 //Prepend the full scope before newItem
1323 DUContext* parent = m_dynamicData->m_parentContext.data();
1324 while(parent) {
1325 newItem = SearchItem::Ptr( new SearchItem(parent->d_func()->m_scopeIdentifier, newItem) );
1326 parent = parent->m_dynamicData->m_parentContext.data();
1329 newItem->isExplicitlyGlobal = true;
1330 insertToArray(identifiers, newItem, 0);
1335 void DUContext::findContextsInternal(ContextType contextType, const SearchItem::PtrList& baseIdentifiers, const SimpleCursor& position, QList<DUContext*>& ret, SearchFlags flags) const
1337 DUCHAIN_D(DUContext);
1338 if (contextType == type()) {
1339 FOREACH_ARRAY( const SearchItem::Ptr& identifier, baseIdentifiers )
1340 if (identifier->match(scopeIdentifier(true)) && (!parentContext() || !identifier->isExplicitlyGlobal) )
1341 ret.append(const_cast<DUContext*>(this));
1343 ///@todo This doesn't seem quite correct: Local Contexts aren't found anywhere
1344 ///Step 1: Apply namespace-aliases and -imports
1345 SearchItem::PtrList aliasedIdentifiers;
1346 //Because of namespace-imports and aliases, this identifier may need to be searched as under multiple names
1347 applyAliases(baseIdentifiers, aliasedIdentifiers, position, contextType == Namespace);
1349 if( d->m_importedContextsSize() != 0 ) {
1350 ///Step 2: Give identifiers that are not marked as explicitly-global to imported contexts(explicitly global ones are treatead in TopDUContext)
1351 SearchItem::PtrList nonGlobalIdentifiers;
1352 FOREACH_ARRAY( const SearchItem::Ptr& identifier, aliasedIdentifiers )
1353 if( !identifier->isExplicitlyGlobal )
1354 nonGlobalIdentifiers << identifier;
1356 if( !nonGlobalIdentifiers.isEmpty() ) {
1357 for(int a = d->m_importedContextsSize()-1; a >= 0; --a) {
1359 DUContext* context = d->m_importedContexts()[a].context();
1361 while( !context && a > 0 ) {
1362 --a;
1363 context = d->m_importedContexts()[a].context();
1366 if(context == this) {
1367 kDebug() << "resolved self as import:" << scopeIdentifier(true);
1368 continue;
1371 if( !context )
1372 break;
1374 context->findContextsInternal(contextType, nonGlobalIdentifiers, url() == context->url() ? position : context->range().end, ret, flags | InImportedParentContext);
1379 ///Step 3: Continue search in parent
1380 if ( !(flags & DontSearchInParent) && shouldSearchInParent(flags) && parentContext()) {
1381 applyUpwardsAliases(aliasedIdentifiers);
1382 parentContext()->findContextsInternal(contextType, aliasedIdentifiers, url() == parentContext()->url() ? position : parentContext()->range().end, ret, flags);
1386 bool DUContext::shouldSearchInParent(SearchFlags flags) const
1388 return !(flags & InImportedParentContext);
1391 const Use* DUContext::uses() const
1393 ENSURE_CAN_READ
1395 synchronizeUsesFromSmart();
1396 return d_func()->m_uses();
1399 int DUContext::usesCount() const
1401 return d_func()->m_usesSize();
1404 int DUContext::createUse(int declarationIndex, const SimpleRange& range, KTextEditor::SmartRange* smartRange, int insertBefore)
1406 DUCHAIN_D_DYNAMIC(DUContext);
1407 ENSURE_CAN_WRITE
1409 if(insertBefore == -1) {
1410 //Find position where to insert
1411 unsigned int a = 0;
1412 for(; a < d->m_usesSize() && range.start > d->m_uses()[a].m_range.start; ++a) { ///@todo do binary search
1414 insertBefore = a;
1417 insertToArray(d->m_usesList(), Use(range, declarationIndex), insertBefore);
1418 if(smartRange) {
1419 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.size()) == d->m_usesSize()-1);
1420 m_dynamicData->m_rangesForUses.insert(insertBefore, smartRange);
1421 smartRange->addWatcher(this);
1422 // smartRange->setWantsDirectChanges(true);
1424 d->m_usesList()[insertBefore].m_range = SimpleRange(*smartRange);
1425 }else{
1426 // This can happen eg. when a document is closed during its parsing, and has no ill effects.
1427 //Q_ASSERT(m_dynamicData->m_rangesForUses.isEmpty());
1430 return insertBefore;
1433 KTextEditor::SmartRange* DUContext::useSmartRange(int useIndex)
1435 ENSURE_CAN_READ
1436 if(m_dynamicData->m_rangesForUses.isEmpty())
1437 return 0;
1438 else{
1439 if(useIndex >= 0 && useIndex < m_dynamicData->m_rangesForUses.size())
1440 return m_dynamicData->m_rangesForUses.at(useIndex);
1441 else
1442 return 0;
1447 void DUContext::setUseSmartRange(int useIndex, KTextEditor::SmartRange* range)
1449 ENSURE_CAN_WRITE
1450 if(m_dynamicData->m_rangesForUses.isEmpty())
1451 m_dynamicData->m_rangesForUses.insert(0, d_func()->m_usesSize(), 0);
1453 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.size()) == d_func()->m_usesSize());
1455 if(m_dynamicData->m_rangesForUses[useIndex]) {
1456 EditorIntegrator editor;
1457 editor.setCurrentUrl(url(), (bool)range);
1458 LockedSmartInterface iface = editor.smart();
1459 if (iface) {
1460 m_dynamicData->m_rangesForUses[useIndex]->removeWatcher(this);
1461 EditorIntegrator::releaseRange(m_dynamicData->m_rangesForUses[useIndex]);
1465 m_dynamicData->m_rangesForUses[useIndex] = range;
1466 d_func_dynamic()->m_usesList()[useIndex].m_range = SimpleRange(*range);
1467 range->addWatcher(this);
1468 // range->setWantsDirectChanges(true);
1471 void DUContext::clearUseSmartRanges()
1473 ENSURE_CAN_WRITE
1475 if (!m_dynamicData->m_rangesForUses.isEmpty()) {
1476 EditorIntegrator editor;
1477 editor.setCurrentUrl(url(), (bool)smartRange());
1478 LockedSmartInterface iface = editor.smart();
1479 if (iface) {
1480 foreach (SmartRange* range, m_dynamicData->m_rangesForUses) {
1481 range->removeWatcher(this);
1482 EditorIntegrator::releaseRange(range);
1486 m_dynamicData->m_rangesForUses.clear();
1490 void DUContext::setUseDeclaration(int useNumber, int declarationIndex)
1492 ENSURE_CAN_WRITE
1493 d_func_dynamic()->m_usesList()[useNumber].m_declarationIndex = declarationIndex;
1497 DUContext * DUContext::findContextAt(const SimpleCursor & position) const
1499 ENSURE_CAN_READ
1501 if (!range().contains(position))
1502 return 0;
1504 FOREACH_FUNCTION(LocalIndexedDUContext child, d_func()->m_childContexts)
1505 if (DUContext* specific = child.data(topContext())->findContextAt(position))
1506 return specific;
1508 return const_cast<DUContext*>(this);
1511 DUContext* DUContext::findContextIncluding(const SimpleRange& range) const
1513 ENSURE_CAN_READ
1515 if (!this->range().contains(range))
1516 return 0;
1518 FOREACH_FUNCTION(LocalIndexedDUContext child, d_func()->m_childContexts)
1519 if (DUContext* specific = child.data(topContext())->findContextIncluding(range))
1520 return specific;
1522 return const_cast<DUContext*>(this);
1525 int DUContext::findUseAt(const SimpleCursor & position) const
1527 ENSURE_CAN_READ
1529 synchronizeUsesFromSmart();
1531 if (!range().contains(position))
1532 return -1;
1534 for(unsigned int a = 0; a < d_func()->m_usesSize(); ++a)
1535 if (d_func()->m_uses()[a].m_range.contains(position))
1536 return a;
1538 return -1;
1541 bool DUContext::inSymbolTable() const
1543 return d_func()->m_inSymbolTable;
1546 void DUContext::setInSymbolTable(bool inSymbolTable)
1548 if(parentContext()) {
1549 if(!d_func()->m_inSymbolTable && inSymbolTable) {
1550 QualifiedIdentifier id(scopeIdentifier(true));
1551 PersistentSymbolTable::self().addContext(id, this);
1553 if(d_func()->m_contextType == DUContext::Namespace)
1554 CodeModel::self().addItem(url(), id, CodeModelItem::Namespace);
1555 }else if(d_func()->m_inSymbolTable && !inSymbolTable) {
1556 QualifiedIdentifier id(scopeIdentifier(true));
1557 PersistentSymbolTable::self().removeContext(id, this);
1559 if(d_func()->m_contextType == DUContext::Namespace)
1560 CodeModel::self().removeItem(url(), id);
1564 d_func_dynamic()->m_inSymbolTable = inSymbolTable;
1567 // kate: indent-width 2;
1569 void DUContext::clearImportedParentContexts()
1571 ENSURE_CAN_WRITE
1572 DUCHAIN_D_DYNAMIC(DUContext);
1574 while(d->m_importedContextsSize())
1575 removeImportedParentContext(d->m_importedContexts()[0].context());
1578 void DUContext::cleanIfNotEncountered(const QSet<DUChainBase*>& encountered)
1580 ENSURE_CAN_WRITE
1582 foreach (Declaration* dec, localDeclarations())
1583 if (!encountered.contains(dec))
1584 delete dec;
1586 FOREACH_FUNCTION(LocalIndexedDUContext childContext, d_func()->m_childContexts)
1587 if (!encountered.contains(childContext.data(topContext())))
1588 delete childContext.data(topContext());
1591 TopDUContext* DUContext::topContext() const
1593 return m_dynamicData->m_topContext;
1596 QWidget* DUContext::createNavigationWidget(Declaration* /*decl*/, TopDUContext* /*topContext*/, const QString& /*htmlPrefix*/, const QString& /*htmlSuffix*/) const
1598 return 0;
1601 void DUContext::squeeze()
1603 if(!m_dynamicData->m_rangesForUses.isEmpty())
1604 m_dynamicData->m_rangesForUses.squeeze();
1606 FOREACH_FUNCTION(LocalIndexedDUContext child, d_func()->m_childContexts)
1607 child.data(topContext())->squeeze();
1610 QList<SimpleRange> allUses(DUContext* context, int declarationIndex, bool noEmptyUses)
1612 QList<SimpleRange> ret;
1613 for(int a = 0; a < context->usesCount(); ++a)
1614 if(context->uses()[a].m_declarationIndex == declarationIndex)
1615 if(!noEmptyUses || !context->uses()[a].m_range.isEmpty())
1616 ret << context->uses()[a].m_range;
1618 foreach(DUContext* child, context->childContexts())
1619 ret += allUses(child, declarationIndex, noEmptyUses);
1621 return ret;
1624 QList<KTextEditor::SmartRange*> allSmartUses(DUContext* context, int declarationIndex)
1626 QList<KTextEditor::SmartRange*> ret;
1628 const Use* uses(context->uses());
1630 for(int a = 0; a < context->usesCount(); ++a)
1631 if(uses[a].m_declarationIndex == declarationIndex) {
1632 KTextEditor::SmartRange* range = context->useSmartRange(a);
1633 if(range)
1634 ret << range;
1637 foreach(DUContext* child, context->childContexts())
1638 ret += allSmartUses(child, declarationIndex);
1640 return ret;
1643 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, Ptr nextItem, int start) : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false) {
1644 if(!id.isEmpty()) {
1645 if(id.count() > start)
1646 identifier = id.at(start);
1648 if(id.count() > start+1)
1649 addNext(Ptr( new SearchItem(id, nextItem, start+1) ));
1650 else if(nextItem)
1651 next.append(nextItem);
1652 }else if(nextItem) {
1653 ///If there is no prefix, just copy nextItem
1654 isExplicitlyGlobal = nextItem->isExplicitlyGlobal;
1655 identifier = nextItem->identifier;
1656 next = nextItem->next;
1660 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, const PtrList& nextItems, int start) : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false) {
1661 if(id.count() > start)
1662 identifier = id.at(start);
1664 if(id.count() > start+1)
1665 addNext(Ptr( new SearchItem(id, nextItems, start+1) ));
1666 else
1667 next = nextItems;
1670 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, Identifier id, const PtrList& nextItems) : isExplicitlyGlobal(explicitlyGlobal), identifier(id), next(nextItems) {
1673 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, Identifier id, Ptr nextItem) : isExplicitlyGlobal(explicitlyGlobal), identifier(id) {
1674 next.append(nextItem);
1677 bool DUContext::SearchItem::match(const QualifiedIdentifier& id, int offset) const {
1678 if(id.isEmpty()) {
1679 if(identifier.isEmpty() && next.isEmpty())
1680 return true;
1681 else
1682 return false;
1685 if(id.at(offset) != identifier) //The identifier is different
1686 return false;
1688 if(offset == id.count()-1) {
1689 if(next.isEmpty())
1690 return true; //match
1691 else
1692 return false; //id is too short
1695 for(int a = 0; a < next.size(); ++a)
1696 if(next[a]->match(id, offset+1))
1697 return true;
1699 return false;
1702 bool DUContext::SearchItem::isEmpty() const {
1703 return identifier.isEmpty();
1706 bool DUContext::SearchItem::hasNext() const {
1707 return !next.isEmpty();
1710 QList<QualifiedIdentifier> DUContext::SearchItem::toList(const QualifiedIdentifier& prefix) const {
1711 QList<QualifiedIdentifier> ret;
1713 QualifiedIdentifier id = prefix;
1714 if(id.isEmpty())
1715 id.setExplicitlyGlobal(isExplicitlyGlobal);
1716 if(!identifier.isEmpty())
1717 id.push(identifier);
1719 if(next.isEmpty()) {
1720 ret << id;
1721 } else {
1722 for(int a = 0; a < next.size(); ++a)
1723 ret += next[a]->toList(id);
1725 return ret;
1729 void DUContext::SearchItem::addNext(SearchItem::Ptr other) {
1730 next.append(other);
1733 void DUContext::SearchItem::addToEachNode(SearchItem::Ptr other) {
1734 if(other->isExplicitlyGlobal)
1735 return;
1737 next.append(other);
1738 for(int a = 0; a < next.size()-1; ++a)
1739 next[a]->addToEachNode(other);
1742 void DUContext::SearchItem::addToEachNode(SearchItem::PtrList other) {
1743 int added = 0;
1744 FOREACH_ARRAY(SearchItem::Ptr o, other) {
1745 if(!o->isExplicitlyGlobal) {
1746 next.append(o);
1747 ++added;
1751 for(int a = 0; a < next.size()-added; ++a)
1752 next[a]->addToEachNode(other);
1755 DUContext::Import::Import(DUContext* _context, const SimpleCursor& _position) : position(_position) {
1756 if(_context && _context->owner() && _context->owner()->specialization()) {
1757 m_declaration = _context->owner()->id(true);
1758 }else{
1759 m_context = _context;
1762 DUContext* DUContext::Import::context() const {
1763 if(m_declaration.isValid()) {
1764 Declaration* decl = m_declaration.getDeclaration(0);
1765 if(decl)
1766 return decl->internalContext();
1767 else
1768 return 0;
1769 }else{
1770 return m_context.data();
1776 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on