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"
23 #include <QMutableLinkedListIterator>
26 #include <ktexteditor/document.h>
27 #include <ktexteditor/smartinterface.h>
29 #include "../editor/editorintegrator.h"
31 #include "ducontextdata.h"
32 #include "declaration.h"
34 #include "duchainlock.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
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 }}
58 #define ENSURE_CAN_WRITE_(x)
59 #define ENSURE_CAN_READ_(x)
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
);
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() {
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();
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 {
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
)
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
) )
141 IndexedDUContext::IndexedDUContext(uint topContext
, uint contextIndex
) : m_topContext(topContext
), m_contextIndex(contextIndex
) {
144 IndexedDUContext::IndexedDUContext(DUContext
* ctx
) {
146 m_topContext
= ctx
->topContext()->ownIndex();
147 m_contextIndex
= ctx
->m_dynamicData
->m_indexInTopContext
;
154 IndexedTopDUContext
IndexedDUContext::indexedTopContext() const {
155 return IndexedTopDUContext(m_topContext
);
158 LocalIndexedDUContext::LocalIndexedDUContext(uint contextIndex
) : m_contextIndex(contextIndex
) {
161 LocalIndexedDUContext::LocalIndexedDUContext(DUContext
* ctx
) {
163 m_contextIndex
= ctx
->m_dynamicData
->m_indexInTopContext
;
169 bool LocalIndexedDUContext::isLoaded(TopDUContext
* top
) const {
173 return top
->m_dynamicData
->isContextForIndexLoaded(m_contextIndex
);
176 DUContext
* LocalIndexedDUContext::data(TopDUContext
* top
) const {
180 return top
->m_dynamicData
->getContextForIndex(m_contextIndex
);
183 DUContext
* IndexedDUContext::context() const {
184 ENSURE_CHAIN_READ_LOCKED
188 TopDUContext
* ctx
= DUChain::self()->chainForIndex(m_topContext
);
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
)
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())
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() );
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
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();
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
);
253 range
->removeWatcher(this);
254 int index
= m_dynamicData
->m_rangesForUses
.indexOf(range
);
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
);
272 if(currentDecl
!= decl
)
273 m_localDeclarationsHash
.insert( decl
->identifier(), DeclarationPointer(decl
) );
275 m_localDeclarationsHash
.insert( currentIdentifier
, DeclarationPointer(decl
) );
278 FOREACH_FUNCTION(LocalIndexedDUContext child
, ctx
->d_func()->m_childContexts
) {
279 DUContext
* childCtx
= child
.data(m_topContext
);
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
300 if(m_context
->d_func()->m_localDeclarationsSize() > 15)
303 uint propagatingChildContexts
= 0;
305 FOREACH_FUNCTION(LocalIndexedDUContext child
, m_context
->d_func()->m_childContexts
) {
306 DUContext
* childCtx
= child
.data(m_topContext
);
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
);
362 if(child
== newDeclaration
)
364 if (start
> child
->range().start
) {
365 insertToArray(m_context
->d_func_dynamic()->m_localDeclarationsList(), newDeclaration
, i
+1);
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);
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
)
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
)
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
;
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
) {
457 if( removeOne(m_context
->d_func_dynamic()->m_childContextsList(), LocalIndexedDUContext(context
)) )
463 void DUContextDynamicData::addImportedChildContext( DUContext
* context
)
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
)
477 removeOne(m_context
->d_func_dynamic()->m_importersList(), IndexedDUContext(context
));
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);
496 m_dynamicData
->m_topContext
= parent
->topContext();
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;
509 m_dynamicData
->m_indexInTopContext
= parent
->topContext()->m_dynamicData
->allocateContextIndex(this, parent
->isAnonymous() || anonymous
);
510 Q_ASSERT(m_dynamicData
->m_indexInTopContext
);
513 parent
->m_dynamicData
->addChildContext(this);
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))
530 m_dynamicData
->m_topContext
= parent
->topContext();
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
;
540 m_dynamicData
->m_indexInTopContext
= parent
->topContext()->m_dynamicData
->allocateContextIndex(this, parent
->isAnonymous() || anonymous
);
543 parent
->m_dynamicData
->addChildContext(this);
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());
580 removeOneImport(d
->m_importedContextsList(), 0);
583 deleteChildContextsRecursively();
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);
594 top
->m_dynamicData
->clearContextIndex(this);
597 QVector
< DUContext
* > DUContext::childContexts( ) const
601 QVector
< DUContext
* > ret
;
602 FOREACH_FUNCTION(LocalIndexedDUContext ctx
, d_func()->m_childContexts
)
603 ret
<< ctx
.data(topContext());
607 Declaration
* DUContext::owner() const {
609 return d_func()->m_owner
.declaration();
612 void DUContext::setOwner(Declaration
* owner
) {
614 DUCHAIN_D_DYNAMIC(DUContext
);
615 if( owner
== d
->m_owner
.declaration() )
618 Declaration
* oldOwner
= d
->m_owner
.declaration();
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
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
)
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
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
);
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();
684 kDebug() << "lost aliased declaration";
688 if( declaration
->kind() == Declaration::NamespaceAlias
)
691 if((m_flags
& OnlyFunctions
) && !declaration
->isFunctionDeclaration())
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
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
);
712 Declaration
* declaration
= *it
;
713 if(declaration
->indexedIdentifier() == indexedIdentifier
) {
714 Declaration
* checked
= checker
.check(declaration
);
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();
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
);
733 Declaration
* checked
= checker
.check(decl
);
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();
748 //This should never happen, but let's see
749 kDebug(9505) << "DUContext::findLocalDeclarationsInternal: Invalid declaration in local-declaration-hash";
753 Declaration
* checked
= checker
.check(declaration
);
761 bool DUContext::foundEnough( const DeclarationList
& ret
) const {
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
) )
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);
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 ) {
804 if(context
== this) {
805 kDebug() << "resolved self as import:" << scopeIdentifier(true);
812 if( position
.isValid() && d
->m_importedContexts()[import
].position
.isValid() && position
< d
->m_importedContexts()[import
].position
)
815 if( !context
->findDeclarationsInternal(nonGlobalIdentifiers
, url() == context
->url() ? position
: context
->range().end
, dataType
, ret
, source
, flags
| InImportedParentContext
) )
821 if( foundEnough(ret
) )
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
);
832 QList
<Declaration
*> DUContext::findDeclarations( const QualifiedIdentifier
& identifier
, const SimpleCursor
& position
, const AbstractType::Ptr
& dataType
, const TopDUContext
* topContext
, SearchFlags flags
) const
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
849 return origin
->m_dynamicData
->isThisImportedBy(this);
853 void DUContext::addImportedParentContext( DUContext
* context
, const SimpleCursor
& position
, bool anonymous
, bool /*temporary*/ )
856 DUCHAIN_D_DYNAMIC(DUContext
);
858 if(context
== this) {
859 kDebug(9007) << "Tried to import self";
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
;
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
)
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
);
898 context
->m_dynamicData
->removeImportedChildContext(this);
900 //DUChain::contextChanged(this, DUChainObserver::Removal, DUChainObserver::ImportedParentContexts, context);
903 QVector
<DUContext
*> DUContext::importers() const
907 QVector
<DUContext
*> ret
;
908 FOREACH_FUNCTION(IndexedDUContext ctx
, d_func()->m_importers
)
909 ret
<< ctx
.context();
914 DUContext
* DUContext::findContext( const SimpleCursor
& position
, DUContext
* parent
) const
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()));
925 ret
= context
.data(topContext());
933 bool DUContext::parentContextOf(DUContext
* context
) const
938 FOREACH_FUNCTION(LocalIndexedDUContext child
, d_func()->m_childContexts
) {
939 if (child
.data(topContext())->parentContextOf(context
))
946 QList
<Declaration
*> DUContext::allLocalDeclarations(const Identifier
& identifier
) const
948 IndexedIdentifier
indexedIdentifier(identifier
);
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
)
962 DUContextDynamicData::VisibleDeclarationIterator
it(m_dynamicData
);
964 Declaration
* decl
= *it
;
965 if(decl
->indexedIdentifier() == indexedIdentifier
)
973 QList
< QPair
<Declaration
*, int> > DUContext::allDeclarations(const SimpleCursor
& position
, const TopDUContext
* topContext
, bool searchInParents
) const
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
);
986 QVector
<Declaration
*> DUContext::localDeclarations() const
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();
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))
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
);
1015 Declaration
* decl
= *it
;
1017 if ( decl
&& (!position
.isValid() || decl
->range().start
<= position
) )
1018 definitions
<< qMakePair(decl
, currentDepth
);
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 ) {
1028 import
= &d
->m_importedContexts()[a
];
1029 context
= import
->context();
1034 if(context
== this) {
1035 kDebug() << "resolved self as import:" << scopeIdentifier(true);
1040 if( position
.isValid() && import
->position
.isValid() && position
< import
->position
)
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()
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()
1071 DUCHAIN_D_DYNAMIC(DUContext
);
1072 QVector
<LocalIndexedDUContext
> children
;
1073 FOREACH_FUNCTION(LocalIndexedDUContext ctx
, d
->m_childContexts
)
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
)
1092 QualifiedIdentifier
DUContext::scopeIdentifier(bool includeClasses
) const
1096 QualifiedIdentifier ret
;
1097 m_dynamicData
->scopeIdentifier(includeClasses
, ret
);
1102 bool DUContext::equalScopeIdentifier(const DUContext
* rhs
) const
1106 const DUContext
* left
= this;
1107 const DUContext
* right
= rhs
;
1109 while(left
|| right
) {
1113 if(!(left
->d_func()->m_scopeIdentifier
== right
->d_func()->m_scopeIdentifier
))
1116 left
= left
->parentContext();
1117 right
= right
->parentContext();
1123 void DUContext::setLocalScopeIdentifier(const QualifiedIdentifier
& identifier
)
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
)
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
) {
1160 }else if(!wasNamespaceInCodeModel
&& shouldBeNamespaceInCodeModel
) {
1162 QualifiedIdentifier
id(scopeIdentifier(true));
1163 CodeModel::self().addItem(url(), id
, CodeModelItem::Namespace
);
1164 }else if(wasNamespaceInCodeModel
&& !shouldBeNamespaceInCodeModel
) {
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
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
)
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();
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()
1207 DUCHAIN_D_DYNAMIC(DUContext
);
1209 d
->m_usesList().clear();
1211 clearUseSmartRanges();
1214 bool DUContext::inDUChain() const {
1215 if( d_func()->m_anonymousInParent
)
1218 TopDUContext
* top
= topContext();
1219 return top
&& top
->inDuChain();
1222 DUContext
* DUContext::specialize(uint
/*specialization*/, const TopDUContext
* /*topContext*/, int /*upDistance*/) {
1226 SimpleCursor
DUContext::importPosition(const DUContext
* target
) const
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
1239 QVector
<DUContext::Import
> ret
;
1240 FOREACH_FUNCTION(const DUContext::Import
& import
, d_func()->m_importedContexts
)
1245 QList
<DUContext
*> DUContext::findContexts(ContextType contextType
, const QualifiedIdentifier
& identifier
, const SimpleCursor
& position
, SearchFlags flags
) const
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
);
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
)
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
)
1289 if(!dynamic_cast<NamespaceAliasDeclaration
*>(aliasDecl
))
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
) ) ) ;
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())
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();
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 ) {
1363 context
= d
->m_importedContexts()[a
].context();
1366 if(context
== this) {
1367 kDebug() << "resolved self as import:" << scopeIdentifier(true);
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
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
);
1409 if(insertBefore
== -1) {
1410 //Find position where to insert
1412 for(; a
< d
->m_usesSize() && range
.start
> d
->m_uses()[a
].m_range
.start
; ++a
) { ///@todo do binary search
1417 insertToArray(d
->m_usesList(), Use(range
, declarationIndex
), insertBefore
);
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
);
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
)
1436 if(m_dynamicData
->m_rangesForUses
.isEmpty())
1439 if(useIndex
>= 0 && useIndex
< m_dynamicData
->m_rangesForUses
.size())
1440 return m_dynamicData
->m_rangesForUses
.at(useIndex
);
1447 void DUContext::setUseSmartRange(int useIndex
, KTextEditor::SmartRange
* range
)
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();
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()
1475 if (!m_dynamicData
->m_rangesForUses
.isEmpty()) {
1476 EditorIntegrator editor
;
1477 editor
.setCurrentUrl(url(), (bool)smartRange());
1478 LockedSmartInterface iface
= editor
.smart();
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
)
1493 d_func_dynamic()->m_usesList()[useNumber
].m_declarationIndex
= declarationIndex
;
1497 DUContext
* DUContext::findContextAt(const SimpleCursor
& position
) const
1501 if (!range().contains(position
))
1504 FOREACH_FUNCTION(LocalIndexedDUContext child
, d_func()->m_childContexts
)
1505 if (DUContext
* specific
= child
.data(topContext())->findContextAt(position
))
1508 return const_cast<DUContext
*>(this);
1511 DUContext
* DUContext::findContextIncluding(const SimpleRange
& range
) const
1515 if (!this->range().contains(range
))
1518 FOREACH_FUNCTION(LocalIndexedDUContext child
, d_func()->m_childContexts
)
1519 if (DUContext
* specific
= child
.data(topContext())->findContextIncluding(range
))
1522 return const_cast<DUContext
*>(this);
1525 int DUContext::findUseAt(const SimpleCursor
& position
) const
1529 synchronizeUsesFromSmart();
1531 if (!range().contains(position
))
1534 for(unsigned int a
= 0; a
< d_func()->m_usesSize(); ++a
)
1535 if (d_func()->m_uses()[a
].m_range
.contains(position
))
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()
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
)
1582 foreach (Declaration
* dec
, localDeclarations())
1583 if (!encountered
.contains(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
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
);
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
);
1637 foreach(DUContext
* child
, context
->childContexts())
1638 ret
+= allSmartUses(child
, declarationIndex
);
1643 DUContext::SearchItem::SearchItem(const QualifiedIdentifier
& id
, Ptr nextItem
, int start
) : isExplicitlyGlobal(start
== 0 ? id
.explicitlyGlobal() : false) {
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) ));
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) ));
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 {
1679 if(identifier
.isEmpty() && next
.isEmpty())
1685 if(id
.at(offset
) != identifier
) //The identifier is different
1688 if(offset
== id
.count()-1) {
1690 return true; //match
1692 return false; //id is too short
1695 for(int a
= 0; a
< next
.size(); ++a
)
1696 if(next
[a
]->match(id
, offset
+1))
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
;
1715 id
.setExplicitlyGlobal(isExplicitlyGlobal
);
1716 if(!identifier
.isEmpty())
1717 id
.push(identifier
);
1719 if(next
.isEmpty()) {
1722 for(int a
= 0; a
< next
.size(); ++a
)
1723 ret
+= next
[a
]->toList(id
);
1729 void DUContext::SearchItem::addNext(SearchItem::Ptr other
) {
1733 void DUContext::SearchItem::addToEachNode(SearchItem::Ptr other
) {
1734 if(other
->isExplicitlyGlobal
)
1738 for(int a
= 0; a
< next
.size()-1; ++a
)
1739 next
[a
]->addToEachNode(other
);
1742 void DUContext::SearchItem::addToEachNode(SearchItem::PtrList other
) {
1744 FOREACH_ARRAY(SearchItem::Ptr o
, other
) {
1745 if(!o
->isExplicitlyGlobal
) {
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);
1759 m_context
= _context
;
1762 DUContext
* DUContext::Import::context() const {
1763 if(m_declaration
.isValid()) {
1764 Declaration
* decl
= m_declaration
.getDeclaration(0);
1766 return decl
->internalContext();
1770 return m_context
.data();
1776 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on