00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "ducontext.h"
00021
00022 #include <limits>
00023
00024 #include <QMutableLinkedListIterator>
00025 #include <QSet>
00026
00027 #include <ktexteditor/document.h>
00028 #include <ktexteditor/smartinterface.h>
00029
00030 #include "../editor/editorintegrator.h"
00031
00032 #include "ducontextdata.h"
00033 #include "declaration.h"
00034 #include "duchain.h"
00035 #include "duchainlock.h"
00036 #include "use.h"
00037 #include "identifier.h"
00038 #include "topducontext.h"
00039 #include "persistentsymboltable.h"
00040 #include "aliasdeclaration.h"
00041 #include "namespacealiasdeclaration.h"
00042 #include "abstractfunctiondeclaration.h"
00043 #include "indexedstring.h"
00044 #include "duchainregister.h"
00045 #include "topducontextdynamicdata.h"
00046 #include "arrayhelpers.h"
00047 #include "importers.h"
00048
00050
00051 const uint maxParentDepth = 20;
00052
00053 using namespace KTextEditor;
00054
00055
00056
00057 #ifndef NDEBUG
00058 #define ENSURE_CAN_WRITE_(x) {if(x->inDUChain()) { ENSURE_CHAIN_WRITE_LOCKED }}
00059 #define ENSURE_CAN_READ_(x) {if(x->inDUChain()) { ENSURE_CHAIN_READ_LOCKED }}
00060 #else
00061 #define ENSURE_CAN_WRITE_(x)
00062 #define ENSURE_CAN_READ_(x)
00063 #endif
00064
00065 namespace KDevelop
00066 {
00067 QMutex DUContextDynamicData::m_localDeclarationsMutex(QMutex::Recursive);
00068
00069 DEFINE_LIST_MEMBER_HASH(DUContextData, m_childContexts, LocalIndexedDUContext)
00070 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importers, IndexedDUContext)
00071 DEFINE_LIST_MEMBER_HASH(DUContextData, m_importedContexts, DUContext::Import)
00072 DEFINE_LIST_MEMBER_HASH(DUContextData, m_localDeclarations, LocalIndexedDeclaration)
00073 DEFINE_LIST_MEMBER_HASH(DUContextData, m_uses, Use)
00074
00075 REGISTER_DUCHAIN_ITEM(DUContext);
00076
00077
00078 const Identifier& globalImportIdentifier(*new Identifier("{...import...}"));
00079
00080 void DUContext::rebuildDynamicData(DUContext* parent, uint ownIndex) {
00081
00082 Q_ASSERT(!parent || ownIndex);
00083 m_dynamicData->m_topContext = parent ? parent->topContext() : static_cast<TopDUContext*>(this);
00084 m_dynamicData->m_indexInTopContext = ownIndex;
00085 m_dynamicData->m_parentContext = DUContextPointer(parent);
00086 m_dynamicData->m_context = this;
00087
00088 DUChainBase::rebuildDynamicData(parent, ownIndex);
00089 }
00090
00091 DUContextData::DUContextData()
00092 : m_inSymbolTable(false), m_anonymousInParent(false), m_propagateDeclarations(false)
00093 {
00094 initializeAppendedLists();
00095 }
00096
00097 DUContextData::~DUContextData() {
00098 freeAppendedLists();
00099 }
00100
00101 DUContextData::DUContextData(const DUContextData& rhs) : DUChainBaseData(rhs), m_inSymbolTable(rhs.m_inSymbolTable), m_anonymousInParent(rhs.m_anonymousInParent), m_propagateDeclarations(rhs.m_propagateDeclarations) {
00102 initializeAppendedLists();
00103 copyListsFrom(rhs);
00104 m_scopeIdentifier = rhs.m_scopeIdentifier;
00105 m_contextType = rhs.m_contextType;
00106 m_owner = rhs.m_owner;
00107 }
00108
00109 DUContextDynamicData::DUContextDynamicData(DUContext* d)
00110 : m_topContext(0), m_hasLocalDeclarationsHash(false), m_indexInTopContext(0), m_context(d), m_rangesChanged(true)
00111 {
00112 }
00113
00114 void DUContextDynamicData::scopeIdentifier(bool includeClasses, QualifiedIdentifier& target) const {
00115 if (m_parentContext)
00116 m_parentContext->m_dynamicData->scopeIdentifier(includeClasses, target);
00117
00118 if (includeClasses || m_context->d_func()->m_contextType != DUContext::Class)
00119 target += m_context->d_func()->m_scopeIdentifier;
00120 }
00121
00122 bool DUContextDynamicData::importsSafeButSlow(const DUContext* context, const TopDUContext* source, ImportsHash& checked) const {
00123 if( this == context->m_dynamicData )
00124 return true;
00125
00126 if(checked.find(this) != checked.end())
00127 return false;
00128 checked.insert(std::make_pair(this, true));
00129
00130 FOREACH_FUNCTION( const DUContext::Import& ctx, m_context->d_func()->m_importedContexts ) {
00131 DUContext* import = ctx.context(source);
00132 if(import == context || (import && import->m_dynamicData->importsSafeButSlow(context, source, checked)))
00133 return true;
00134 }
00135
00136 return false;
00137 }
00138
00139 bool DUContextDynamicData::imports(const DUContext* context, const TopDUContext* source, int maxDepth) const {
00140 if( this == context->m_dynamicData )
00141 return true;
00142
00143 if(maxDepth == 0) {
00144 ImportsHash checked(500);
00145 checked.set_empty_key(0);
00146 return importsSafeButSlow(context, source, checked);
00147 }
00148
00149 FOREACH_FUNCTION( const DUContext::Import& ctx, m_context->d_func()->m_importedContexts ) {
00150 DUContext* import = ctx.context(source);
00151 if(import == context || (import && import->m_dynamicData->imports(context, source, maxDepth-1)))
00152 return true;
00153 }
00154
00155 return false;
00156 }
00157
00158 IndexedDUContext::IndexedDUContext(uint topContext, uint contextIndex) : m_topContext(topContext), m_contextIndex(contextIndex) {
00159 }
00160
00161 IndexedDUContext::IndexedDUContext(DUContext* ctx) {
00162 if(ctx) {
00163 m_topContext = ctx->topContext()->ownIndex();
00164 m_contextIndex = ctx->m_dynamicData->m_indexInTopContext;
00165 }else{
00166 m_topContext = 0;
00167 m_contextIndex = 0;
00168 }
00169 }
00170
00171 IndexedTopDUContext IndexedDUContext::indexedTopContext() const {
00172 if(isDummy())
00173 return IndexedTopDUContext();
00174 return IndexedTopDUContext(m_topContext);
00175 }
00176
00177 LocalIndexedDUContext::LocalIndexedDUContext(uint contextIndex) : m_contextIndex(contextIndex) {
00178 }
00179
00180 LocalIndexedDUContext::LocalIndexedDUContext(DUContext* ctx) {
00181 if(ctx) {
00182 m_contextIndex = ctx->m_dynamicData->m_indexInTopContext;
00183 }else{
00184 m_contextIndex = 0;
00185 }
00186 }
00187
00188 bool LocalIndexedDUContext::isLoaded(TopDUContext* top) const {
00189 if(!m_contextIndex)
00190 return false;
00191 else
00192 return top->m_dynamicData->isContextForIndexLoaded(m_contextIndex);
00193 }
00194
00195 DUContext* LocalIndexedDUContext::data(TopDUContext* top) const {
00196 if(!m_contextIndex)
00197 return 0;
00198 else
00199 return top->m_dynamicData->getContextForIndex(m_contextIndex);
00200 }
00201
00202 DUContext* IndexedDUContext::context() const {
00203 if(isDummy())
00204 return 0;
00205 // ENSURE_CHAIN_READ_LOCKED
00206 if(!m_topContext)
00207 return 0;
00208
00209 TopDUContext* ctx = DUChain::self()->chainForIndex(m_topContext);
00210 if(!ctx)
00211 return 0;
00212
00213 if(!m_contextIndex)
00214 return ctx;
00215
00216 return ctx->m_dynamicData->getContextForIndex(m_contextIndex);
00217 }
00218
00219 void DUContext::synchronizeUsesFromSmart() const
00220 {
00221 DUCHAIN_D(DUContext);
00222
00223 if(m_dynamicData->m_rangesForUses.isEmpty() || !m_dynamicData->m_rangesChanged)
00224 return;
00225
00226 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.count()) == d->m_usesSize());
00227
00228 for(unsigned int a = 0; a < d->m_usesSize(); a++)
00229 if(m_dynamicData->m_rangesForUses[a]) ///@todo somehow signalize the change
00230 const_cast<Use&>(d->m_uses()[a]).m_range = SimpleRange(*m_dynamicData->m_rangesForUses[a]);
00231
00232 m_dynamicData->m_rangesChanged = false;
00233 }
00234
00235 void DUContext::synchronizeUsesToSmart() const
00236 {
00237 DUCHAIN_D(DUContext);
00238 if(m_dynamicData->m_rangesForUses.isEmpty())
00239 return;
00240 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.count()) == d->m_usesSize());
00241
00242 // TODO: file close race? from here
00243 KTextEditor::SmartInterface *iface = qobject_cast<KTextEditor::SmartInterface*>( smartRange()->document() );
00244 Q_ASSERT(iface);
00245
00246 // TODO: file close race to here
00247 QMutexLocker l(iface->smartMutex());
00248
00249 for(unsigned int a = 0; a < d->m_usesSize(); a++) {
00250 if(a % 10 == 0) { //Unlock the smart-lock time by time, to increase responsiveness
00251 l.unlock();
00252 l.relock();
00253 }
00254 if(m_dynamicData->m_rangesForUses[a]) {
00255 m_dynamicData->m_rangesForUses[a]->start() = d->m_uses()[a].m_range.start.textCursor();
00256 m_dynamicData->m_rangesForUses[a]->end() = d->m_uses()[a].m_range.end.textCursor();
00257 }else{
00258 kDebug() << "bad smart-range";
00259 }
00260 }
00261 }
00262
00263 void DUContext::rangePositionChanged(KTextEditor::SmartRange* range)
00264 {
00265 if(range != smartRange())
00266 m_dynamicData->m_rangesChanged = true;
00267 }
00268
00269 void DUContext::rangeDeleted(KTextEditor::SmartRange* range)
00270 {
00271 if(range == smartRange()) {
00272 DocumentRangeObject::rangeDeleted(range);
00273 } else {
00274 range->removeWatcher(this);
00275 int index = m_dynamicData->m_rangesForUses.indexOf(range);
00276 if(index != -1) {
00277 d_func_dynamic()->m_usesList()[index].m_range = SimpleRange(*range);
00278 m_dynamicData->m_rangesForUses[index] = 0;
00279 }
00280
00281 if(m_dynamicData->m_rangesForUses.count(0) == m_dynamicData->m_rangesForUses.size())
00282 m_dynamicData->m_rangesForUses.clear();
00283 }
00284 }
00285
00286 void DUContextDynamicData::enableLocalDeclarationsHash(DUContext* ctx, const Identifier& currentIdentifier, Declaration* currentDecl)
00287 {
00288 m_hasLocalDeclarationsHash = true;
00289
00290 FOREACH_FUNCTION(LocalIndexedDeclaration indexedDecl, ctx->d_func()->m_localDeclarations) {
00291 Declaration* decl = indexedDecl.data(m_topContext);
00292 Q_ASSERT(decl);
00293 if(currentDecl != decl)
00294 m_localDeclarationsHash.insert( decl->identifier(), DeclarationPointer(decl) );
00295 else
00296 m_localDeclarationsHash.insert( currentIdentifier, DeclarationPointer(decl) );
00297 }
00298
00299 FOREACH_FUNCTION(LocalIndexedDUContext child, ctx->d_func()->m_childContexts) {
00300 DUContext* childCtx = child.data(m_topContext);
00301 Q_ASSERT(childCtx);
00302 if(childCtx->d_func()->m_propagateDeclarations)
00303 enableLocalDeclarationsHash(childCtx, currentIdentifier, currentDecl);
00304 }
00305 }
00306
00307 void DUContextDynamicData::disableLocalDeclarationsHash()
00308 {
00309 m_hasLocalDeclarationsHash = false;
00310 m_localDeclarationsHash.clear();
00311 }
00312
00313 bool DUContextDynamicData::needsLocalDeclarationsHash()
00314 {
00316 //For now disable the hash, until we make sure that all declarations needed for the hash are loaded first
00317 //including those in propagating sub-contexts.
00318 //Then, also make sure that we create the declaration hash after loading if needed
00319 return false;
00320
00321 if(m_context->d_func()->m_localDeclarationsSize() > 15)
00322 return true;
00323
00324 uint propagatingChildContexts = 0;
00325
00326 FOREACH_FUNCTION(LocalIndexedDUContext child, m_context->d_func()->m_childContexts) {
00327 DUContext* childCtx = child.data(m_topContext);
00328 Q_ASSERT(childCtx);
00329 if(childCtx->d_func()->m_propagateDeclarations)
00330 ++propagatingChildContexts;
00331 }
00332
00333 return propagatingChildContexts > 4;
00334 }
00335
00336 void DUContextDynamicData::addDeclarationToHash(const Identifier& identifier, Declaration* declaration)
00337 {
00338 if(m_hasLocalDeclarationsHash)
00339 m_localDeclarationsHash.insert( identifier, DeclarationPointer(declaration) );
00340
00341 if( m_context->d_func()->m_propagateDeclarations && m_parentContext )
00342 m_parentContext->m_dynamicData->addDeclarationToHash(identifier, declaration);
00343
00344 if(!m_hasLocalDeclarationsHash && needsLocalDeclarationsHash())
00345 enableLocalDeclarationsHash(m_context, identifier, declaration);
00346 }
00347
00348 void DUContextDynamicData::removeDeclarationFromHash(const Identifier& identifier, Declaration* declaration)
00349 {
00350 if(m_hasLocalDeclarationsHash)
00351 m_localDeclarationsHash.remove( identifier, DeclarationPointer(declaration) );
00352
00353 if( m_context->d_func()->m_propagateDeclarations && m_parentContext )
00354 m_parentContext->m_dynamicData->removeDeclarationFromHash(identifier, declaration);
00355
00356 if(m_hasLocalDeclarationsHash && !needsLocalDeclarationsHash())
00357 disableLocalDeclarationsHash();
00358 }
00359
00360 void DUContextDynamicData::addDeclaration( Declaration * newDeclaration )
00361 {
00362 // The definition may not have its identifier set when it's assigned... allow dupes here, TODO catch the error elsewhere
00363 {
00364 QMutexLocker lock(&m_localDeclarationsMutex);
00365
00366 // m_localDeclarations.append(newDeclaration);
00367
00368 if(m_indexInTopContext < (0xffffffff/2)) {
00369 //If this context is not temporary, added declarations shouldn't be either
00370 Q_ASSERT(newDeclaration->ownIndex() < (0xffffffff/2));
00371 }
00372 if(m_indexInTopContext > (0xffffffff/2)) {
00373 //If this context is temporary, added declarations should be as well
00374 Q_ASSERT(newDeclaration->ownIndex() > (0xffffffff/2));
00375 }
00376
00377 SimpleCursor start = newDeclaration->range().start;
00379 bool inserted = false;
00380 for (int i = m_context->d_func_dynamic()->m_localDeclarationsSize()-1; i >= 0; --i) {
00381 Declaration* child = m_context->d_func_dynamic()->m_localDeclarations()[i].data(m_topContext);
00382 if(!child) {
00383 kWarning() << "child declaration number" << i << "of" << m_context->d_func_dynamic()->m_localDeclarationsSize() << "is invalid";
00384 continue;
00385 }
00386 if(child == newDeclaration)
00387 return;
00388 if (start > child->range().start) {
00389 insertToArray(m_context->d_func_dynamic()->m_localDeclarationsList(), newDeclaration, i+1);
00390 if(!m_context->d_func()->m_localDeclarations()[i+1].data(m_topContext))
00391 kFatal() << "Inserted a not addressable declaration";
00392
00393 inserted = true;
00394 break;
00395 }
00396 }
00397 if( !inserted ) //We haven't found any child that is before this one, so prepend it
00398 insertToArray(m_context->d_func_dynamic()->m_localDeclarationsList(), newDeclaration, 0);
00399
00400 addDeclarationToHash(newDeclaration->identifier(), newDeclaration);
00401 }
00402
00403 //DUChain::contextChanged(m_context, DUChainObserver::Addition, DUChainObserver::LocalDeclarations, newDeclaration);
00404 }
00405
00406 bool DUContextDynamicData::removeDeclaration(Declaration* declaration)
00407 {
00408 QMutexLocker lock(&m_localDeclarationsMutex);
00409
00410 if(!m_topContext->deleting()) //We can save a lot of time by just not caring about the hash while deleting
00411 removeDeclarationFromHash(declaration->identifier(), declaration);
00412
00413 if( removeOne(m_context->d_func_dynamic()->m_localDeclarationsList(), LocalIndexedDeclaration(declaration)) ) {
00414 //DUChain::contextChanged(m_context, DUChainObserver::Removal, DUChainObserver::LocalDeclarations, declaration);
00415 return true;
00416 }else {
00417 return false;
00418 }
00419 }
00420
00421 void DUContext::changingIdentifier( Declaration* decl, const Identifier& from, const Identifier& to ) {
00422 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
00423 m_dynamicData->removeDeclarationFromHash(from, decl);
00424 m_dynamicData->addDeclarationToHash(to, decl);
00425 }
00426
00427 void DUContextDynamicData::addChildContext( DUContext * context )
00428 {
00429 // Internal, don't need to assert a lock
00430 Q_ASSERT(!context->m_dynamicData->m_parentContext || context->m_dynamicData->m_parentContext.data()->m_dynamicData == this );
00431
00432 LocalIndexedDUContext indexed(context->m_dynamicData->m_indexInTopContext);
00433
00434 if(m_indexInTopContext < (0xffffffff/2)) {
00435 //If this context is not temporary, added declarations shouldn't be either
00436 Q_ASSERT(indexed.localIndex() < (0xffffffff/2));
00437 }
00438 if(m_indexInTopContext > (0xffffffff/2)) {
00439 //If this context is temporary, added declarations should be as well
00440 Q_ASSERT(indexed.localIndex() > (0xffffffff/2));
00441 }
00442
00443 bool inserted = false;
00444
00445 int childCount = m_context->d_func()->m_childContextsSize();
00446
00447 for (int i = childCount-1; i >= 0; --i) {///@todo Do binary search to find the position
00448 DUContext* child = m_context->d_func()->m_childContexts()[i].data(m_topContext);
00449 if (context == child)
00450 return;
00451 if (context->range().start >= child->range().start) {
00452 insertToArray(m_context->d_func_dynamic()->m_childContextsList(), indexed, i+1);
00453 context->m_dynamicData->m_parentContext = m_context;
00454 inserted = true;
00455 break;
00456 }
00457 }
00458
00459 if( !inserted ) {
00460 m_context->d_func_dynamic()->m_childContextsList().insert(indexed, 0);
00461 context->m_dynamicData->m_parentContext = m_context;
00462 }
00463
00464 if(context->d_func()->m_propagateDeclarations) {
00465 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
00466 disableLocalDeclarationsHash();
00467 if(needsLocalDeclarationsHash())
00468 enableLocalDeclarationsHash(m_context);
00469 }
00470
00471 //DUChain::contextChanged(m_context, DUChainObserver::Addition, DUChainObserver::ChildContexts, context);
00472 }
00473
00474 bool DUContextDynamicData::removeChildContext( DUContext* context ) {
00475 // ENSURE_CAN_WRITE
00476
00477 if( removeOne(m_context->d_func_dynamic()->m_childContextsList(), LocalIndexedDUContext(context)) )
00478 return true;
00479 else
00480 return false;
00481 }
00482
00483 void DUContextDynamicData::addImportedChildContext( DUContext * context )
00484 {
00485 // ENSURE_CAN_WRITE
00486 DUContext::Import import(m_context, context);
00487
00488 if(import.isDirect()) {
00489 //Direct importers are registered directly within the data
00490 if(arrayContains(m_context->d_func_dynamic()->m_importersList(), IndexedDUContext(context))) {
00491 kDebug(9505) << m_context->scopeIdentifier(true).toString() << "importer added multiple times:" << context->scopeIdentifier(true).toString();
00492 return;
00493 }
00494
00495 m_context->d_func_dynamic()->m_importersList().append(context);
00496 }else{
00497 //Indirect importers are registered separately
00498 Importers::self().addImporter(import.indirectDeclarationId(), IndexedDUContext(context));
00499 }
00500
00501 //DUChain::contextChanged(m_context, DUChainObserver::Addition, DUChainObserver::ImportedChildContexts, context);
00502 }
00503
00504 //Can also be called with a context that is not in the list
00505 void DUContextDynamicData::removeImportedChildContext( DUContext * context )
00506 {
00507 // ENSURE_CAN_WRITE
00508 DUContext::Import import(m_context, context);
00509
00510 if(import.isDirect()) {
00511 removeOne(m_context->d_func_dynamic()->m_importersList(), IndexedDUContext(context));
00512 }else{
00513 //Indirect importers are registered separately
00514 Importers::self().removeImporter(import.indirectDeclarationId(), IndexedDUContext(context));
00515 }
00516 }
00517
00518 int DUContext::depth() const
00519 {
00520 { if (!parentContext()) return 0; return parentContext()->depth() + 1; }
00521 }
00522
00523 DUContext::DUContext(DUContextData& data) : DUChainBase(data), m_dynamicData(new DUContextDynamicData(this)) {
00524 }
00525
00526
00527 DUContext::DUContext(const SimpleRange& range, DUContext* parent, bool anonymous)
00528 : DUChainBase(*new DUContextData(), range), m_dynamicData(new DUContextDynamicData(this))
00529 {
00530 d_func_dynamic()->setClassId(this);
00531 if(parent)
00532 m_dynamicData->m_topContext = parent->topContext();
00533 else
00534 m_dynamicData->m_topContext = static_cast<TopDUContext*>(this);
00535
00536 d_func_dynamic()->setClassId(this);
00537 DUCHAIN_D_DYNAMIC(DUContext);
00538 d->m_contextType = Other;
00539 m_dynamicData->m_parentContext = 0;
00540
00541 d->m_anonymousInParent = anonymous;
00542 d->m_inSymbolTable = false;
00543
00544 if (parent) {
00545 m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this, parent->isAnonymous() || anonymous);
00546 Q_ASSERT(m_dynamicData->m_indexInTopContext);
00547
00548 if( !anonymous )
00549 parent->m_dynamicData->addChildContext(this);
00550 else
00551 m_dynamicData->m_parentContext = parent;
00552 }
00553
00554 if(parent && !anonymous && parent->inSymbolTable())
00555 setInSymbolTable(true);
00556 }
00557
00558 bool DUContext::isAnonymous() const {
00559 return d_func()->m_anonymousInParent || (m_dynamicData->m_parentContext && m_dynamicData->m_parentContext->isAnonymous());
00560 }
00561
00562 DUContext::DUContext( DUContextData& dd, const SimpleRange& range, DUContext * parent, bool anonymous )
00563 : DUChainBase(dd, range), m_dynamicData(new DUContextDynamicData(this))
00564 {
00565 if(parent)
00566 m_dynamicData->m_topContext = parent->topContext();
00567 else
00568 m_dynamicData->m_topContext = static_cast<TopDUContext*>(this);
00569
00570 DUCHAIN_D_DYNAMIC(DUContext);
00571 d->m_contextType = Other;
00572 m_dynamicData->m_parentContext = 0;
00573 d->m_inSymbolTable = false;
00574 d->m_anonymousInParent = anonymous;
00575 if (parent) {
00576 m_dynamicData->m_indexInTopContext = parent->topContext()->m_dynamicData->allocateContextIndex(this, parent->isAnonymous() || anonymous);
00577
00578 if( !anonymous )
00579 parent->m_dynamicData->addChildContext(this);
00580 else
00581 m_dynamicData->m_parentContext = parent;
00582 }
00583 }
00584
00585 DUContext::DUContext(DUContext& useDataFrom)
00586 : DUChainBase(useDataFrom), m_dynamicData(useDataFrom.m_dynamicData)
00587 {
00588 }
00589
00590 DUContext::~DUContext( )
00591 {
00592 TopDUContext* top = topContext();
00593
00594 if(!top->deleting() || !top->isOnDisk()) {
00595 DUCHAIN_D_DYNAMIC(DUContext);
00596 QualifiedIdentifier id(scopeIdentifier(true));
00597 if(d->m_inSymbolTable && parentContext()) {
00598 PersistentSymbolTable::self().removeContext(id, this);
00599 }
00600
00601 if(d->m_owner.declaration())
00602 d->m_owner.declaration()->setInternalContext(0);
00603
00604 while( d->m_importersSize() != 0 ) {
00605 if(d->m_importers()[0].data())
00606 d->m_importers()[0].data()->removeImportedParentContext(this);
00607 else {
00608 kDebug() << "importer disappeared";
00609 d->m_importersList().removeOne(d->m_importers()[0]);
00610 }
00611 }
00612
00613 clearImportedParentContexts();
00614 }
00615
00616 deleteChildContextsRecursively();
00617
00618 if(!topContext()->deleting() || !topContext()->isOnDisk())
00619 deleteUses();
00620 else
00621 clearUseSmartRanges();
00622
00623 deleteLocalDeclarations();
00624
00625 //If the top-context is being delete, we don't need to spend time rebuilding the inner structure.
00626 //That's expensive, especially when the data is not dynamic.
00627 if(!top->deleting() || !top->isOnDisk()) {
00628 if (m_dynamicData->m_parentContext)
00629 m_dynamicData->m_parentContext->m_dynamicData->removeChildContext(this);
00630 //DUChain::contextChanged(this, DUChainObserver::Deletion, DUChainObserver::NotApplicable);
00631 }
00632
00633 top->m_dynamicData->clearContextIndex(this);
00634
00635 Q_ASSERT(d_func()->isDynamic() == (!top->deleting() || !top->isOnDisk() || top->m_dynamicData->isTemporaryContextIndex(m_dynamicData->m_indexInTopContext)));
00636 delete m_dynamicData;
00637 }
00638
00639 QVector< DUContext * > DUContext::childContexts( ) const
00640 {
00641 ENSURE_CAN_READ
00642
00643 QVector< DUContext * > ret;
00644 FOREACH_FUNCTION(LocalIndexedDUContext ctx, d_func()->m_childContexts)
00645 ret << ctx.data(topContext());
00646 return ret;
00647 }
00648
00649 Declaration* DUContext::owner() const {
00650 ENSURE_CAN_READ
00651 return d_func()->m_owner.declaration();
00652 }
00653
00654 void DUContext::setOwner(Declaration* owner) {
00655 ENSURE_CAN_WRITE
00656 DUCHAIN_D_DYNAMIC(DUContext);
00657 if( owner == d->m_owner.declaration() )
00658 return;
00659
00660 Declaration* oldOwner = d->m_owner.declaration();
00661
00662 d->m_owner = owner;
00663
00664 //Q_ASSERT(!oldOwner || oldOwner->internalContext() == this);
00665 if( oldOwner && oldOwner->internalContext() == this )
00666 oldOwner->setInternalContext(0);
00667
00668
00669 //The context set as internal context should always be the last opened context
00670 if( owner )
00671 owner->setInternalContext(this);
00672 }
00673
00674 DUContext* DUContext::parentContext( ) const
00675 {
00676 //ENSURE_CAN_READ Commented out for performance reasons
00677
00678 return m_dynamicData->m_parentContext.data();
00679 }
00680
00681 void DUContext::setPropagateDeclarations(bool propagate)
00682 {
00683 ENSURE_CAN_WRITE
00684 DUCHAIN_D_DYNAMIC(DUContext);
00685
00686 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
00687
00688 if(propagate == d->m_propagateDeclarations)
00689 return;
00690
00691 m_dynamicData->m_parentContext->m_dynamicData->disableLocalDeclarationsHash();
00692
00693 d->m_propagateDeclarations = propagate;
00694
00695 if(m_dynamicData->m_parentContext->m_dynamicData->needsLocalDeclarationsHash())
00696 m_dynamicData->m_parentContext->m_dynamicData->enableLocalDeclarationsHash(m_dynamicData->m_parentContext.data());
00697 }
00698
00699 bool DUContext::isPropagateDeclarations() const
00700 {
00701 return d_func()->m_propagateDeclarations;
00702 }
00703
00704 QList<Declaration*> DUContext::findLocalDeclarations( const Identifier& identifier, const SimpleCursor & position, const TopDUContext* topContext, const AbstractType::Ptr& dataType, SearchFlags flags ) const
00705 {
00706 ENSURE_CAN_READ
00707
00708 DeclarationList ret;
00709 findLocalDeclarationsInternal(identifier, position.isValid() ? position : range().end, dataType, ret, topContext ? topContext : this->topContext(), flags);
00710 return arrayToList(ret);
00711 }
00712
00713 bool contextIsChildOrEqual(const DUContext* childContext, const DUContext* context) {
00714 if(childContext == context)
00715 return true;
00716
00717 if(childContext->parentContext())
00718 return contextIsChildOrEqual(childContext->parentContext(), context);
00719 else
00720 return false;
00721 }
00722
00723 void DUContext::findLocalDeclarationsInternal( const Identifier& identifier, const SimpleCursor & position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* /*source*/, SearchFlags flags ) const
00724 {
00725 IndexedIdentifier indexedIdentifier(identifier);
00726 {
00727 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
00728
00729 struct Checker {
00730 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) {
00731 }
00732
00733 Declaration* check(Declaration* declaration) {
00734 if( declaration->kind() == Declaration::Alias ) {
00735 //Apply alias declarations
00736 AliasDeclaration* alias = static_cast<AliasDeclaration*>(declaration);
00737 if(alias->aliasedDeclaration().isValid()) {
00738 declaration = alias->aliasedDeclaration().declaration();
00739 } else {
00740 #ifndef Q_CC_MSVC
00741 kDebug() << "lost aliased declaration";
00742 #endif
00743 }
00744 }
00745
00746 if( declaration->kind() == Declaration::NamespaceAlias && !(m_flags & NoFiltering) )
00747 return 0;
00748
00749 if((m_flags & OnlyFunctions) && !declaration->isFunctionDeclaration())
00750 return 0;
00751
00752 if (!m_dataType || m_dataType->indexed() == declaration->abstractType()->indexed())
00753 if (m_ownType == Class || m_ownType == Template || m_position > declaration->range().start || !m_position.isValid()) ///@todo This is C++-specific
00754 return declaration;
00755 return 0;
00756 }
00757
00758 SearchFlags m_flags;
00759 const AbstractType::Ptr& m_dataType;
00760 const SimpleCursor& m_position;
00761 DUContext::ContextType m_ownType;
00762 };
00763
00764 Checker checker(flags, dataType, position, type());
00765
00766 if(m_dynamicData->m_hasLocalDeclarationsHash) {
00767 //Use a special hash that contains all declarations visible in this context
00768 QHash<Identifier, DeclarationPointer>::const_iterator it = m_dynamicData->m_localDeclarationsHash.constFind(identifier);
00769 QHash<Identifier, DeclarationPointer>::const_iterator end = m_dynamicData->m_localDeclarationsHash.constEnd();
00770
00771 for( ; it != end && it.key() == identifier; ++it ) {
00772 Declaration* declaration = (*it).data();
00773
00774 if( !declaration ) {
00775 //This should never happen, but let's see
00776 kDebug(9505) << "DUContext::findLocalDeclarationsInternal: Invalid declaration in local-declaration-hash";
00777 continue;
00778 }
00779
00780 Declaration* checked = checker.check(declaration);
00781 if(checked)
00782 ret.append(checked);
00783 }
00784 }else if(d_func()->m_inSymbolTable && !this->localScopeIdentifier().isEmpty() && !identifier.isEmpty()) {
00785 //This context is in the symbol table, use the symbol-table to speed up the search
00786 QualifiedIdentifier id(scopeIdentifier(true) + identifier);
00787
00788 TopDUContext* top = topContext();
00789
00790 uint count;
00791 const IndexedDeclaration* declarations;
00792 PersistentSymbolTable::self().declarations(id, count, declarations);
00793 for(uint a = 0; a < count; ++a) {
00795 if(declarations[a].topContextIndex() == top->ownIndex()) {
00796 Declaration* decl = LocalIndexedDeclaration(declarations[a].localIndex()).data(top);
00797 if(decl && contextIsChildOrEqual(decl->context(), this)) {
00798 Declaration* checked = checker.check(decl);
00799 if(checked)
00800 ret.append(checked);
00801 }
00802 }
00803 }
00804 }else {
00805 //Iterate through all declarations
00806 DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
00807 while(it) {
00808 Declaration* declaration = *it;
00809 if(declaration->indexedIdentifier() == indexedIdentifier) {
00810 Declaration* checked = checker.check(declaration);
00811 if(checked)
00812 ret.append(checked);
00813 }
00814 ++it;
00815 }
00816 }
00817 }
00818 }
00819
00820 bool DUContext::foundEnough( const DeclarationList& ret, SearchFlags flags ) const {
00821 if( !ret.isEmpty() && !(flags & DUContext::NoFiltering))
00822 return true;
00823 else
00824 return false;
00825 }
00826
00827 bool DUContext::findDeclarationsInternal( const SearchItem::PtrList & baseIdentifiers, const SimpleCursor & position, const AbstractType::Ptr& dataType, DeclarationList& ret, const TopDUContext* source, SearchFlags flags, uint depth ) const
00828 {
00829 if(depth > maxParentDepth) {
00830 kDebug() << "maximum depth reached in" << scopeIdentifier(true);
00831 return false;
00832 }
00833
00834 DUCHAIN_D(DUContext);
00835 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.
00836 for(int a = 0; a < baseIdentifiers.size(); ++a)
00837 if(!baseIdentifiers[a]->isExplicitlyGlobal && baseIdentifiers[a]->next.isEmpty()) //It makes no sense searching locally for qualified identifiers
00838 findLocalDeclarationsInternal(baseIdentifiers[a]->identifier, position, dataType, ret, source, flags);
00839
00840 if( foundEnough(ret, flags) )
00841 return true;
00842 }
00843
00845 SearchItem::PtrList aliasedIdentifiers;
00846 //Because of namespace-imports and aliases, this identifier may need to be searched under multiple names
00847 applyAliases(baseIdentifiers, aliasedIdentifiers, position, false, type() != DUContext::Namespace && type() != DUContext::Global);
00848
00849
00850 if( d->m_importedContextsSize() != 0 ) {
00852 SearchItem::PtrList nonGlobalIdentifiers;
00853 FOREACH_ARRAY( const SearchItem::Ptr& identifier, aliasedIdentifiers )
00854 if( !identifier->isExplicitlyGlobal )
00855 nonGlobalIdentifiers << identifier;
00856
00857 if( !nonGlobalIdentifiers.isEmpty() ) {
00858 for(int import = d->m_importedContextsSize()-1; import >= 0; --import ) {
00859 DUContext* context = d->m_importedContexts()[import].context(source);
00860
00861 while( !context && import > 0 ) {
00862 --import;
00863 context = d->m_importedContexts()[import].context(source);
00864 }
00865
00866 if(context == this) {
00867 kDebug() << "resolved self as import:" << scopeIdentifier(true);
00868 continue;
00869 }
00870
00871 if( !context )
00872 break;
00873
00874 if( position.isValid() && d->m_importedContexts()[import].position.isValid() && position < d->m_importedContexts()[import].position )
00875 continue;
00876
00877 if( !context->findDeclarationsInternal(nonGlobalIdentifiers, url() == context->url() ? position : context->range().end, dataType, ret, source, flags | InImportedParentContext, depth+1) )
00878 return false;
00879 }
00880 }
00881 }
00882
00883 if( foundEnough(ret, flags) )
00884 return true;
00885
00887 if (!(flags & DontSearchInParent) && shouldSearchInParent(flags) && m_dynamicData->m_parentContext) {
00888 applyUpwardsAliases(aliasedIdentifiers, source);
00889 return m_dynamicData->m_parentContext->findDeclarationsInternal(aliasedIdentifiers, url() == m_dynamicData->m_parentContext->url() ? position : m_dynamicData->m_parentContext->range().end, dataType, ret, source, flags, depth);
00890 }
00891 return true;
00892 }
00893
00894 QList< QualifiedIdentifier > DUContext::fullyApplyAliases(KDevelop::QualifiedIdentifier id, const KDevelop::TopDUContext* source) const
00895 {
00896 ENSURE_CAN_READ
00897
00898 if(!source)
00899 source = topContext();
00900
00901 SearchItem::PtrList identifiers;
00902 identifiers << SearchItem::Ptr(new SearchItem(id));
00903
00904 const DUContext* current = this;
00905 while(current) {
00906 SearchItem::PtrList aliasedIdentifiers;
00907 current->applyAliases(identifiers, aliasedIdentifiers, SimpleCursor::invalid(), true, false);
00908 current->applyUpwardsAliases(identifiers, source);
00909
00910 current = current->parentContext();
00911 }
00912
00913 QList<QualifiedIdentifier> ret;
00914 FOREACH_ARRAY(SearchItem::Ptr item, identifiers)
00915 ret += item->toList();
00916
00917 return ret;
00918 }
00919
00920 QList<Declaration*> DUContext::findDeclarations( const QualifiedIdentifier & identifier, const SimpleCursor & position, const AbstractType::Ptr& dataType, const TopDUContext* topContext, SearchFlags flags) const
00921 {
00922 ENSURE_CAN_READ
00923
00924 DeclarationList ret;
00925 SearchItem::PtrList identifiers;
00926 identifiers << SearchItem::Ptr(new SearchItem(identifier));
00927
00928 findDeclarationsInternal(identifiers, position.isValid() ? position : range().end, dataType, ret, topContext ? topContext : this->topContext(), flags, 0);
00929
00930 return arrayToList(ret);
00931 }
00932
00933 bool DUContext::imports(const DUContext* origin, const SimpleCursor& /*position*/ ) const
00934 {
00935 ENSURE_CAN_READ
00936
00937 return m_dynamicData->imports(origin, topContext(), 4);
00938 }
00939
00940 bool DUContext::addIndirectImport(const DUContext::Import& import) {
00941 ENSURE_CAN_WRITE
00942 DUCHAIN_D_DYNAMIC(DUContext);
00943
00944 for(unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
00945 if(d->m_importedContexts()[a] == import) {
00946 d->m_importedContextsList()[a].position = import.position;
00947 return true;
00948 }
00949 }
00950
00953
00954 d->m_importedContextsList().append(import);
00955 return false;
00956 }
00957
00958 void DUContext::addImportedParentContext( DUContext * context, const SimpleCursor& position, bool anonymous, bool /*temporary*/ )
00959 {
00960 ENSURE_CAN_WRITE
00961
00962 if(context == this) {
00963 kDebug() << "Tried to import self";
00964 return;
00965 }
00966
00967 Import import(context, this, position);
00968 if(addIndirectImport(import))
00969 return;
00970
00971 if( !anonymous ) {
00972 ENSURE_CAN_WRITE_(context)
00973 context->m_dynamicData->addImportedChildContext(this);
00974 }
00975 //DUChain::contextChanged(this, DUChainObserver::Addition, DUChainObserver::ImportedParentContexts, context);
00976 }
00977
00978 void DUContext::removeImportedParentContext( DUContext * context )
00979 {
00980 ENSURE_CAN_WRITE
00981 DUCHAIN_D_DYNAMIC(DUContext);
00982
00983 Import import(context, this, SimpleCursor::invalid());
00984
00985 for(unsigned int a = 0; a < d->m_importedContextsSize(); ++a) {
00986 if(d->m_importedContexts()[a] == import) {
00987 removeFromArray(d->m_importedContextsList(), a);
00988 break;
00989 }
00990 }
00991
00992 if( !context )
00993 return;
00994
00995 context->m_dynamicData->removeImportedChildContext(this);
00996
00997 //DUChain::contextChanged(this, DUChainObserver::Removal, DUChainObserver::ImportedParentContexts, context);
00998 }
00999
01000 KDevVarLengthArray<IndexedDUContext> DUContext::indexedImporters() const
01001 {
01002 KDevVarLengthArray<IndexedDUContext> ret;
01003 if(owner())
01004 ret = Importers::self().importers(owner()->id()); //Add indirect importers to the list
01005
01006 FOREACH_FUNCTION(IndexedDUContext ctx, d_func()->m_importers)
01007 ret.append(ctx);
01008
01009 return ret;
01010 }
01011
01012 QVector<DUContext*> DUContext::importers() const
01013 {
01014 ENSURE_CAN_READ
01015
01016 QVector<DUContext*> ret;
01017 FOREACH_FUNCTION(IndexedDUContext ctx, d_func()->m_importers)
01018 ret << ctx.context();
01019
01020 if(owner()) {
01021 //Add indirect importers to the list
01022 KDevVarLengthArray<IndexedDUContext> indirect = Importers::self().importers(owner()->id());
01023 FOREACH_ARRAY(IndexedDUContext ctx, indirect) {
01024 ret << ctx.context();
01025 }
01026 }
01027
01028 return ret;
01029 }
01030
01031 DUContext * DUContext::findContext( const SimpleCursor& position, DUContext* parent) const
01032 {
01033 ENSURE_CAN_READ
01034
01035 if (!parent)
01036 parent = const_cast<DUContext*>(this);
01037
01038 FOREACH_FUNCTION(LocalIndexedDUContext context, parent->d_func()->m_childContexts)
01039 if (context.data(topContext())->range().contains(position)) {
01040 DUContext* ret = findContext(position, context.data(topContext()));
01041 if (!ret)
01042 ret = context.data(topContext());
01043
01044 return ret;
01045 }
01046
01047 return 0;
01048 }
01049
01050 bool DUContext::parentContextOf(DUContext* context) const
01051 {
01052 if (this == context)
01053 return true;
01054
01055 FOREACH_FUNCTION(LocalIndexedDUContext child, d_func()->m_childContexts) {
01056 if (child.data(topContext())->parentContextOf(context))
01057 return true;
01058 }
01059
01060 return false;
01061 }
01062
01063 QList<Declaration*> DUContext::allLocalDeclarations(const Identifier& identifier) const
01064 {
01065 IndexedIdentifier indexedIdentifier(identifier);
01066
01067 ENSURE_CAN_READ
01068 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
01069
01070 QList<Declaration*> ret;
01071
01072 if(m_dynamicData->m_hasLocalDeclarationsHash) {
01073 QHash<Identifier, DeclarationPointer>::const_iterator it = m_dynamicData->m_localDeclarationsHash.constFind(identifier);
01074 QHash<Identifier, DeclarationPointer>::const_iterator end = m_dynamicData->m_localDeclarationsHash.constEnd();
01075
01076 for( ; it != end && it.key() == identifier; ++it )
01077 ret << (*it).data();
01078 }else{
01079 DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
01080 while(it) {
01081 Declaration* decl = *it;
01082 if(decl->indexedIdentifier() == indexedIdentifier)
01083 ret << decl;
01084 ++it;
01085 }
01086 }
01087 return ret;
01088 }
01089
01090 QList< QPair<Declaration*, int> > DUContext::allDeclarations(const SimpleCursor& position, const TopDUContext* topContext, bool searchInParents) const
01091 {
01092 ENSURE_CAN_READ
01093
01094 QList< QPair<Declaration*, int> > ret;
01095
01096 QHash<const DUContext*, bool> hadContexts;
01097 // Iterate back up the chain
01098 mergeDeclarationsInternal(ret, position, hadContexts, topContext ? topContext : this->topContext(), searchInParents);
01099
01100 return ret;
01101 }
01102
01103 QVector<Declaration*> DUContext::localDeclarations(const TopDUContext* source) const
01104 {
01105 Q_UNUSED(source);
01106 ENSURE_CAN_READ
01107
01108 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
01109 QVector<Declaration*> ret;
01110 FOREACH_FUNCTION(LocalIndexedDeclaration decl, d_func()->m_localDeclarations) {
01111 ret << decl.data(topContext());
01112 Q_ASSERT(ret.back()->context() == this);
01113 ret.back()->identifier().isEmpty();
01114 }
01115
01116 return ret;
01117 }
01118
01119 void DUContext::mergeDeclarationsInternal(QList< QPair<Declaration*, int> >& definitions, const SimpleCursor& position, QHash<const DUContext*, bool>& hadContexts, const TopDUContext* source, bool searchInParents, int currentDepth) const
01120 {
01121 if((currentDepth > 300 && currentDepth < 1000) || currentDepth > 1300) {
01122 kDebug() << "too much depth";
01123 return;
01124 }
01125 DUCHAIN_D(DUContext);
01126
01127 if(hadContexts.contains(this) && !searchInParents)
01128 return;
01129
01130 if(!hadContexts.contains(this)) {
01131 hadContexts[this] = true;
01132
01133 if( (type() == DUContext::Namespace || type() == DUContext::Global) && currentDepth < 1000 )
01134 currentDepth += 1000;
01135
01136 {
01137 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
01138 DUContextDynamicData::VisibleDeclarationIterator it(m_dynamicData);
01139 while(it) {
01140 Declaration* decl = *it;
01141
01142 if ( decl && (!position.isValid() || decl->range().start <= position) )
01143 definitions << qMakePair(decl, currentDepth);
01144 ++it;
01145 }
01146 }
01147
01148 for(int a = d->m_importedContextsSize()-1; a >= 0; --a) {
01149 const Import* import(&d->m_importedContexts()[a]);
01150 DUContext* context = import->context(source);
01151 while( !context && a > 0 ) {
01152 --a;
01153 import = &d->m_importedContexts()[a];
01154 context = import->context(source);
01155 }
01156 if( !context )
01157 break;
01158
01159 if(context == this) {
01160 kDebug() << "resolved self as import:" << scopeIdentifier(true);
01161 continue;
01162 }
01163
01164
01165 if( position.isValid() && import->position.isValid() && position < import->position )
01166 continue;
01167
01168 context->mergeDeclarationsInternal(definitions, SimpleCursor::invalid(), hadContexts, source, searchInParents && context->shouldSearchInParent(InImportedParentContext) && context->parentContext()->type() == DUContext::Helper, currentDepth+1);
01169 }
01170 }
01171
01173 if (parentContext() && searchInParents )
01174 parentContext()->mergeDeclarationsInternal(definitions, parentContext()->type() == DUContext::Class ? parentContext()->range().end : position, hadContexts, source, searchInParents, currentDepth+1);
01175 }
01176
01177 void DUContext::deleteLocalDeclarations()
01178 {
01179 ENSURE_CAN_WRITE
01180 KDevVarLengthArray<LocalIndexedDeclaration> declarations;
01181 {
01182 QMutexLocker lock(&DUContextDynamicData::m_localDeclarationsMutex);
01183 FOREACH_FUNCTION(const LocalIndexedDeclaration& decl, d_func()->m_localDeclarations)
01184 declarations.append(decl);
01185 }
01186
01187 TopDUContext* top = topContext();
01188 //If we are deleting something that is not stored to disk, we need to create + delete the declarations,
01189 //so their destructor unregisters from the persistent symbol table and from TopDUContextDynamicData
01190 FOREACH_ARRAY(LocalIndexedDeclaration decl, declarations)
01191 if(decl.isLoaded(top) || !top->deleting() || !top->isOnDisk())
01192 delete decl.data(top);
01193 }
01194
01195 void DUContext::deleteChildContextsRecursively()
01196 {
01197 ENSURE_CAN_WRITE
01198
01199 TopDUContext* top = topContext();
01200
01201 QVector<LocalIndexedDUContext> children;
01202 FOREACH_FUNCTION(LocalIndexedDUContext ctx, d_func()->m_childContexts)
01203 children << ctx;
01204
01205 //If we are deleting a context that is already stored to disk, we don't need to load not yet loaded child-contexts.
01206 //Else we need to, so the declarations are unregistered from symbol-table and from TopDUContextDynamicData in their destructor
01207 foreach(const LocalIndexedDUContext &ctx, children)
01208 if(ctx.isLoaded(top) || !top->deleting() || !top->isOnDisk())
01209 delete ctx.data(top);
01210 }
01211
01212 QVector< Declaration * > DUContext::clearLocalDeclarations( )
01213 {
01214 QVector< Declaration * > ret = localDeclarations();
01215 foreach (Declaration* dec, ret)
01216 dec->setContext(0);
01217 return ret;
01218 }
01219
01220 QualifiedIdentifier DUContext::scopeIdentifier(bool includeClasses) const
01221 {
01222 ENSURE_CAN_READ
01223
01224 QualifiedIdentifier ret;
01225 m_dynamicData->scopeIdentifier(includeClasses, ret);
01226
01227 return ret;
01228 }
01229
01230 bool DUContext::equalScopeIdentifier(const DUContext* rhs) const
01231 {
01232 ENSURE_CAN_READ
01233
01234 const DUContext* left = this;
01235 const DUContext* right = rhs;
01236
01237 while(left || right) {
01238 if(!left || !right)
01239 return false;
01240
01241 if(!(left->d_func()->m_scopeIdentifier == right->d_func()->m_scopeIdentifier))
01242 return false;
01243
01244 left = left->parentContext();
01245 right = right->parentContext();
01246 }
01247
01248 return true;
01249 }
01250
01251 void DUContext::setLocalScopeIdentifier(const QualifiedIdentifier & identifier)
01252 {
01253 ENSURE_CAN_WRITE
01254 //Q_ASSERT(d_func()->m_childContexts.isEmpty() && d_func()->m_localDeclarations.isEmpty());
01255 bool wasInSymbolTable = inSymbolTable();
01256 setInSymbolTable(false);
01257 d_func_dynamic()->m_scopeIdentifier = identifier;
01258 setInSymbolTable(wasInSymbolTable);
01259 //DUChain::contextChanged(this, DUChainObserver::Change, DUChainObserver::Identifier);
01260 }
01261
01262 QualifiedIdentifier DUContext::localScopeIdentifier() const
01263 {
01264 //ENSURE_CAN_READ Commented out for performance reasons
01265
01266 return d_func()->m_scopeIdentifier;
01267 }
01268
01269 IndexedQualifiedIdentifier DUContext::indexedLocalScopeIdentifier() const {
01270 return d_func()->m_scopeIdentifier;
01271 }
01272
01273 DUContext::ContextType DUContext::type() const
01274 {
01275 //ENSURE_CAN_READ This is disabled, because type() is called very often while searching, and it costs us performance
01276
01277 return d_func()->m_contextType;
01278 }
01279
01280 void DUContext::setType(ContextType type)
01281 {
01282 ENSURE_CAN_WRITE
01283
01284 d_func_dynamic()->m_contextType = type;
01285
01286 //DUChain::contextChanged(this, DUChainObserver::Change, DUChainObserver::ContextType);
01287 }
01288
01289 QList<Declaration*> DUContext::findDeclarations(const Identifier& identifier, const SimpleCursor& position, const TopDUContext* topContext, SearchFlags flags) const
01290 {
01291 ENSURE_CAN_READ
01292
01293 DeclarationList ret;
01294 SearchItem::PtrList identifiers;
01295 identifiers << SearchItem::Ptr(new SearchItem(QualifiedIdentifier(identifier)));
01296 findDeclarationsInternal(identifiers, position.isValid() ? position : range().end, AbstractType::Ptr(), ret, topContext ? topContext : this->topContext(), flags, 0);
01297 return arrayToList(ret);
01298 }
01299
01300 void DUContext::deleteUse(int index)
01301 {
01302 ENSURE_CAN_WRITE
01303 DUCHAIN_D_DYNAMIC(DUContext);
01304 removeFromArray(d->m_usesList(), index);
01305
01306 if(!m_dynamicData->m_rangesForUses.isEmpty()) {
01307 if(m_dynamicData->m_rangesForUses[index]) {
01308 EditorIntegrator editor;
01309 editor.setCurrentUrl(url(), (bool)smartRange());
01310 LockedSmartInterface iface = editor.smart();
01311 if (iface) {
01312 m_dynamicData->m_rangesForUses[index]->removeWatcher(this);
01313 EditorIntegrator::releaseRange(m_dynamicData->m_rangesForUses[index]);
01314 }
01315 }
01316 m_dynamicData->m_rangesForUses.remove(index);
01317 }
01318 }
01319
01320 QVector<KTextEditor::SmartRange*> DUContext::takeUseRanges()
01321 {
01322 ENSURE_CAN_WRITE
01323 QVector<KTextEditor::SmartRange*> ret = m_dynamicData->m_rangesForUses;
01324
01325 foreach(KTextEditor::SmartRange* range, ret)
01326 if(range)
01327 range->removeWatcher(this);
01328
01329 m_dynamicData->m_rangesForUses.clear();
01330 return ret;
01331 }
01332
01333 QVector<KTextEditor::SmartRange*> DUContext::useRanges()
01334 {
01335 ENSURE_CAN_READ
01336 return m_dynamicData->m_rangesForUses;
01337 }
01338
01339 void DUContext::deleteUses()
01340 {
01341 ENSURE_CAN_WRITE
01342
01343 DUCHAIN_D_DYNAMIC(DUContext);
01344 d->m_usesList().clear();
01345
01346 clearUseSmartRanges();
01347 }
01348
01349 void DUContext::deleteUsesRecursively()
01350 {
01351 deleteUses();
01352
01353 FOREACH_FUNCTION(LocalIndexedDUContext childContext, d_func()->m_childContexts)
01354 childContext.data(topContext())->deleteUsesRecursively();
01355 }
01356
01357 bool DUContext::inDUChain() const {
01358 if( d_func()->m_anonymousInParent || !m_dynamicData->m_parentContext)
01359 return false;
01360
01361 TopDUContext* top = topContext();
01362 return top && top->inDUChain();
01363 }
01364
01365 DUContext* DUContext::specialize(IndexedInstantiationInformation /*specialization*/, const TopDUContext* /*topContext*/, int /*upDistance*/) {
01366 return this;
01367 }
01368
01369 SimpleCursor DUContext::importPosition(const DUContext* target) const
01370 {
01371 ENSURE_CAN_READ
01372 DUCHAIN_D(DUContext);
01373 Import import(const_cast<DUContext*>(target), this, SimpleCursor::invalid());
01374 for(unsigned int a = 0; a < d->m_importedContextsSize(); ++a)
01375 if(d->m_importedContexts()[a] == import)
01376 return d->m_importedContexts()[a].position;
01377 return SimpleCursor::invalid();
01378 }
01379
01380 QVector<DUContext::Import> DUContext::importedParentContexts() const
01381 {
01382 ENSURE_CAN_READ
01383 QVector<DUContext::Import> ret;
01384 FOREACH_FUNCTION(const DUContext::Import& import, d_func()->m_importedContexts)
01385 ret << import;
01386 return ret;
01387 }
01388
01389 QList<DUContext*> DUContext::findContexts(ContextType contextType, const QualifiedIdentifier& identifier, const SimpleCursor& position, const TopDUContext* top, SearchFlags flags) const
01390 {
01391 ENSURE_CAN_READ
01392
01393 QList<DUContext*> ret;
01394 SearchItem::PtrList identifiers;
01395 identifiers << SearchItem::Ptr(new SearchItem(identifier));
01396
01397 findContextsInternal(contextType, identifiers, position.isValid() ? position : range().end, ret, top ? top : topContext(), flags);
01398 return ret;
01399 }
01400
01401 void DUContext::applyAliases(const SearchItem::PtrList& baseIdentifiers, SearchItem::PtrList& identifiers, const SimpleCursor& position, bool canBeNamespace, bool onlyImports) const {
01402
01403 QList<Declaration*> imports = allLocalDeclarations(globalImportIdentifier);
01404 if(imports.isEmpty() && onlyImports) {
01405 identifiers = baseIdentifiers;
01406 return;
01407 }
01408
01409 FOREACH_ARRAY( const SearchItem::Ptr& identifier, baseIdentifiers ) {
01410 bool addUnmodified = true;
01411
01412 if( !identifier->isExplicitlyGlobal ) {
01413
01414 if( !imports.isEmpty() )
01415 {
01416 //We have namespace-imports.
01417 foreach( Declaration* importDecl, imports )
01418 {
01419 if( importDecl->range().end > position )
01420 continue;
01421 //Search for the identifier with the import-identifier prepended
01422 Q_ASSERT(dynamic_cast<NamespaceAliasDeclaration*>(importDecl));
01423 NamespaceAliasDeclaration* alias = static_cast<NamespaceAliasDeclaration*>(importDecl);
01424 identifiers.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier(), identifier ) ) ) ;
01425 }
01426 }
01427
01428 if( !identifier->isEmpty() && (identifier->hasNext() || canBeNamespace) ) {
01429 QList<Declaration*> aliases = allLocalDeclarations(identifier->identifier);
01430 if(!aliases.isEmpty()) {
01431 //The first part of the identifier has been found as a namespace-alias.
01432 //In c++, we only need the first alias. However, just to be correct, follow them all for now.
01433 foreach( Declaration* aliasDecl, aliases )
01434 {
01435 if( aliasDecl->range().end > position )
01436 continue;
01437 if(!dynamic_cast<NamespaceAliasDeclaration*>(aliasDecl))
01438 continue;
01439
01440 addUnmodified = false; //The un-modified identifier can be ignored, because it will be replaced with the resolved alias
01441 NamespaceAliasDeclaration* alias = static_cast<NamespaceAliasDeclaration*>(aliasDecl);
01442
01443 //Create an identifier where namespace-alias part is replaced with the alias target
01444 identifiers.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier(), identifier->next ) ) ) ;
01445 }
01446 }
01447 }
01448 }
01449
01450 if( addUnmodified )
01451 identifiers.append(identifier);
01452 }
01453 }
01454
01455 void DUContext::applyUpwardsAliases(SearchItem::PtrList& identifiers, const TopDUContext* /*source*/) const {
01456
01457 if(type() == Namespace) {
01458 QualifiedIdentifier localId = d_func()->m_scopeIdentifier;
01459 if(localId.isEmpty())
01460 return;
01461
01462 //Make sure we search for the items in all namespaces of the same name, by duplicating each one with the namespace-identifier prepended.
01463 //We do this by prepending items to the current identifiers that equal the local scope identifier.
01464 SearchItem::Ptr newItem( new SearchItem(localId) );
01465
01466 //This will exclude explictly global identifiers
01467 newItem->addToEachNode( identifiers );
01468
01469 if(!newItem->next.isEmpty()) {
01470 //Prepend the full scope before newItem
01471 DUContext* parent = m_dynamicData->m_parentContext.data();
01472 while(parent) {
01473 newItem = SearchItem::Ptr( new SearchItem(parent->d_func()->m_scopeIdentifier, newItem) );
01474 parent = parent->m_dynamicData->m_parentContext.data();
01475 }
01476
01477 newItem->isExplicitlyGlobal = true;
01478 insertToArray(identifiers, newItem, 0);
01479 }
01480 }
01481 }
01482
01483 void DUContext::findContextsInternal(ContextType contextType, const SearchItem::PtrList& baseIdentifiers, const SimpleCursor& position, QList<DUContext*>& ret, const TopDUContext* source, SearchFlags flags) const
01484 {
01485 DUCHAIN_D(DUContext);
01486 if (contextType == type()) {
01487 FOREACH_ARRAY( const SearchItem::Ptr& identifier, baseIdentifiers )
01488 if (identifier->match(scopeIdentifier(true)) && (!parentContext() || !identifier->isExplicitlyGlobal) )
01489 ret.append(const_cast<DUContext*>(this));
01490 }
01493 SearchItem::PtrList aliasedIdentifiers;
01494 //Because of namespace-imports and aliases, this identifier may need to be searched as under multiple names
01495 applyAliases(baseIdentifiers, aliasedIdentifiers, position, contextType == Namespace, contextType != Namespace);
01496
01497 if( d->m_importedContextsSize() != 0 ) {
01499 SearchItem::PtrList nonGlobalIdentifiers;
01500 FOREACH_ARRAY( const SearchItem::Ptr& identifier, aliasedIdentifiers )
01501 if( !identifier->isExplicitlyGlobal )
01502 nonGlobalIdentifiers << identifier;
01503
01504 if( !nonGlobalIdentifiers.isEmpty() ) {
01505 for(int a = d->m_importedContextsSize()-1; a >= 0; --a) {
01506
01507 DUContext* context = d->m_importedContexts()[a].context(source);
01508
01509 while( !context && a > 0 ) {
01510 --a;
01511 context = d->m_importedContexts()[a].context(source);
01512 }
01513
01514 if(context == this) {
01515 kDebug() << "resolved self as import:" << scopeIdentifier(true);
01516 continue;
01517 }
01518
01519 if( !context )
01520 break;
01521
01522 context->findContextsInternal(contextType, nonGlobalIdentifiers, url() == context->url() ? position : context->range().end, ret, source, flags | InImportedParentContext);
01523 }
01524 }
01525 }
01526
01528 if ( !(flags & DontSearchInParent) && shouldSearchInParent(flags) && parentContext()) {
01529 applyUpwardsAliases(aliasedIdentifiers, source);
01530 parentContext()->findContextsInternal(contextType, aliasedIdentifiers, url() == parentContext()->url() ? position : parentContext()->range().end, ret, source, flags);
01531 }
01532 }
01533
01534 bool DUContext::shouldSearchInParent(SearchFlags flags) const
01535 {
01536 return (parentContext() && parentContext()->type() == DUContext::Helper && (flags & InImportedParentContext)) ||
01537 !(flags & InImportedParentContext);
01538 }
01539
01540 const Use* DUContext::uses() const
01541 {
01542 ENSURE_CAN_READ
01543
01544 synchronizeUsesFromSmart();
01545 return d_func()->m_uses();
01546 }
01547
01548 int DUContext::usesCount() const
01549 {
01550 return d_func()->m_usesSize();
01551 }
01552
01553 int DUContext::createUse(int declarationIndex, const SimpleRange& range, KTextEditor::SmartRange* smartRange, int insertBefore)
01554 {
01555 DUCHAIN_D_DYNAMIC(DUContext);
01556 ENSURE_CAN_WRITE
01557
01558 if(insertBefore == -1) {
01559 //Find position where to insert
01560 unsigned int a = 0;
01561 for(; a < d->m_usesSize() && range.start > d->m_uses()[a].m_range.start; ++a) { ///@todo do binary search
01562 }
01563 insertBefore = a;
01564 }
01565
01566 insertToArray(d->m_usesList(), Use(range, declarationIndex), insertBefore);
01567 if(smartRange) {
01569 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.size()) == d->m_usesSize()-1);
01570 m_dynamicData->m_rangesForUses.insert(insertBefore, smartRange);
01571 smartRange->addWatcher(this);
01572 // smartRange->setWantsDirectChanges(true);
01573
01574 d->m_usesList()[insertBefore].m_range = SimpleRange(*smartRange);
01575 }else{
01576 // This can happen eg. when a document is closed during its parsing, and has no ill effects.
01577 //Q_ASSERT(m_dynamicData->m_rangesForUses.isEmpty());
01578 }
01579
01580 return insertBefore;
01581 }
01582
01583 KTextEditor::SmartRange* DUContext::useSmartRange(int useIndex)
01584 {
01585 ENSURE_CAN_READ
01586 if(m_dynamicData->m_rangesForUses.isEmpty())
01587 return 0;
01588 else{
01589 if(useIndex >= 0 && useIndex < m_dynamicData->m_rangesForUses.size())
01590 return m_dynamicData->m_rangesForUses.at(useIndex);
01591 else
01592 return 0;
01593 }
01594 }
01595
01596
01597 void DUContext::setUseSmartRange(int useIndex, KTextEditor::SmartRange* range)
01598 {
01599 ENSURE_CAN_WRITE
01600 if(m_dynamicData->m_rangesForUses.isEmpty())
01601 m_dynamicData->m_rangesForUses.insert(0, d_func()->m_usesSize(), 0);
01602
01603 Q_ASSERT(uint(m_dynamicData->m_rangesForUses.size()) == d_func()->m_usesSize());
01604
01605 if(m_dynamicData->m_rangesForUses[useIndex]) {
01606 EditorIntegrator editor;
01607 editor.setCurrentUrl(url(), (bool)range);
01608 LockedSmartInterface iface = editor.smart();
01609 if (iface) {
01610 m_dynamicData->m_rangesForUses[useIndex]->removeWatcher(this);
01611 EditorIntegrator::releaseRange(m_dynamicData->m_rangesForUses[useIndex]);
01612 }
01613 }
01614
01615 m_dynamicData->m_rangesForUses[useIndex] = range;
01616 d_func_dynamic()->m_usesList()[useIndex].m_range = SimpleRange(*range);
01617 range->addWatcher(this);
01618 // range->setWantsDirectChanges(true);
01619 }
01620
01621 void DUContext::clearUseSmartRanges()
01622 {
01623 ENSURE_CAN_WRITE
01624
01625 if (!m_dynamicData->m_rangesForUses.isEmpty()) {
01626 EditorIntegrator editor;
01627 editor.setCurrentUrl(url(), (bool)smartRange());
01628 LockedSmartInterface iface = editor.smart();
01629 if (iface) {
01630 foreach (SmartRange* range, m_dynamicData->m_rangesForUses) {
01631 range->removeWatcher(this);
01632 EditorIntegrator::releaseRange(range);
01633 }
01634 }
01635
01636 m_dynamicData->m_rangesForUses.clear();
01637 }
01638 }
01639
01640 void DUContext::setUseDeclaration(int useNumber, int declarationIndex)
01641 {
01642 ENSURE_CAN_WRITE
01643 d_func_dynamic()->m_usesList()[useNumber].m_declarationIndex = declarationIndex;
01644 }
01645
01646
01647 DUContext * DUContext::findContextAt(const SimpleCursor & position, bool includeRightBorder) const
01648 {
01649 ENSURE_CAN_READ
01650
01651 // kDebug() << "searchign" << position.textCursor() << "in:" << scopeIdentifier(true).toString() << range().textRange() << includeRightBorder;
01652
01653 if (!range().contains(position) && (!includeRightBorder || range().end != position)) {
01654 // kDebug() << "mismatch";
01655 return 0;
01656 }
01657
01658 for(int a = int(d_func()->m_childContextsSize())-1; a >= 0; --a)
01659 if (DUContext* specific = d_func()->m_childContexts()[a].data(topContext())->findContextAt(position, includeRightBorder))
01660 return specific;
01661
01662 return const_cast<DUContext*>(this);
01663 }
01664
01665 Declaration * DUContext::findDeclarationAt(const SimpleCursor & position) const
01666 {
01667 ENSURE_CAN_READ
01668
01669 if (!range().contains(position))
01670 return 0;
01671
01672 FOREACH_FUNCTION(LocalIndexedDeclaration child, d_func()->m_localDeclarations)
01673 if (child.data(topContext())->range().contains(position))
01674 return child.data(topContext());
01675
01676 return 0;
01677 }
01678
01679 DUContext* DUContext::findContextIncluding(const SimpleRange& range) const
01680 {
01681 ENSURE_CAN_READ
01682
01683 if (!this->range().contains(range))
01684 return 0;
01685
01686 FOREACH_FUNCTION(LocalIndexedDUContext child, d_func()->m_childContexts)
01687 if (DUContext* specific = child.data(topContext())->findContextIncluding(range))
01688 return specific;
01689
01690 return const_cast<DUContext*>(this);
01691 }
01692
01693 int DUContext::findUseAt(const SimpleCursor & position) const
01694 {
01695 ENSURE_CAN_READ
01696
01697 synchronizeUsesFromSmart();
01698
01699 if (!range().contains(position))
01700 return -1;
01701
01702 for(unsigned int a = 0; a < d_func()->m_usesSize(); ++a)
01703 if (d_func()->m_uses()[a].m_range.contains(position))
01704 return a;
01705
01706 return -1;
01707 }
01708
01709 bool DUContext::inSymbolTable() const
01710 {
01711 return d_func()->m_inSymbolTable;
01712 }
01713
01714 void DUContext::setInSymbolTable(bool inSymbolTable)
01715 {
01716 if(parentContext()) {
01717 if(!d_func()->m_inSymbolTable && inSymbolTable) {
01718 QualifiedIdentifier id(scopeIdentifier(true));
01719 PersistentSymbolTable::self().addContext(id, this);
01720
01721 }else if(d_func()->m_inSymbolTable && !inSymbolTable) {
01722 QualifiedIdentifier id(scopeIdentifier(true));
01723 PersistentSymbolTable::self().removeContext(id, this);
01724 }
01725 }
01726
01727 d_func_dynamic()->m_inSymbolTable = inSymbolTable;
01728 }
01729
01730 // kate: indent-width 2;
01731
01732 void DUContext::clearImportedParentContexts()
01733 {
01734 ENSURE_CAN_WRITE
01735 DUCHAIN_D_DYNAMIC(DUContext);
01736
01737 while( d->m_importedContextsSize() != 0 ) {
01738 DUContext* ctx = d->m_importedContexts()[0].context(0);
01739 if(ctx)
01740 ctx->m_dynamicData->removeImportedChildContext(this);
01741
01742 d->m_importedContextsList().removeOne(d->m_importedContexts()[0]);
01743 }
01744 }
01745
01746 void DUContext::cleanIfNotEncountered(const QSet<DUChainBase*>& encountered)
01747 {
01748 ENSURE_CAN_WRITE
01749
01750 foreach (Declaration* dec, localDeclarations())
01751 if (!encountered.contains(dec))
01752 delete dec;
01753
01754 //Copy since the array may change during the iteration
01755 KDevVarLengthArray<LocalIndexedDUContext, 10> childrenCopy = d_func_dynamic()->m_childContextsList();
01756
01757 FOREACH_ARRAY(LocalIndexedDUContext childContext, childrenCopy)
01758 if (!encountered.contains(childContext.data(topContext())))
01759 delete childContext.data(topContext());
01760 }
01761
01762 TopDUContext* DUContext::topContext() const
01763 {
01764 return m_dynamicData->m_topContext;
01765 }
01766
01767 QWidget* DUContext::createNavigationWidget(Declaration* /*decl*/, TopDUContext* /*topContext*/, const QString& /*htmlPrefix*/, const QString& /*htmlSuffix*/) const
01768 {
01769 return 0;
01770 }
01771
01772 void DUContext::squeeze()
01773 {
01774 if(!m_dynamicData->m_rangesForUses.isEmpty())
01775 m_dynamicData->m_rangesForUses.squeeze();
01776
01777 FOREACH_FUNCTION(LocalIndexedDUContext child, d_func()->m_childContexts)
01778 child.data(topContext())->squeeze();
01779 }
01780
01781 QList<SimpleRange> allUses(DUContext* context, int declarationIndex, bool noEmptyUses)
01782 {
01783 QList<SimpleRange> ret;
01784 for(int a = 0; a < context->usesCount(); ++a)
01785 if(context->uses()[a].m_declarationIndex == declarationIndex)
01786 if(!noEmptyUses || !context->uses()[a].m_range.isEmpty())
01787 ret << context->uses()[a].m_range;
01788
01789 foreach(DUContext* child, context->childContexts())
01790 ret += allUses(child, declarationIndex, noEmptyUses);
01791
01792 return ret;
01793 }
01794
01795 QList<KTextEditor::SmartRange*> allSmartUses(DUContext* context, int declarationIndex)
01796 {
01797 QList<KTextEditor::SmartRange*> ret;
01798
01799 const Use* uses(context->uses());
01800
01801 for(int a = 0; a < context->usesCount(); ++a)
01802 if(uses[a].m_declarationIndex == declarationIndex) {
01803 KTextEditor::SmartRange* range = context->useSmartRange(a);
01804 if(range)
01805 ret << range;
01806 }
01807
01808 foreach(DUContext* child, context->childContexts())
01809 ret += allSmartUses(child, declarationIndex);
01810
01811 return ret;
01812 }
01813
01814 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, Ptr nextItem, int start) : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false) {
01815 if(!id.isEmpty()) {
01816 if(id.count() > start)
01817 identifier = id.at(start);
01818
01819 if(id.count() > start+1)
01820 addNext(Ptr( new SearchItem(id, nextItem, start+1) ));
01821 else if(nextItem)
01822 next.append(nextItem);
01823 }else if(nextItem) {
01825 isExplicitlyGlobal = nextItem->isExplicitlyGlobal;
01826 identifier = nextItem->identifier;
01827 next = nextItem->next;
01828 }
01829 }
01830
01831 DUContext::SearchItem::SearchItem(const QualifiedIdentifier& id, const PtrList& nextItems, int start) : isExplicitlyGlobal(start == 0 ? id.explicitlyGlobal() : false) {
01832 if(id.count() > start)
01833 identifier = id.at(start);
01834
01835 if(id.count() > start+1)
01836 addNext(Ptr( new SearchItem(id, nextItems, start+1) ));
01837 else
01838 next = nextItems;
01839 }
01840
01841 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, Identifier id, const PtrList& nextItems) : isExplicitlyGlobal(explicitlyGlobal), identifier(id), next(nextItems) {
01842 }
01843
01844 DUContext::SearchItem::SearchItem(bool explicitlyGlobal, Identifier id, Ptr nextItem) : isExplicitlyGlobal(explicitlyGlobal), identifier(id) {
01845 next.append(nextItem);
01846 }
01847
01848 bool DUContext::SearchItem::match(const QualifiedIdentifier& id, int offset) const {
01849 if(id.isEmpty()) {
01850 if(identifier.isEmpty() && next.isEmpty())
01851 return true;
01852 else
01853 return false;
01854 }
01855
01856 if(id.at(offset) != identifier) //The identifier is different
01857 return false;
01858
01859 if(offset == id.count()-1) {
01860 if(next.isEmpty())
01861 return true; //match
01862 else
01863 return false; //id is too short
01864 }
01865
01866 for(int a = 0; a < next.size(); ++a)
01867 if(next[a]->match(id, offset+1))
01868 return true;
01869
01870 return false;
01871 }
01872
01873 bool DUContext::SearchItem::isEmpty() const {
01874 return identifier.isEmpty();
01875 }
01876
01877 bool DUContext::SearchItem::hasNext() const {
01878 return !next.isEmpty();
01879 }
01880
01881 QList<QualifiedIdentifier> DUContext::SearchItem::toList(const QualifiedIdentifier& prefix) const {
01882 QList<QualifiedIdentifier> ret;
01883
01884 QualifiedIdentifier id = prefix;
01885 if(id.isEmpty())
01886 id.setExplicitlyGlobal(isExplicitlyGlobal);
01887 if(!identifier.isEmpty())
01888 id.push(identifier);
01889
01890 if(next.isEmpty()) {
01891 ret << id;
01892 } else {
01893 for(int a = 0; a < next.size(); ++a)
01894 ret += next[a]->toList(id);
01895 }
01896 return ret;
01897 }
01898
01899
01900 void DUContext::SearchItem::addNext(SearchItem::Ptr other) {
01901 next.append(other);
01902 }
01903
01904 void DUContext::SearchItem::addToEachNode(SearchItem::Ptr other) {
01905 if(other->isExplicitlyGlobal)
01906 return;
01907
01908 next.append(other);
01909 for(int a = 0; a < next.size()-1; ++a)
01910 next[a]->addToEachNode(other);
01911 }
01912
01913 void DUContext::SearchItem::addToEachNode(SearchItem::PtrList other) {
01914 int added = 0;
01915 FOREACH_ARRAY(SearchItem::Ptr o, other) {
01916 if(!o->isExplicitlyGlobal) {
01917 next.append(o);
01918 ++added;
01919 }
01920 }
01921
01922 for(int a = 0; a < next.size()-added; ++a)
01923 next[a]->addToEachNode(other);
01924 }
01925
01926 DUContext::Import::Import(DUContext* _context, const DUContext* importer, const SimpleCursor& _position) : position(_position) {
01927 if(_context && _context->owner() && (_context->owner()->specialization().index() || (importer && importer->topContext() != _context->topContext()))) {
01928 m_declaration = _context->owner()->id();
01929 }else{
01930 m_context = _context;
01931 }
01932 }
01933
01934 DUContext::Import::Import(const DeclarationId& id, const SimpleCursor& _position) : position(_position) {
01935 m_declaration = id;
01936 }
01937
01938 DUContext* DUContext::Import::context(const TopDUContext* topContext) const {
01939 if(m_declaration.isValid()) {
01940 Declaration* decl = m_declaration.getDeclaration(topContext);
01941 if(decl)
01942 return decl->logicalInternalContext(topContext);
01943 else
01944 return 0;
01945 }else{
01946 return m_context.data();
01947 }
01948 }
01949
01950 bool DUContext::Import::isDirect() const {
01951 return m_context.isValid();
01952 }
01953
01954 }
01955
01956 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on