00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "duchain.h"
00021 #include "duchainlock.h"
00022
00023 #include <QtCore/QCoreApplication>
00024 #include <QApplication>
00025 #include <QtCore/QHash>
00026 #include <QtCore/QMultiMap>
00027 #include <QtCore/QTimer>
00028 #include <QtCore/QReadWriteLock>
00029 #include <QtCore/qatomic.h>
00030
00031 #include <kglobal.h>
00032
00033 #include <KDE/KTextEditor/Document>
00034 #include <KDE/KTextEditor/SmartInterface>
00035
00036 #include <interfaces/idocumentcontroller.h>
00037 #include <interfaces/icore.h>
00038 #include <interfaces/ilanguage.h>
00039 #include <interfaces/ilanguagecontroller.h>
00040
00041 #include "../editor/editorintegrator.h"
00042 #include "../interfaces/ilanguagesupport.h"
00043 #include "../interfaces/icodehighlighting.h"
00044 #include "../backgroundparser/backgroundparser.h"
00045
00046 #include "topducontext.h"
00047 #include "topducontextdata.h"
00048 #include "topducontextdynamicdata.h"
00049 #include "parsingenvironment.h"
00050 #include "declaration.h"
00051 #include "definitions.h"
00052 #include "duchainutils.h"
00053 #include "use.h"
00054 #include "uses.h"
00055 #include "abstractfunctiondeclaration.h"
00056 #include "smartconverter.h"
00057 #include "duchainregister.h"
00058 #include "persistentsymboltable.h"
00059 #include "repositories/itemrepository.h"
00060 #include <util/google/dense_hash_map>
00061 #include <QtCore/qthread.h>
00062 #include <QtCore/qwaitcondition.h>
00063 #include <QtCore/qmutex.h>
00064 #include <unistd.h>
00065 #include "waitforupdate.h"
00066 #include "referencecounting.h"
00067
00068 Q_DECLARE_METATYPE(KDevelop::IndexedString)
00069 Q_DECLARE_METATYPE(KDevelop::IndexedTopDUContext)
00070 Q_DECLARE_METATYPE(KDevelop::ReferencedTopDUContext)
00071
00072 namespace {
00073
00074
00075
00076
00077
00078 const int SOFT_CLEANUP_STEPS = 1;
00079
00080 const uint cleanupEverySeconds = 200;
00081
00083 const uint maxFinalCleanupCheckContexts = 2000;
00084 const uint minimumFinalCleanupCheckContextsPercentage = 10;
00085
00086 bool duChainDeleted = false;
00087 }
00088
00089 namespace KDevelop
00090 {
00091
00092 DEFINE_LIST_MEMBER_HASH(EnvironmentInformationListItem, items, uint)
00093
00094
00095 class EnvironmentInformationItem {
00096 public:
00097 EnvironmentInformationItem(uint topContext, uint size) : m_topContext(topContext), m_size(size) {
00098 }
00099
00100 ~EnvironmentInformationItem() {
00101 }
00102
00103 unsigned int hash() const {
00104 return m_topContext;
00105 }
00106
00107 unsigned int itemSize() const {
00108 return sizeof(*this) + m_size;
00109 }
00110
00111 uint m_topContext;
00112 uint m_size;
00113 };
00114
00115 struct ItemRepositoryIndexHash
00116 {
00117 size_t
00118 operator()(unsigned int __x) const
00119 { return 173*(__x>>2) + 11 * (__x >> 16); }
00120 };
00121
00122
00123 class EnvironmentInformationRequest {
00124 public:
00125
00127 EnvironmentInformationRequest(uint topContextIndex) : m_file(0), m_index(topContextIndex) {
00128 }
00129
00130 EnvironmentInformationRequest(const ParsingEnvironmentFile* file) : m_file(file), m_index(file->indexedTopContext().index()) {
00131 }
00132
00133 enum {
00134 AverageSize = 32
00135 };
00136
00137 unsigned int hash() const {
00138 return m_index;
00139 }
00140
00141 size_t itemSize() const {
00142 return sizeof(EnvironmentInformationItem) + DUChainItemSystem::self().dynamicSize(*m_file->d_func());
00143 }
00144
00145 void createItem(EnvironmentInformationItem* item) const {
00146 new (item) EnvironmentInformationItem(m_index, DUChainItemSystem::self().dynamicSize(*m_file->d_func()));
00147 Q_ASSERT(m_file->d_func()->m_dynamic);
00148 DUChainItemSystem::self().copy(*m_file->d_func(), *(DUChainBaseData*)(((char*)item) + sizeof(EnvironmentInformationItem)), true);
00149 Q_ASSERT((*(DUChainBaseData*)(((char*)item) + sizeof(EnvironmentInformationItem))).m_range == m_file->d_func()->m_range);
00150 Q_ASSERT((*(DUChainBaseData*)(((char*)item) + sizeof(EnvironmentInformationItem))).classId == m_file->d_func()->classId);
00151 Q_ASSERT((*(DUChainBaseData*)(((char*)item) + sizeof(EnvironmentInformationItem))).m_dynamic == false);
00152 }
00153
00154 static void destroy(EnvironmentInformationItem* item, KDevelop::AbstractItemRepository&) {
00155 item->~EnvironmentInformationItem();
00156
00157
00158
00159 }
00160
00161 static bool persistent(const EnvironmentInformationItem* ) {
00162
00163 return true;
00164 }
00165
00166 bool equals(const EnvironmentInformationItem* item) const {
00167 return m_index == item->m_topContext;
00168 }
00169
00170 const ParsingEnvironmentFile* m_file;
00171 uint m_index;
00172 };
00173
00175 class EnvironmentInformationListItem {
00176 public:
00177 EnvironmentInformationListItem() {
00178 initializeAppendedLists(true);
00179 }
00180
00181 EnvironmentInformationListItem(const EnvironmentInformationListItem& rhs, bool dynamic = true) {
00182 initializeAppendedLists(dynamic);
00183 m_file = rhs.m_file;
00184 copyListsFrom(rhs);
00185 }
00186
00187 ~EnvironmentInformationListItem() {
00188 freeAppendedLists();
00189 }
00190
00191 unsigned int hash() const {
00192
00193
00194 return m_file.hash();
00195 }
00196
00197 unsigned short int itemSize() const {
00198 return dynamicSize();
00199 }
00200
00201 IndexedString m_file;
00202
00203 uint classSize() const {
00204 return sizeof(*this);
00205 }
00206
00207 START_APPENDED_LISTS(EnvironmentInformationListItem);
00209 APPENDED_LIST_FIRST(EnvironmentInformationListItem, uint, items);
00210 END_APPENDED_LISTS(EnvironmentInformationListItem, items);
00211 };
00212
00213 class EnvironmentInformationListRequest {
00214 public:
00215
00217 EnvironmentInformationListRequest(const IndexedString& file) : m_file(file), m_item(0) {
00218 }
00220 EnvironmentInformationListRequest(const IndexedString& file, const EnvironmentInformationListItem& item) : m_file(file), m_item(&item) {
00221 }
00222
00223 enum {
00224 AverageSize = 160
00225 };
00226
00227 unsigned int hash() const {
00228 return m_file.hash();
00229 }
00230
00231 size_t itemSize() const {
00232 return m_item->itemSize();
00233 }
00234
00235 void createItem(EnvironmentInformationListItem* item) const {
00236 Q_ASSERT(m_item->m_file == m_file);
00237 new (item) EnvironmentInformationListItem(*m_item, false);
00238 }
00239
00240 static void destroy(EnvironmentInformationListItem* item, KDevelop::AbstractItemRepository&) {
00241 item->~EnvironmentInformationListItem();
00242 }
00243
00244 static bool persistent(const EnvironmentInformationListItem*) {
00245
00246 return true;
00247 }
00248
00249 bool equals(const EnvironmentInformationListItem* item) const {
00250 return m_file == item->m_file;
00251 }
00252
00253 IndexedString m_file;
00254 const EnvironmentInformationListItem* m_item;
00255 };
00256
00257 class DUChainPrivate;
00258 static DUChainPrivate* duChainPrivateSelf = 0;
00259 class DUChainPrivate
00260 {
00261 class CleanupThread : public QThread {
00262 public:
00263 CleanupThread(DUChainPrivate* data) : m_stopRunning(false), m_data(data) {
00264 }
00265
00266 void stopThread() {
00267 m_waitMutex.lock();
00268 m_stopRunning = true;
00269 m_wait.wakeAll();
00270 m_waitMutex.unlock();
00271 wait();
00272 }
00273
00274 private:
00275 void run() {
00276 while(1) {
00277 m_waitMutex.lock();
00278 if(m_stopRunning)
00279 break;
00280 m_wait.wait(&m_waitMutex, 1000 * cleanupEverySeconds);
00281 m_waitMutex.unlock();
00282 if(m_stopRunning)
00283 break;
00284
00285
00286 ModificationRevisionSet::clearCache();
00287
00288 m_data->doMoreCleanup(SOFT_CLEANUP_STEPS);
00289 if(m_stopRunning)
00290 break;
00291 }
00292 }
00293 bool m_stopRunning;
00294 QWaitCondition m_wait;
00295 QMutex m_waitMutex;
00296 DUChainPrivate* m_data;
00297 };
00298 public:
00299 DUChainPrivate() : m_chainsMutex(QMutex::Recursive), instance(0), m_cleanupDisabled(false), m_destroyed(false), m_environmentListInfo("Environment Lists"), m_environmentInfo("Environment Information")
00300 {
00301 #if defined(TEST_NO_CLEANUP)
00302 m_cleanupDisabled = true;
00303 #endif
00304
00305 m_chainsByIndex.set_empty_key(0);
00306 m_chainsByIndex.set_deleted_key(0xffffffff);
00307 duChainPrivateSelf = this;
00308 qRegisterMetaType<DUChainBasePointer>("KDevelop::DUChainBasePointer");
00309 qRegisterMetaType<DUContextPointer>("KDevelop::DUContextPointer");
00310 qRegisterMetaType<TopDUContextPointer>("KDevelop::TopDUContextPointer");
00311 qRegisterMetaType<DeclarationPointer>("KDevelop::DeclarationPointer");
00312 qRegisterMetaType<FunctionDeclarationPointer>("KDevelop::FunctionDeclarationPointer");
00313 qRegisterMetaType<KDevelop::IndexedString>("KDevelop::IndexedString");
00314 qRegisterMetaType<KDevelop::IndexedTopDUContext>("KDevelop::IndexedTopDUContext");
00315 qRegisterMetaType<KDevelop::ReferencedTopDUContext>("KDevelop::ReferencedTopDUContext");
00316
00317 notifier = new DUChainObserver();
00318 instance = new DUChain();
00319 m_cleanup = new CleanupThread(this);
00320 m_cleanup->start();
00321
00322 duChainDeleted = false;
00323
00324 {
00326 QFile f(globalItemRepositoryRegistry().path() + "/parsing_environment_data");
00327 bool opened = f.open(QIODevice::ReadOnly);
00328 ParsingEnvironmentFile::m_staticData = (StaticParsingEnvironmentData*) new char[sizeof(StaticParsingEnvironmentData)];
00329 if(opened) {
00330 kDebug() << "reading parsing-environment static data";
00331
00332 f.read((char*)ParsingEnvironmentFile::m_staticData, sizeof(StaticParsingEnvironmentData));
00333 }else{
00334 kDebug() << "creating new parsing-environment static data";
00335
00336 new (ParsingEnvironmentFile::m_staticData) StaticParsingEnvironmentData();
00337 }
00338 }
00339 }
00340 ~DUChainPrivate() {
00341 duChainDeleted = true;
00342 m_cleanup->stopThread();
00343 delete m_cleanup;
00344 delete instance;
00345 }
00346
00347 void clear() {
00348
00349 if(!m_cleanupDisabled)
00350 doMoreCleanup();
00351
00352 QMutexLocker l(&m_chainsMutex);
00353
00354 DUChainWriteLocker writeLock(DUChain::lock());
00355
00356 for(google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::const_iterator it = m_chainsByIndex.begin(); it != m_chainsByIndex.end(); ++it)
00357 removeDocumentChainFromMemory((*it).second);
00358
00359 m_indexEnvironmentInformations.clear();
00360 m_fileEnvironmentInformations.clear();
00361
00362 Q_ASSERT(m_fileEnvironmentInformations.isEmpty());
00363 Q_ASSERT(m_chainsByUrl.isEmpty());
00364 Q_ASSERT(m_chainsByIndex.empty());
00365 }
00366
00369 void removeDocumentChainFromMemory(TopDUContext* context) {
00370 QMutexLocker l(&m_chainsMutex);
00371
00372 {
00373 QMutexLocker l(&m_referenceCountsMutex);
00374
00375 if(m_referenceCounts.contains(context)) {
00376
00377 kDebug() << "removed a top-context that was reference-counted:" << context->url().str() << context->ownIndex();
00378 m_referenceCounts.remove(context);
00379 }
00380 }
00381
00382 uint index = context->ownIndex();
00383
00384
00385 google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::iterator it = m_chainsByIndex.find(index);
00386
00387 Q_ASSERT(it != m_chainsByIndex.end());
00388 m_chainsByUrl.remove(context->url(), context);
00389
00390 if (context->smartRange())
00391 ICore::self()->languageController()->backgroundParser()->removeManagedTopRange(context->smartRange());
00392
00393 if(!context->isOnDisk())
00394 instance->removeFromEnvironmentManager(context);
00395
00396 l.unlock();
00397
00398 context->deleteSelf();
00399 l.relock();
00400 it = m_chainsByIndex.find(index);
00401 Q_ASSERT(it != m_chainsByIndex.end());
00402 m_chainsByIndex.erase(it);
00403
00404 Q_ASSERT(m_chainsByIndex.find(index) == m_chainsByIndex.end());
00405 }
00406
00409 QMutex m_chainsMutex;
00410
00411 CleanupThread* m_cleanup;
00412
00413 DUChain* instance;
00414 DUChainLock lock;
00415 QMultiMap<IndexedString, TopDUContext*> m_chainsByUrl;
00416 google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash> m_chainsByIndex;
00417
00418
00419 QMutex m_referenceCountsMutex;
00420 QHash<TopDUContext*, uint> m_referenceCounts;
00421
00422 DUChainObserver* notifier;
00423 Definitions m_definitions;
00424 Uses m_uses;
00425 QSet<uint> m_loading;
00426 bool m_cleanupDisabled;
00427
00429 QSet<ReferencedTopDUContext> m_openDocumentContexts;
00430
00431 bool m_destroyed;
00432
00435 void addEnvironmentInformation(ParsingEnvironmentFilePointer info) {
00436 Q_ASSERT(!findInformation(info->indexedTopContext().index()));
00437 Q_ASSERT(m_environmentInfo.findIndex(info->indexedTopContext().index()) == 0);
00438
00439 QMutexLocker lock(&m_chainsMutex);
00440 m_fileEnvironmentInformations.insert(info->url(), info);
00441
00442 m_indexEnvironmentInformations.insert(info->indexedTopContext().index(), info);
00443
00444 Q_ASSERT(info->d_func()->classId);
00445 }
00446
00449 void removeEnvironmentInformation(ParsingEnvironmentFilePointer info) {
00450
00451 info->makeDynamic();
00452
00453 m_chainsMutex.lock();
00454 bool removed = m_fileEnvironmentInformations.remove(info->url(), info);
00455
00456 bool removed2 = m_indexEnvironmentInformations.remove(info->indexedTopContext().index());
00457
00458 m_chainsMutex.unlock();
00459
00460 {
00461
00462 QMutexLocker lock(m_environmentListInfo.mutex());
00463 uint index = m_environmentListInfo.findIndex(info->url());
00464
00465 if(index) {
00466 EnvironmentInformationListItem item(*m_environmentListInfo.itemFromIndex(index));
00467 if(item.itemsList().removeOne(info->indexedTopContext().index())) {
00468 m_environmentListInfo.deleteItem(index);
00469 if(!item.itemsList().isEmpty())
00470 m_environmentListInfo.index(EnvironmentInformationListRequest(info->url(), item));
00471 }
00472 }
00473 }
00474
00475 QMutexLocker lock(m_environmentInfo.mutex());
00476 uint index = m_environmentInfo.findIndex(info->indexedTopContext().index());
00477 if(index) {
00478 m_environmentInfo.deleteItem(index);
00479 }
00480
00481 Q_ASSERT(index || (removed && removed2));
00482 Q_ASSERT(!findInformation(info->indexedTopContext().index()));
00483 }
00484
00486 QList<ParsingEnvironmentFilePointer> getEnvironmentInformation(IndexedString url) {
00487 QList<ParsingEnvironmentFilePointer> ret;
00488 uint listIndex = m_environmentListInfo.findIndex(url);
00489
00490 if(listIndex) {
00491 KDevVarLengthArray<uint> topContextIndices;
00492
00493 {
00494
00495
00496 QMutexLocker lock(m_environmentListInfo.mutex());
00497 const EnvironmentInformationListItem* item = m_environmentListInfo.itemFromIndex(listIndex);
00498 FOREACH_FUNCTION(uint topContextIndex, item->items)
00499 topContextIndices << topContextIndex;
00500 }
00501
00502
00503
00504 FOREACH_ARRAY(uint topContextIndex, topContextIndices) {
00505 KSharedPtr< ParsingEnvironmentFile > p = ParsingEnvironmentFilePointer(loadInformation(topContextIndex));
00506 if(p) {
00507 ret << p;
00508 }else{
00509 kDebug() << "Failed to load enviromment-information for" << TopDUContextDynamicData::loadUrl(topContextIndex).str();
00510 }
00511 }
00512 }
00513
00514 QMutexLocker l(&m_chainsMutex);
00515
00516
00517 foreach(ParsingEnvironmentFilePointer file, m_fileEnvironmentInformations.values(url))
00518 if(!ret.contains(file))
00519 ret << file;
00520
00521 return ret;
00522 }
00523
00526 void loadChain(uint index, QSet<uint>& loaded) {
00527
00528 QMutexLocker l(&m_chainsMutex);
00529
00530 if(m_chainsByIndex.find(index) == m_chainsByIndex.end()) {
00531 if(m_loading.contains(index)) {
00532
00533 while(m_loading.contains(index)) {
00534 l.unlock();
00535 kDebug() << "waiting for another thread to load index" << index;
00536 usleep(50000);
00537 l.relock();
00538 }
00539 loaded.insert(index);
00540 return;
00541 }
00542 m_loading.insert(index);
00543 loaded.insert(index);
00544
00545 l.unlock();
00546 kDebug() << "loading top-context" << index;
00547 TopDUContext* chain = TopDUContextDynamicData::load(index);
00548 if(chain) {
00549 chain->setParsingEnvironmentFile(loadInformation(chain->ownIndex()));
00550
00551 if(!chain->usingImportsCache()) {
00552
00553 foreach(const DUContext::Import &import, chain->DUContext::importedParentContexts()) {
00554 if(!loaded.contains(import.topContextIndex())) {
00555 loadChain(import.topContextIndex(), loaded);
00556 }
00557 }
00558 }
00559 chain->rebuildDynamicImportStructure();
00560
00561 chain->setInDuChain(true);
00562 instance->addDocumentChain(chain);
00563 }
00564
00565 l.relock();
00566 m_loading.remove(index);
00567 }
00568 }
00569
00570
00574 void storeAllInformation(bool atomic, DUChainWriteLocker& locker) {
00575
00576 uint cnt = 0;
00577
00578 QList<IndexedString> urls;
00579 {
00580 QMutexLocker lock(&m_chainsMutex);
00581 urls += m_fileEnvironmentInformations.keys();
00582 }
00583
00584 foreach(const IndexedString &url, urls) {
00585 QList<ParsingEnvironmentFilePointer> check;
00586 {
00587 QMutexLocker lock(&m_chainsMutex);
00588 check = m_fileEnvironmentInformations.values(url);
00589 }
00590
00591 foreach(ParsingEnvironmentFilePointer file, check) {
00592
00593 EnvironmentInformationRequest req(file.data());
00594 QMutexLocker lock(m_environmentInfo.mutex());
00595 uint index = m_environmentInfo.findIndex(req);
00596
00597 if(file->d_func()->isDynamic()) {
00598
00599
00600
00601 if(index)
00602 m_environmentInfo.deleteItem(index);
00603
00604
00605 index = m_environmentInfo.index(req);
00606 Q_ASSERT(index);
00607
00608 EnvironmentInformationItem* item = const_cast<EnvironmentInformationItem*>(m_environmentInfo.itemFromIndex(index));
00609 DUChainBaseData* theData = (DUChainBaseData*)(((char*)item) + sizeof(EnvironmentInformationItem));
00610 static DUChainBaseData* dataCopy;
00611 dataCopy = theData;
00612
00613 Q_ASSERT(theData->m_range == file->d_func()->m_range);
00614 Q_ASSERT(theData->m_dynamic == false);
00615 Q_ASSERT(theData->classId == file->d_func()->classId);
00616
00617 file->setData( theData );
00618
00619 ++cnt;
00620 }else{
00621 m_environmentInfo.itemFromIndex(index);
00622 }
00623 }
00624
00627 if(!atomic && (cnt % 100 == 0)) {
00628
00629 locker.unlock();
00630 locker.lock();
00631 }
00632
00633 storeInformationList(url);
00634
00635
00636 uint index = m_environmentListInfo.findIndex(EnvironmentInformationListRequest(url));
00637 if(index) {
00638 m_environmentListInfo.itemFromIndex(index);
00639 }else{
00640 QMutexLocker lock(&m_chainsMutex);
00641 kDebug(9505) << "Did not find stored item for" << url.str() << "count:" << m_fileEnvironmentInformations.values(url);
00642 }
00643 if(!atomic) {
00644 locker.unlock();
00645 locker.lock();
00646 }
00647 }
00648 }
00649
00650 QMutex& cleanupMutex() {
00651 static QMutex mutex(QMutex::Recursive);
00652 return mutex;
00653 }
00654
00659 void doMoreCleanup(int retries = 0, bool needLockRepository = true) {
00660
00661 if(m_cleanupDisabled)
00662 return;
00663
00664
00665 QMutexLocker lockCleanupMutex(&cleanupMutex());
00666
00667 if(m_destroyed || m_cleanupDisabled)
00668 return;
00669
00670 Q_ASSERT(!instance->lock()->currentThreadHasReadLock() && !instance->lock()->currentThreadHasWriteLock());
00671 DUChainWriteLocker writeLock(instance->lock());
00672 PersistentSymbolTable::self().clearCache();
00673
00674
00675
00676 QList<ILanguage*> lockedParseMutexes;
00677
00678 QList<QReadWriteLock*> locked;
00679
00680 if(needLockRepository) {
00681
00682 if (ICore* core = ICore::self())
00683 if (ILanguageController* lc = core->languageController())
00684 lockedParseMutexes = lc->loadedLanguages();
00685
00686 writeLock.unlock();
00687
00688
00689 foreach(ILanguage* language, lockedParseMutexes) {
00690 language->parseLock()->lockForWrite();
00691 locked << language->parseLock();
00692 }
00693
00694 writeLock.lock();
00695
00696 globalItemRepositoryRegistry().lockForWriting();
00697 kDebug(9505) << "starting cleanup";
00698 }
00699
00700 QTime startTime = QTime::currentTime();
00701
00702 storeAllInformation(!retries, writeLock);
00703
00704
00705 QSet<TopDUContext*> workOnContexts;
00706
00707 {
00708 QMutexLocker l(&m_chainsMutex);
00709
00710 for(google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::const_iterator it = m_chainsByIndex.begin(); it != m_chainsByIndex.end(); ++it)
00711 workOnContexts << (*it).second;
00712 }
00713
00714 foreach(TopDUContext* context, workOnContexts) {
00715
00716 context->m_dynamicData->store();
00717
00718 if(retries) {
00719
00720 writeLock.unlock();
00721
00722 usleep(500);
00723 writeLock.lock();
00724 }
00725 }
00726
00727
00728
00729 QSet<IndexedString> unloadedNames;
00730 bool unloadedOne = true;
00731
00732 bool unloadAllUnreferenced = !retries;
00733
00734
00735
00736
00737
00738 while(unloadedOne) {
00739 unloadedOne = false;
00740 int hadUnloadable = 0;
00741
00742 unloadContexts:
00743
00744 foreach(TopDUContext* unload, workOnContexts) {
00745
00746 bool hasReference = false;
00747
00748 {
00749 QMutexLocker l(&m_referenceCountsMutex);
00750
00751 foreach(TopDUContext* context, m_referenceCounts.keys()) {
00752 if(context == unload || context->imports(unload, SimpleCursor())) {
00753 workOnContexts.remove(unload);
00754 hasReference = true;
00755 }
00756 }
00757 }
00758
00759 if(!hasReference)
00760 ++hadUnloadable;
00761 else
00762 continue;
00763
00764 bool isImportedByLoaded = !unload->loadedImporters().isEmpty();
00765
00766
00767 if(isImportedByLoaded && !unloadAllUnreferenced)
00768 continue;
00769
00770 unloadedNames.insert(unload->url());
00771
00772
00773 unload->m_dynamicData->store();
00774 Q_ASSERT(!unload->d_func()->m_dynamic);
00775 removeDocumentChainFromMemory(unload);
00776 workOnContexts.remove(unload);
00777 unloadedOne = true;
00778
00779 if(!unloadAllUnreferenced) {
00780
00781 writeLock.unlock();
00782
00783 usleep(500);
00784 writeLock.lock();
00785 }
00786 }
00787 if(hadUnloadable && !unloadedOne) {
00788 Q_ASSERT(!unloadAllUnreferenced);
00789
00790 kDebug(9505) << "found" << hadUnloadable << "unloadable contexts, but could not unload separately. Unloading atomically.";
00791 unloadAllUnreferenced = true;
00792 hadUnloadable = 0;
00793 goto unloadContexts;
00794 }
00795 }
00796
00797
00798 if(retries == 0) {
00799 QMutexLocker lock(&m_chainsMutex);
00800
00801 for(QMultiMap<IndexedString, ParsingEnvironmentFilePointer>::iterator it = m_fileEnvironmentInformations.begin(); it != m_fileEnvironmentInformations.end(); ) {
00802 ParsingEnvironmentFile* f = (*it).data();
00803 Q_ASSERT(f->d_func()->classId);
00804 if(f->ref == 1) {
00805 Q_ASSERT(!f->d_func()->isDynamic());
00806
00807
00809 it = m_fileEnvironmentInformations.erase(it);
00810 }else{
00811 ++it;
00812 }
00813 }
00814 }
00815
00816 if(retries)
00817 writeLock.unlock();
00818
00819
00820 globalItemRepositoryRegistry().store();
00821
00822 {
00823
00825 Q_ASSERT(ParsingEnvironmentFile::m_staticData);
00826 QFile f(globalItemRepositoryRegistry().path() + "/parsing_environment_data");
00827 bool opened = f.open(QIODevice::WriteOnly);
00828 Q_ASSERT(opened);
00829 f.write((char*)ParsingEnvironmentFile::m_staticData, sizeof(StaticParsingEnvironmentData));
00830 }
00831
00832 if(retries) {
00833 doMoreCleanup(retries-1, false);
00834 writeLock.lock();
00835 }
00836
00837 if(needLockRepository) {
00838 globalItemRepositoryRegistry().unlockForWriting();
00839
00840 int elapsedSeconds = startTime.secsTo(QTime::currentTime());
00841 kDebug(9505) << "seconds spent doing cleanup: " << elapsedSeconds << "top-contexts still open:" << m_chainsByIndex.size();;
00842 }
00843 if(!retries) {
00844 int elapesedMilliSeconds = startTime.msecsTo(QTime::currentTime());
00845 kDebug(9505) << "milliseconds spent doing cleanup with locked duchain: " << elapesedMilliSeconds;
00846 }
00847
00848 foreach(QReadWriteLock* lock, locked)
00849 lock->unlock();
00850 }
00851
00853 ParsingEnvironmentFile* findInformation(uint topContextIndex) {
00854 QMutexLocker lock(&m_chainsMutex);
00855 QHash<uint, ParsingEnvironmentFilePointer>::iterator it = m_indexEnvironmentInformations.find(topContextIndex);
00856 if(it != m_indexEnvironmentInformations.end())
00857 return (*it).data();
00858 return 0;
00859 }
00860
00864 ParsingEnvironmentFile* loadInformation(uint topContextIndex) {
00865
00866 ParsingEnvironmentFile* alreadyLoaded = findInformation(topContextIndex);
00867 if(alreadyLoaded)
00868 return alreadyLoaded;
00869
00870
00871 uint dataIndex = m_environmentInfo.findIndex(EnvironmentInformationRequest(topContextIndex));
00872 if(!dataIndex) {
00873
00874 return 0;
00875 }
00876
00877 const EnvironmentInformationItem& item(*m_environmentInfo.itemFromIndex(dataIndex));
00878
00879 QMutexLocker lock(&m_chainsMutex);
00880
00881
00882 alreadyLoaded = findInformation(topContextIndex);
00883 if(alreadyLoaded)
00884 return alreadyLoaded;
00885
00886 ParsingEnvironmentFile* ret = dynamic_cast<ParsingEnvironmentFile*>(DUChainItemSystem::self().create( (DUChainBaseData*)(((char*)&item) + sizeof(EnvironmentInformationItem)) ));
00887 if(ret) {
00888 Q_ASSERT(ret->d_func()->classId);
00889 Q_ASSERT(ret->indexedTopContext().index() == topContextIndex);
00890 ParsingEnvironmentFilePointer retPtr(ret);
00891
00892 m_fileEnvironmentInformations.insert(ret->url(), retPtr);
00893
00894 Q_ASSERT(!m_indexEnvironmentInformations.contains(ret->indexedTopContext().index()));
00895 m_indexEnvironmentInformations.insert(ret->indexedTopContext().index(), retPtr);
00896 }
00897 return ret;
00898 }
00899
00900 struct CleanupListVisitor {
00901 QList<uint> checkContexts;
00902 bool operator()(const EnvironmentInformationItem* item) {
00903 checkContexts << item->m_topContext;
00904 return true;
00905 }
00906 };
00907
00909 void cleanupTopContexts() {
00910 DUChainWriteLocker lock( DUChain::lock() );
00911 kDebug() << "cleaning top-contexts";
00912 CleanupListVisitor visitor;
00913 uint startPos = 0;
00914 m_environmentInfo.visitAllItems(visitor);
00915
00916 int checkContextsCount = maxFinalCleanupCheckContexts;
00917 int percentageOfContexts = (visitor.checkContexts.size() * 100) / minimumFinalCleanupCheckContextsPercentage;
00918
00919 if(checkContextsCount < percentageOfContexts)
00920 checkContextsCount = percentageOfContexts;
00921
00922 if(visitor.checkContexts.size() > (int)checkContextsCount)
00923 startPos = qrand() % (visitor.checkContexts.size() - checkContextsCount);
00924
00925 int endPos = startPos + maxFinalCleanupCheckContexts;
00926 if(endPos > visitor.checkContexts.size())
00927 endPos = visitor.checkContexts.size();
00928 QSet< uint > check;
00929 for(int a = startPos; a < endPos && check.size() < checkContextsCount; ++a)
00930 if(check.size() < checkContextsCount)
00931 addContextsForRemoval(check, IndexedTopDUContext(visitor.checkContexts[a]));
00932
00933 foreach(uint topIndex, check) {
00934 IndexedTopDUContext top(topIndex);
00935 if(top.data()) {
00936 kDebug() << "removing top-context for" << top.data()->url().str() << "because it is out of date";
00937 instance->removeDocumentChain(top.data());
00938 }
00939 }
00940 kDebug() << "check ready";
00941 }
00942
00943 private:
00944
00945 void addContextsForRemoval(QSet<uint>& topContexts, IndexedTopDUContext top) {
00946 if(topContexts.contains(top.index()))
00947 return;
00948
00949 KSharedPtr<ParsingEnvironmentFile> info( instance->environmentFileForDocument(top) );
00951 if(info && info->needsUpdate()) {
00952
00953 }else{
00954 return;
00955 }
00956
00957 topContexts.insert(top.index());
00958
00959 if(info) {
00960
00961 QList< KSharedPtr<ParsingEnvironmentFile> > importers = info->importers();
00962
00963 QSet< KSharedPtr<ParsingEnvironmentFile> > checkNext;
00964
00965
00966
00967 for(QList< KSharedPtr<ParsingEnvironmentFile> >::iterator it = importers.begin(); it != importers.end(); ++it) {
00968 IndexedTopDUContext c = (*it)->indexedTopContext();
00969 if(!topContexts.contains(c.index())) {
00970 topContexts.insert(c.index());
00971 checkNext.insert(*it);
00972 }
00973 }
00974
00975 for(QSet< KSharedPtr<ParsingEnvironmentFile> >::const_iterator it = checkNext.begin(); it != checkNext.end(); ++it) {
00976 topContexts.remove((*it)->indexedTopContext().index());
00977 addContextsForRemoval(topContexts, (*it)->indexedTopContext());
00978 }
00979 }
00980 }
00981
00982 template<class Entry>
00983 bool listContains(const Entry entry, const Entry* list, uint listSize) {
00984 for(uint a = 0; a < listSize; ++a)
00985 if(list[a] == entry)
00986 return true;
00987 return false;
00988 }
00989
00991 void storeInformationList(IndexedString url) {
00992
00993 QMutexLocker lock(m_environmentListInfo.mutex());
00994
00995 EnvironmentInformationListItem newItem;
00996 newItem.m_file = url;
00997
00998 QSet<uint> newItems;
00999
01000 {
01001 QMutexLocker lock(&m_chainsMutex);
01002 QMultiMap<IndexedString, ParsingEnvironmentFilePointer>::iterator start = m_fileEnvironmentInformations.lowerBound(url);
01003 QMultiMap<IndexedString, ParsingEnvironmentFilePointer>::iterator end = m_fileEnvironmentInformations.upperBound(url);
01004
01005 for(QMultiMap<IndexedString, ParsingEnvironmentFilePointer>::iterator it = start; it != end; ++it) {
01006 uint topContextIndex = (*it)->indexedTopContext().index();
01007 newItems.insert(topContextIndex);
01008 newItem.itemsList().append(topContextIndex);
01009 }
01010 }
01011
01012 uint index = m_environmentListInfo.findIndex(url);
01013
01014 if(index) {
01015
01016
01017
01018 const EnvironmentInformationListItem* item = m_environmentListInfo.itemFromIndex(index);
01019 QSet<uint> oldItems;
01020 FOREACH_FUNCTION(uint topContextIndex, item->items) {
01021 oldItems.insert(topContextIndex);
01022 if(!newItems.contains(topContextIndex)) {
01023 newItems.insert(topContextIndex);
01024 newItem.itemsList().append(topContextIndex);
01025 }
01026 }
01027
01028 if(oldItems == newItems)
01029 return;
01030
01032 m_environmentListInfo.deleteItem(index);
01033 }
01034
01035 Q_ASSERT(m_environmentListInfo.findIndex(EnvironmentInformationListRequest(url)) == 0);
01036
01037
01038 m_environmentListInfo.index(EnvironmentInformationListRequest(url, newItem));
01039
01040 Q_ASSERT(m_environmentListInfo.findIndex(EnvironmentInformationListRequest(url)));
01041 }
01042
01043
01044 QMultiMap<IndexedString, ParsingEnvironmentFilePointer> m_fileEnvironmentInformations;
01045 QHash<uint, ParsingEnvironmentFilePointer> m_indexEnvironmentInformations;
01046
01050 ItemRepository<EnvironmentInformationListItem, EnvironmentInformationListRequest> m_environmentListInfo;
01052 ItemRepository<EnvironmentInformationItem, EnvironmentInformationRequest> m_environmentInfo;
01053 };
01054
01055 K_GLOBAL_STATIC(DUChainPrivate, sdDUChainPrivate)
01056
01057
01058 DUChain::DUChain()
01059 {
01060 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit()));
01061
01062 connect(EditorIntegrator::notifier(), SIGNAL(documentAboutToBeDeleted(KTextEditor::Document*)), SLOT(documentAboutToBeDeleted(KTextEditor::Document*)));
01063 connect(EditorIntegrator::notifier(), SIGNAL(documentAboutToBeDeletedFinal(KTextEditor::Document*)), SLOT(documentAboutToBeDeletedFinal(KTextEditor::Document*)));
01064 if(ICore::self()) {
01065 Q_ASSERT(ICore::self()->documentController());
01066 connect(ICore::self()->documentController(), SIGNAL(documentLoadedPrepare(KDevelop::IDocument*)), this, SLOT(documentLoadedPrepare(KDevelop::IDocument*)));
01067 connect(ICore::self()->documentController(), SIGNAL(documentUrlChanged(KDevelop::IDocument*)), this, SLOT(documentRenamed(KDevelop::IDocument*)));
01068 connect(ICore::self()->documentController(), SIGNAL(documentActivated(KDevelop::IDocument*)), this, SLOT(documentActivated(KDevelop::IDocument*)));
01069 }
01070 }
01071
01072 DUChain::~DUChain()
01073 {
01074 duChainDeleted = true;
01075 }
01076
01077 DUChain* DUChain::self()
01078 {
01079 return sdDUChainPrivate->instance;
01080 }
01081
01082 DUChainLock* DUChain::lock()
01083 {
01084 return &sdDUChainPrivate->lock;
01085 }
01086
01087 QList<TopDUContext*> DUChain::allChains() const
01088 {
01089 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01090 QList<TopDUContext*> ret;
01091 for(google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::const_iterator it = sdDUChainPrivate->m_chainsByIndex.begin(); it != sdDUChainPrivate->m_chainsByIndex.end(); ++it)
01092 ret << (*it).second;
01093
01094 return ret;
01095 }
01096
01097 void DUChain::updateContextEnvironment( TopDUContext* context, ParsingEnvironmentFile* file ) {
01098
01099 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01100
01101 removeFromEnvironmentManager( context );
01102
01103 context->setParsingEnvironmentFile( file );
01104
01105 addToEnvironmentManager( context );
01106
01107 branchModified(context);
01108 }
01109
01110 void DUChain::removeDocumentChain( TopDUContext* context )
01111 {
01112 ENSURE_CHAIN_WRITE_LOCKED;
01113 IndexedTopDUContext indexed(context->indexed());
01114 Q_ASSERT(indexed.data() == context);
01115 branchRemoved(context);
01116 context->m_dynamicData->deleteOnDisk();
01117 Q_ASSERT(indexed.data() == context);
01118 sdDUChainPrivate->removeDocumentChainFromMemory(context);
01119 Q_ASSERT(!indexed.data());
01120 Q_ASSERT(!environmentFileForDocument(indexed));
01121 }
01122
01123 void DUChain::addDocumentChain( TopDUContext * chain )
01124 {
01125 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01126
01127
01128 Q_ASSERT(chain);
01129 if (chain->smartRange()) {
01130 Q_ASSERT(!chain->smartRange()->parentRange());
01131 ICore::self()->languageController()->backgroundParser()->addManagedTopRange(KUrl(chain->url().str()), chain->smartRange());
01132 }
01133
01134 Q_ASSERT(sdDUChainPrivate->m_chainsByIndex.find(chain->ownIndex()) == sdDUChainPrivate->m_chainsByIndex.end());
01135
01136 sdDUChainPrivate->m_chainsByIndex.insert(std::make_pair(chain->ownIndex(), chain));
01137 sdDUChainPrivate->m_chainsByUrl.insert(chain->url(), chain);
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152 chain->setInDuChain(true);
01153
01154 l.unlock();
01155
01156 addToEnvironmentManager(chain);
01157
01158
01159
01160 KTextEditor::Document* doc = EditorIntegrator::documentForUrl(chain->url());
01161 if(doc) {
01162
01163 ReferencedTopDUContext ctx(chain);
01164 sdDUChainPrivate->m_openDocumentContexts.insert(ctx);
01165 }
01166
01167 branchAdded(chain);
01168 }
01169
01170 void DUChain::addToEnvironmentManager( TopDUContext * chain ) {
01171
01172 ParsingEnvironmentFilePointer file = chain->parsingEnvironmentFile();
01173 if( !file )
01174 return;
01175
01176 Q_ASSERT(file->indexedTopContext().index() == chain->ownIndex());
01177
01178 if(ParsingEnvironmentFile* alreadyHave = sdDUChainPrivate->findInformation(file->indexedTopContext().index()))
01179 {
01182 Q_ASSERT(alreadyHave == file.data());
01183 return;
01184 }
01185
01186 sdDUChainPrivate->addEnvironmentInformation(file);
01187 }
01188
01189 void DUChain::removeFromEnvironmentManager( TopDUContext * chain ) {
01190
01191 ParsingEnvironmentFilePointer file = chain->parsingEnvironmentFile();
01192 if( !file )
01193 return;
01194
01195 sdDUChainPrivate->removeEnvironmentInformation(file);
01196 }
01197
01198 TopDUContext* DUChain::chainForDocument(const KUrl& document) const {
01199 return chainForDocument(IndexedString(document.pathOrUrl()));
01200 }
01201
01202 bool DUChain::isInMemory(uint topContextIndex) const {
01203 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01204
01205 google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::const_iterator it = sdDUChainPrivate->m_chainsByIndex.find(topContextIndex);
01206 return it != sdDUChainPrivate->m_chainsByIndex.end();
01207 }
01208
01209 IndexedString DUChain::urlForIndex(uint index) const {
01210 {
01211 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01212 google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::const_iterator it = sdDUChainPrivate->m_chainsByIndex.find(index);
01213 if(it != sdDUChainPrivate->m_chainsByIndex.end())
01214 return (*it).second->url();
01215 }
01216
01217 return TopDUContextDynamicData::loadUrl(index);
01218 }
01219
01220
01221 TopDUContext* DUChain::chainForIndex(uint index) const {
01222
01223 DUChainPrivate* p = (sdDUChainPrivate.operator->());
01224 if(p->m_destroyed)
01225 return 0;
01226
01227
01228 p->m_chainsMutex.lock();
01229
01230 google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::const_iterator it = p->m_chainsByIndex.find(index);
01231 if(it != p->m_chainsByIndex.end()) {
01232 TopDUContext* ret = (*it).second;
01233 p->m_chainsMutex.unlock();
01234 return ret;
01235 } else {
01236 p->m_chainsMutex.unlock();
01237 QSet<uint> loaded;
01238 p->loadChain(index, loaded);
01239 p->m_chainsMutex.lock();
01240
01241 it = p->m_chainsByIndex.find(index);
01242 if(it != p->m_chainsByIndex.end()) {
01243 TopDUContext* ret = (*it).second;
01244 p->m_chainsMutex.unlock();
01245 return ret;
01246 } else {
01247 p->m_chainsMutex.unlock();
01248 return 0;
01249 }
01250 }
01251 }
01252
01253 TopDUContext* DUChain::chainForDocument(const IndexedString& document) const
01254 {
01255 if(sdDUChainPrivate->m_destroyed)
01256 return 0;
01257
01258 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270 if(sdDUChainPrivate->m_chainsByUrl.contains(document))
01271 return *sdDUChainPrivate->m_chainsByUrl.find(document);
01272
01273
01274 l.unlock();
01275
01276 QList<ParsingEnvironmentFilePointer> list = sdDUChainPrivate->getEnvironmentInformation(document);
01277
01278 foreach(const ParsingEnvironmentFilePointer &file, list) {
01279 if(isInMemory(file->indexedTopContext().index()))
01280 return file->indexedTopContext().data();
01281 }
01282 if(!list.isEmpty())
01283 return list[0]->topContext();
01284
01285 return 0;
01286 }
01287
01288 QList<TopDUContext*> DUChain::chainsForDocument(const KUrl& document) const
01289 {
01290 return chainsForDocument(IndexedString(document));
01291 }
01292
01293 QList<TopDUContext*> DUChain::chainsForDocument(const IndexedString& document) const
01294 {
01295 QList<TopDUContext*> chains;
01296
01297 if(sdDUChainPrivate->m_destroyed)
01298 return chains;
01299
01300 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01301
01302
01303 for (QMultiMap<IndexedString, TopDUContext*>::Iterator it = sdDUChainPrivate->m_chainsByUrl.lowerBound(document); it != sdDUChainPrivate->m_chainsByUrl.end(); ++it) {
01304 if (it.key() == document)
01305 chains << it.value();
01306 else
01307 break;
01308 }
01309
01310 return chains;
01311 }
01312
01313 TopDUContext* DUChain::chainForDocument( const KUrl& document, const ParsingEnvironment* environment, bool onlyProxyContexts, bool noProxyContexts ) const {
01314 return chainForDocument( IndexedString(document), environment, onlyProxyContexts, noProxyContexts );
01315 }
01316
01317 ParsingEnvironmentFilePointer DUChain::environmentFileForDocument( const IndexedString& document, const ParsingEnvironment* environment, bool onlyProxyContexts, bool noProxyContexts ) const {
01318
01319 if(sdDUChainPrivate->m_destroyed)
01320 return ParsingEnvironmentFilePointer();
01321 QList< ParsingEnvironmentFilePointer> list = sdDUChainPrivate->getEnvironmentInformation(document);
01322
01323
01324
01325 QList< ParsingEnvironmentFilePointer>::const_iterator it = list.constBegin();
01326 while(it != list.constEnd()) {
01327 if(*it && (*it)->matchEnvironment(environment) && (!onlyProxyContexts || (*it)->isProxyContext()) && (!noProxyContexts || !(*it)->isProxyContext())) {
01328 return *it;
01329 }
01330 ++it;
01331 }
01332 return ParsingEnvironmentFilePointer();
01333 }
01334
01335 QList<ParsingEnvironmentFilePointer> DUChain::allEnvironmentFiles(const IndexedString& document) {
01336 return sdDUChainPrivate->getEnvironmentInformation(document);
01337 }
01338
01339 ParsingEnvironmentFilePointer DUChain::environmentFileForDocument(IndexedTopDUContext topContext) const {
01340 if(topContext.index() == 0)
01341 return ParsingEnvironmentFilePointer();
01342
01343 return ParsingEnvironmentFilePointer(sdDUChainPrivate->loadInformation(topContext.index()));
01344 }
01345
01346 TopDUContext* DUChain::chainForDocument( const IndexedString& document, const ParsingEnvironment* environment, bool onlyProxyContexts, bool noProxyContexts ) const {
01347
01348 if(sdDUChainPrivate->m_destroyed)
01349 return 0;
01350 ParsingEnvironmentFilePointer envFile = environmentFileForDocument(document, environment, onlyProxyContexts, noProxyContexts);
01351 if(envFile) {
01352 return envFile->topContext();
01353 }else{
01354 return 0;
01355 }
01356 }
01357
01358 DUChainObserver* DUChain::notifier()
01359 {
01360 return sdDUChainPrivate->notifier;
01361 }
01362
01363 void DUChain::branchAdded(DUContext* context)
01364 {
01365 emit sdDUChainPrivate->notifier->branchAdded(DUContextPointer(context));
01366 }
01367
01368 void DUChain::branchModified(DUContext* context)
01369 {
01370 emit sdDUChainPrivate->notifier->branchModified(DUContextPointer(context));
01371 }
01372
01373 void DUChain::branchRemoved(DUContext* context)
01374 {
01375 emit sdDUChainPrivate->notifier->branchRemoved(DUContextPointer(context));
01376 }
01377
01378 QList<KUrl> DUChain::documents() const
01379 {
01380 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01381
01382 QList<KUrl> ret;
01383 for(google::dense_hash_map<uint, TopDUContext*, ItemRepositoryIndexHash>::const_iterator it = sdDUChainPrivate->m_chainsByIndex.begin(); it != sdDUChainPrivate->m_chainsByIndex.end(); ++it) {
01384 ret << KUrl((*it).second->url().str());
01385 }
01386
01387 return ret;
01388 }
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401 void DUChain::documentActivated(KDevelop::IDocument* doc)
01402 {
01403 if(sdDUChainPrivate->m_destroyed)
01404 return;
01405
01406
01407 DUChainReadLocker lock( DUChain::lock() );
01408 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01409 TopDUContext* ctx = DUChainUtils::standardContextForUrl(doc->url());
01410 if(ctx && ctx->parsingEnvironmentFile())
01411 if(ctx->parsingEnvironmentFile()->needsUpdate())
01412 ICore::self()->languageController()->backgroundParser()->addDocument(doc->url());
01413 }
01414
01415 static void deconvertDUChainInternal(DUContext* context)
01416 {
01417 foreach (Declaration* dec, context->localDeclarations())
01418 dec->clearSmartRange();
01419
01420 context->clearUseSmartRanges();
01421
01422 foreach (DUContext* child, context->childContexts())
01423 deconvertDUChainInternal(child);
01424
01425 context->clearSmartRange();
01426 }
01427
01428 void DUChain::documentAboutToBeDeletedFinal(KTextEditor::Document* doc)
01429 {
01430 if(sdDUChainPrivate->m_destroyed)
01431 return;
01432
01433 QList<TopDUContext*> chains = chainsForDocument(doc->url());
01434
01435 KTextEditor::SmartInterface* smart = dynamic_cast<KTextEditor::SmartInterface*>(doc);
01436 if(!smart)
01437 return;
01438
01439 foreach (TopDUContext* top, chains) {
01440
01441 QMutexLocker lockSmart(smart->smartMutex());
01442
01443 deconvertDUChainInternal(top);
01444 }
01445 }
01446
01447 void DUChain::documentAboutToBeDeleted(KTextEditor::Document* doc)
01448 {
01449 if(sdDUChainPrivate->m_destroyed)
01450 return;
01451
01452 foreach(const ReferencedTopDUContext &top, sdDUChainPrivate->m_openDocumentContexts) {
01453 if(top->url().str() == doc->url().pathOrUrl())
01454 sdDUChainPrivate->m_openDocumentContexts.remove(top);
01455 }
01456 }
01457
01458 void DUChain::documentLoadedPrepare(KDevelop::IDocument* doc)
01459 {
01460 if(sdDUChainPrivate->m_destroyed)
01461 return;
01462 DUChainWriteLocker lock( DUChain::lock() );
01463 QMutexLocker l(&sdDUChainPrivate->m_chainsMutex);
01464
01465
01466 EditorIntegrator editor;
01467 if(doc->textDocument())
01468 editor.insertLoadedDocument(doc->textDocument());
01469
01470 TopDUContext* standardContext = DUChainUtils::standardContextForUrl(doc->url());
01471 QList<TopDUContext*> chains = chainsForDocument(doc->url());
01472
01473 QList<KDevelop::ILanguage*> languages = ICore::self()->languageController()->languagesForUrl(doc->url());
01474
01475 if(standardContext) {
01476 Q_ASSERT(chains.contains(standardContext));
01477
01478 {
01480 SmartConverter sc(&editor);
01481
01482 if(standardContext->smartRange()) {
01483 Q_ASSERT(standardContext->smartRange()->document() == doc->textDocument());
01484 kWarning() << "Strange: context already has smart-range! Probably another document is already open for it. Deconverting";
01485 sc.deconvertDUChain(standardContext);
01486 }
01487 sc.convertDUChain(standardContext);
01488 Q_ASSERT(standardContext->smartRange());
01489 ICore::self()->languageController()->backgroundParser()->addManagedTopRange(doc->url(), standardContext->smartRange());
01490 }
01491
01492 sdDUChainPrivate->m_openDocumentContexts.insert(standardContext);
01493
01494 bool needsUpdate = standardContext->parsingEnvironmentFile() && standardContext->parsingEnvironmentFile()->needsUpdate();
01495 if(!needsUpdate) {
01496
01497
01498
01499
01500
01501
01502 bool allImportsLoaded = true;
01503 foreach(DUContext::Import import, standardContext->importedParentContexts())
01504 if(!import.indexedContext().indexedTopContext().isLoaded())
01505 allImportsLoaded = false;
01506
01507 if(allImportsLoaded) {
01508 foreach( KDevelop::ILanguage* language, languages)
01509 if(language->languageSupport() && language->languageSupport()->codeHighlighting())
01510 language->languageSupport()->codeHighlighting()->highlightDUChain(standardContext);
01511 kDebug() << "highlighted" << doc->url() << "in foreground";
01512 return;
01513 }
01514 }else{
01515 kDebug() << "not highlighting the duchain because the documents needs an update";
01516 }
01517
01518 if(needsUpdate || !(standardContext->features() & TopDUContext::AllDeclarationsContextsAndUses)) {
01519 ICore::self()->languageController()->backgroundParser()->addDocument(doc->url(), (TopDUContext::Features)(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdate));
01520 return;
01521 }
01522 }
01523
01524
01525 ICore::self()->languageController()->backgroundParser()->addDocument(doc->url(), TopDUContext::AllDeclarationsContextsAndUses);
01526 }
01527
01528 void DUChain::documentRenamed(KDevelop::IDocument* doc)
01529 {
01530 if(sdDUChainPrivate->m_destroyed)
01531 return;
01532
01533 if(!doc->url().isValid()) {
01535 kWarning() << "Strange, url of renamed document is invalid!";
01536 }else{
01537 ICore::self()->languageController()->backgroundParser()->addDocument(doc->url(), (TopDUContext::Features)(TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::ForceUpdate));
01538 }
01539 }
01540
01541 Uses* DUChain::uses()
01542 {
01543 return &sdDUChainPrivate->m_uses;
01544 }
01545
01546 Definitions* DUChain::definitions()
01547 {
01548 return &sdDUChainPrivate->m_definitions;
01549 }
01550
01551 void DUChain::aboutToQuit()
01552 {
01553 QMutexLocker lock(&sdDUChainPrivate->cleanupMutex());
01554
01555 {
01556
01557
01558 globalItemRepositoryRegistry().lockForWriting();
01559 sdDUChainPrivate->cleanupTopContexts();
01560 globalItemRepositoryRegistry().unlockForWriting();
01561 }
01562
01563 sdDUChainPrivate->doMoreCleanup();
01564
01565 {
01566
01567
01568 globalItemRepositoryRegistry().lockForWriting();
01569 finalCleanup();
01570 globalItemRepositoryRegistry().unlockForWriting();
01571 }
01572
01573 sdDUChainPrivate->doMoreCleanup();
01574 sdDUChainPrivate->m_openDocumentContexts.clear();
01575 sdDUChainPrivate->m_destroyed = true;
01576 sdDUChainPrivate->clear();
01577
01578 globalItemRepositoryRegistry().shutdown();
01579 }
01580
01581 uint DUChain::newTopContextIndex() {
01582 static QAtomicInt& currentId( globalItemRepositoryRegistry().getCustomCounter("Top-Context Counter", 1) );
01583 return currentId.fetchAndAddRelaxed(1);
01584 }
01585
01586 void DUChain::refCountUp(TopDUContext* top) {
01587 QMutexLocker l(&sdDUChainPrivate->m_referenceCountsMutex);
01588 if(!sdDUChainPrivate->m_referenceCounts.contains(top))
01589 sdDUChainPrivate->m_referenceCounts.insert(top, 1);
01590 else
01591 ++sdDUChainPrivate->m_referenceCounts[top];
01592 }
01593
01594 bool DUChain::deleted() {
01595 return duChainDeleted;
01596 }
01597
01598 void DUChain::refCountDown(TopDUContext* top) {
01599 QMutexLocker l(&sdDUChainPrivate->m_referenceCountsMutex);
01600 if(!sdDUChainPrivate->m_referenceCounts.contains(top)) {
01601
01602 return;
01603 }
01604 --sdDUChainPrivate->m_referenceCounts[top];
01605 if(!sdDUChainPrivate->m_referenceCounts[top])
01606 sdDUChainPrivate->m_referenceCounts.remove(top);
01607 }
01608
01609 void DUChain::emitDeclarationSelected(DeclarationPointer decl) {
01610 emit declarationSelected(decl);
01611 }
01612
01613 KDevelop::ReferencedTopDUContext DUChain::waitForUpdate(const KDevelop::IndexedString& document, KDevelop::TopDUContext::Features minFeatures, bool wantProxyContext) {
01614 Q_ASSERT(!lock()->currentThreadHasReadLock() && !lock()->currentThreadHasWriteLock());
01615
01616 WaitForUpdate waiter;
01617
01618 waiter.m_dataMutex.lock();
01619
01620 {
01621 DUChainReadLocker readLock(DUChain::lock());
01622
01623 updateContextForUrl(document, minFeatures, &waiter);
01624 }
01625
01626
01627
01628 while(!waiter.m_ready) {
01631 QApplication::processEvents();
01632 usleep(10000);
01633
01634 }
01635
01636 if(!wantProxyContext) {
01637 DUChainReadLocker readLock(DUChain::lock());
01638 if(waiter.m_topContext && waiter.m_topContext->parsingEnvironmentFile() && waiter.m_topContext->parsingEnvironmentFile()->isProxyContext() && !waiter.m_topContext->importedParentContexts().isEmpty())
01639 return waiter.m_topContext->importedParentContexts()[0].context(0)->topContext();
01640 }
01641
01642 return waiter.m_topContext;
01643 }
01644
01645 void DUChain::updateContextForUrl(const IndexedString& document, TopDUContext::Features minFeatures, QObject* notifyReady) const {
01646 DUChainReadLocker lock( DUChain::lock() );
01647 TopDUContext* standardContext = DUChainUtils::standardContextForUrl(document.toUrl());
01648 if(standardContext && standardContext->parsingEnvironmentFile() && !standardContext->parsingEnvironmentFile()->needsUpdate() && standardContext->parsingEnvironmentFile()->featuresSatisfied(minFeatures)) {
01649 lock.unlock();
01650 if(notifyReady)
01651 QMetaObject::invokeMethod(notifyReady, "updateReady", Qt::DirectConnection, Q_ARG(KDevelop::IndexedString, document), Q_ARG(KDevelop::ReferencedTopDUContext, ReferencedTopDUContext(standardContext)));
01652 }else{
01654 ICore::self()->languageController()->backgroundParser()->addDocument(document.toUrl(), minFeatures, 1, notifyReady);
01655 }
01656 }
01657
01658 void DUChain::disablePersistentStorage() {
01659 sdDUChainPrivate->m_cleanupDisabled = true;
01660 }
01661
01662 void DUChain::storeToDisk() {
01663 bool wasDisabled = sdDUChainPrivate->m_cleanupDisabled;
01664 sdDUChainPrivate->m_cleanupDisabled = false;
01665
01666 sdDUChainPrivate->doMoreCleanup();
01667
01668 sdDUChainPrivate->m_cleanupDisabled = wasDisabled;
01669 }
01670
01671 void DUChain::finalCleanup() {
01672 DUChainWriteLocker writeLock(DUChain::lock());
01673 kDebug() << "doing final cleanup";
01674
01675 int cleaned = 0;
01676 while((cleaned = globalItemRepositoryRegistry().finalCleanup())) {
01677 kDebug() << "cleaned" << cleaned << "B";
01678 if(cleaned < 1000) {
01679 kDebug() << "cleaned enough";
01680 break;
01681 }
01682 }
01683 kDebug() << "final cleanup ready";
01684 }
01685
01686 bool DUChain::compareToDisk() {
01687
01688 DUChainWriteLocker writeLock(DUChain::lock());
01689
01691 return true;
01692 }
01693
01694 }
01695
01696 #include "duchain.moc"
01697
01698