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

kdevplatform/language/duchain

  • sources
  • kfour-appscomplete
  • kdevelop
  • kdevplatform
  • language
  • duchain
topducontextdynamicdata.cpp
Go to the documentation of this file.
1 /* This is part of KDevelop
2 
3  Copyright 2014 Milian Wolff <[email protected]>
4  Copyright 2008 David Nolden <[email protected]>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2 as published by the Free Software Foundation.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20 
21 #include "topducontextdynamicdata.h"
22 
23 #include <typeinfo>
24 #include <QFile>
25 #include <QByteArray>
26 
27 #include "declaration.h"
28 #include "declarationdata.h"
29 #include "ducontext.h"
30 #include "topducontext.h"
31 #include "topducontextdata.h"
32 #include "ducontextdata.h"
33 #include "ducontextdynamicdata.h"
34 #include "duchainregister.h"
35 #include "serialization/itemrepository.h"
36 #include "problem.h"
37 #include <debug.h>
38 
39 //#define DEBUG_DATA_INFO
40 
41 //This might be problematic on some systems, because really many mmaps are created
42 #define USE_MMAP
43 using namespace KDevelop;
44 
45 namespace {
57 void saveDUChainItem(QVector<TopDUContextDynamicData::ArrayWithPosition>& data, DUChainBase& item,
58  uint& totalDataOffset, bool isSharedDataItem)
59 {
60  if (!item.d_func()->classId) {
61  //If this triggers, you have probably created an own DUChainBase based class, but haven't called setClassId(this) in the constructor.
62  qCritical() << "no class-id set for data attached to a declaration of type" << typeid(item).name();
63  Q_ASSERT(0);
64  }
65 
66  int size = DUChainItemSystem::self().dynamicSize(*item.d_func());
67 
68  if (data.back().array.size() - int( data.back().position ) < size)
69  //Create a new data item
70  data.append({QByteArray(size > 10000 ? size : 10000, 0), 0u});
71 
72  uint pos = data.back().position;
73  data.back().position += size;
74  totalDataOffset += size;
75 
76  DUChainBaseData& target(*(reinterpret_cast<DUChainBaseData*>(data.back().array.data() + pos)));
77 
78  if (item.d_func()->isDynamic()) {
79  //Change from dynamic data to constant data
80  const DUChainReferenceCountingEnabler rcEnabler(data.back().array.data(), data.back().array.size());
81  DUChainItemSystem::self().copy(*item.d_func(), target, true);
82  Q_ASSERT(!target.isDynamic());
83  if (!isSharedDataItem) {
84  item.setData(&target);
85  }
86  } else {
87  //Just copy the data into another place, expensive copy constructors are not needed
88 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 800)
89 #pragma GCC diagnostic push
90 #pragma GCC diagnostic ignored "-Wclass-memaccess"
91 #endif
92  memcpy(&target, item.d_func(), size);
93 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 800)
94 #pragma GCC diagnostic pop
95 #endif
96  if (!isSharedDataItem) {
97  item.setData(&target, false);
98  }
99  }
100 
101  if (!isSharedDataItem) {
102  Q_ASSERT(item.d_func() == &target);
103 
104  Q_ASSERT(!item.d_func()->isDynamic());
105  }
106 }
107 
108 uint indexForParentContext(DUContext* context)
109 {
110  return LocalIndexedDUContext(context->parentContext()).localIndex();
111 }
112 
113 uint indexForParentContext(Declaration* declaration)
114 {
115  return LocalIndexedDUContext(declaration->context()).localIndex();
116 }
117 
118 uint indexForParentContext(const ProblemPointer& /*problem*/)
119 {
120  // always stored in the top context
121  return 0;
122 }
123 
124 #ifndef QT_NO_DEBUG
125 void validateItem(const DUChainBaseData* const data, const uchar* const mappedData, const size_t mappedDataSize)
126 {
127  Q_ASSERT(!data->isDynamic());
128  if (mappedData) {
129  Q_ASSERT((( size_t )data) < (( size_t )mappedData)
130  || (( size_t )data) > (( size_t )mappedData) + mappedDataSize);
131  }
132 }
133 #endif
134 
135 const char* pointerInData(const QVector<TopDUContextDynamicData::ArrayWithPosition>& data, uint totalOffset)
136 {
137  for (auto& awp : data) {
138  if (totalOffset < awp.position) {
139  return awp.array.constData() + totalOffset;
140  }
141  totalOffset -= awp.position;
142  }
143 
144  Q_ASSERT_X(false, Q_FUNC_INFO, "Offset doesn't exist in the data.");
145  return nullptr;
146 }
147 
148 void verifyDataInfo(const TopDUContextDynamicData::ItemDataInfo& info,
149  const QVector<TopDUContextDynamicData::ArrayWithPosition>& data)
150 {
151  Q_UNUSED(info);
152  Q_UNUSED(data);
153 #ifdef DEBUG_DATA_INFO
154  DUChainBaseData* item = ( DUChainBaseData* )(pointerInData(data, info.dataOffset));
155  int size = DUChainItemSystem::self().dynamicSize(*item);
156  Q_ASSERT(size);
157 #endif
158 }
159 
160 QString basePath()
161 {
162  return globalItemRepositoryRegistry().path() + QLatin1String("/topcontexts/");
163 }
164 
165 QString pathForTopContext(const uint topContextIndex)
166 {
167  return basePath() + QString::number(topContextIndex);
168 }
169 
170 enum LoadType {
171  PartialLoad,
172  FullLoad
173 };
174 template <typename F>
175 void loadTopDUContextData(const uint topContextIndex, LoadType loadType, F callback)
176 {
177  QFile file(pathForTopContext(topContextIndex));
178  if (!file.open(QIODevice::ReadOnly)) {
179  return;
180  }
181 
182  uint readValue;
183  file.read(reinterpret_cast<char*>(&readValue), sizeof(uint));
184  // now readValue is filled with the top-context data size
185  Q_ASSERT(readValue >= sizeof(TopDUContextData));
186  const QByteArray data = file.read(loadType == FullLoad ? readValue : sizeof(TopDUContextData));
187  const auto* topData = reinterpret_cast<const TopDUContextData*>(data.constData());
188  callback(topData);
189 }
190 
191 template <typename T>
192 struct PtrType;
193 
194 template <typename T>
195 struct PtrType<T*>
196 {
197  using value = T *;
198 };
199 
200 template <typename T>
201 struct PtrType<QExplicitlySharedDataPointer<T>>
202 {
203  using value = T *;
204 };
205 
206 template <typename T>
207 Q_DECL_CONSTEXPR bool isSharedDataItem()
208 {
209  return false;
210 }
211 
212 template <>
213 Q_DECL_CONSTEXPR bool isSharedDataItem<ProblemPointer>()
214 {
215  return true;
216 }
217 }
218 
219 //BEGIN DUChainItemStorage
220 
221 template <class Item>
222 TopDUContextDynamicData::DUChainItemStorage<Item>::DUChainItemStorage(TopDUContextDynamicData* data)
223  : data(data)
224 {
225 }
226 
227 template <class Item>
228 TopDUContextDynamicData::DUChainItemStorage<Item>::~DUChainItemStorage()
229 {
230  clearItems();
231 }
232 
233 template <class Item>
234 void TopDUContextDynamicData::DUChainItemStorage<Item>::clearItems()
235 {
236  //Due to template specialization it's possible that a declaration is not reachable through the normal context structure.
237  //For that reason we have to check here, and delete all remaining declarations.
238  qDeleteAll(temporaryItems);
239  temporaryItems.clear();
240  qDeleteAll(items);
241  items.clear();
242 }
243 
244 namespace KDevelop {
245 template <>
246 void TopDUContextDynamicData::DUChainItemStorage<ProblemPointer>::clearItems()
247 {
248  // don't delete anything - the problem is shared
249  items.clear();
250 }
251 }
252 
253 template <class Item>
254 void TopDUContextDynamicData::DUChainItemStorage<Item>::clearItemIndex(const Item& item, const uint index)
255 {
256  if (!data->m_dataLoaded)
257  data->loadData();
258 
259  if (index < (0x0fffffff / 2)) {
260  if (index == 0 || index > uint(items.size())) {
261  return;
262  } else {
263  const uint realIndex = index - 1;
264  Q_ASSERT(items[realIndex] == item);
265  items[realIndex] = nullptr;
266 
267  if (realIndex < ( uint )offsets.size()) {
268  offsets[realIndex] = ItemDataInfo();
269  }
270  }
271  } else {
272  const uint realIndex = 0x0fffffff - index; //We always keep the highest bit at zero
273  if (realIndex == 0 || realIndex > uint(temporaryItems.size())) {
274  return;
275  } else {
276  Q_ASSERT(temporaryItems[realIndex - 1] == item);
277  temporaryItems[realIndex - 1] = nullptr;
278  }
279  }
280 
281  Q_UNUSED(item);
282 }
283 
284 template <class Item>
285 void TopDUContextDynamicData::DUChainItemStorage<Item>::storeData(uint& currentDataOffset,
286  const QVector<ArrayWithPosition>& oldData)
287 {
288  auto const oldOffsets = offsets;
289  offsets.clear();
290  offsets.reserve(items.size());
291  for (int a = 0; a < items.size(); ++a) {
292  auto item = items[a];
293  if (!item) {
294  if (oldOffsets.size() > a && oldOffsets[a].dataOffset) {
295  //Directly copy the old data range into the new data
296  const DUChainBaseData* itemData = nullptr;
297  if (data->m_mappedData) {
298  itemData = reinterpret_cast<const DUChainBaseData*>(data->m_mappedData + oldOffsets[a].dataOffset);
299  } else {
300  itemData =
301  reinterpret_cast<const DUChainBaseData*>(::pointerInData(oldData, oldOffsets[a].dataOffset));
302  }
303  offsets << data->writeDataInfo(oldOffsets[a], itemData, currentDataOffset);
304  } else {
305  offsets << ItemDataInfo();
306  }
307  } else {
308  offsets << ItemDataInfo{currentDataOffset, indexForParentContext(item)};
309  saveDUChainItem(data->m_data, *item, currentDataOffset, isSharedDataItem<Item>());
310  }
311  }
312 
313 #ifndef QT_NO_DEBUG
314  if (!isSharedDataItem<Item>()) {
315  for (auto item : items) {
316  if (item) {
317  validateItem(item->d_func(), data->m_mappedData, data->m_mappedDataSize);
318  }
319  }
320  }
321 #endif
322 }
323 
324 template <typename Item>
325 bool TopDUContextDynamicData::DUChainItemStorage<Item>::itemsHaveChanged() const
326 {
327  for (auto item : items) {
328  if (item && item->d_func()->m_dynamic) {
329  return true;
330  }
331  }
332 
333  return false;
334 }
335 
336 template <class Item>
337 uint TopDUContextDynamicData::DUChainItemStorage<Item>::allocateItemIndex(const Item& item, const bool temporary)
338 {
339  if (!data->m_dataLoaded) {
340  data->loadData();
341  }
342  if (!temporary) {
343  items.append(item);
344  return items.size();
345  } else {
346  temporaryItems.append(item);
347  return 0x0fffffff - temporaryItems.size(); //We always keep the highest bit at zero
348  }
349 }
350 
351 template <class Item>
352 bool TopDUContextDynamicData::DUChainItemStorage<Item>::isItemForIndexLoaded(uint index) const
353 {
354  if (!data->m_dataLoaded) {
355  return false;
356  }
357  if (index < (0x0fffffff / 2)) {
358  if (index == 0 || index > uint(items.size())) {
359  return false;
360  }
361  return items[index - 1];
362  } else {
363  // temporary item
364  return true;
365  }
366 }
367 
368 template <class Item>
369 Item TopDUContextDynamicData::DUChainItemStorage<Item>::itemForIndex(uint index) const
370 {
371  if (index >= (0x0fffffff / 2)) {
372  index = 0x0fffffff - index; //We always keep the highest bit at zero
373  if (index == 0 || index > uint(temporaryItems.size()))
374  return {};
375  else
376  return temporaryItems.at(index - 1);
377  }
378 
379  if (index == 0 || index > static_cast<uint>(items.size())) {
380  qCWarning(LANGUAGE) << "item index out of bounds:" << index << "count:" << items.size();
381  return {};
382  }
383  const uint realIndex = index - 1;
384  const auto& item = items.at(realIndex);
385  if (item) {
386  //Shortcut, because this is the most common case
387  return item;
388  }
389 
390  if (realIndex < ( uint )offsets.size() && offsets[realIndex].dataOffset) {
391  Q_ASSERT(!data->m_itemRetrievalForbidden);
392 
393  //Construct the context, and eventuall its parent first
395  auto itemData = const_cast<DUChainBaseData*>(
396  reinterpret_cast<const DUChainBaseData*>(data->pointerInData(offsets[realIndex].dataOffset))
397  );
398 
399  auto& item = items[realIndex];
400  item = dynamic_cast<typename PtrType<Item>::value>(DUChainItemSystem::self().create(itemData));
401  if (!item) {
402  //When this happens, the item has not been registered correctly.
403  //We can stop here, because else we will get crashes later.
404  qCritical() << "Failed to load item with identity" << itemData->classId;
405  return {};
406  }
407 
408  if (isSharedDataItem<Item>()) {
409  // NOTE: shared data must never point to mmapped data regions as otherwise we might end up with
410  // use-after-free or double-deletions etc. pp.
411  // thus, make the item always dynamic after deserialization
412  item->makeDynamic();
413  }
414 
415  auto parent = data->contextForIndex(offsets[realIndex].parentContext);
416  Q_ASSERT_X(parent, Q_FUNC_INFO, "Could not find parent context for loaded item.\n"
417  "Potentially, the context has been deleted without deleting its children.");
418  item->rebuildDynamicData(parent, index);
419  } else {
420  qCWarning(LANGUAGE) << "invalid item for index" << index << offsets.size() <<
421  offsets.value(realIndex).dataOffset;
422  }
423 
424  return item;
425 }
426 
427 template <class Item>
428 void TopDUContextDynamicData::DUChainItemStorage<Item>::deleteOnDisk()
429 {
430  for (auto& item : items) {
431  if (item) {
432  item->makeDynamic();
433  }
434  }
435 }
436 
437 template <class Item>
438 void TopDUContextDynamicData::DUChainItemStorage<Item>::loadData(QFile* file) const
439 {
440  Q_ASSERT(offsets.isEmpty());
441  Q_ASSERT(items.isEmpty());
442 
443  uint readValue;
444  file->read(reinterpret_cast<char*>(&readValue), sizeof(uint));
445  offsets.resize(readValue);
446 
447  file->read(reinterpret_cast<char*>(offsets.data()), sizeof(ItemDataInfo) * offsets.size());
448 
449  //Fill with zeroes for now, will be initialized on-demand
450  items.resize(offsets.size());
451 }
452 
453 template <class Item>
454 void TopDUContextDynamicData::DUChainItemStorage<Item>::writeData(QFile* file)
455 {
456  uint writeValue = offsets.size();
457  file->write(reinterpret_cast<const char*>(&writeValue), sizeof(uint));
458  file->write(reinterpret_cast<const char*>(offsets.data()), sizeof(ItemDataInfo) * offsets.size());
459 }
460 
461 //END DUChainItemStorage
462 
463 const char* TopDUContextDynamicData::pointerInData(uint totalOffset) const
464 {
465  Q_ASSERT(!m_mappedData || m_data.isEmpty());
466 
467  if (m_mappedData && m_mappedDataSize)
468  return reinterpret_cast<const char*>(m_mappedData) + totalOffset;
469 
470  return ::pointerInData(m_data, totalOffset);
471 }
472 
473 TopDUContextDynamicData::TopDUContextDynamicData(TopDUContext* topContext)
474  : m_deleting(false)
475  , m_topContext(topContext)
476  , m_contexts(this)
477  , m_declarations(this)
478  , m_problems(this)
479  , m_onDisk(false)
480  , m_dataLoaded(true)
481  , m_mappedFile(nullptr)
482  , m_mappedData(nullptr)
483  , m_mappedDataSize(0)
484  , m_itemRetrievalForbidden(false)
485 {
486 }
487 
488 void KDevelop::TopDUContextDynamicData::clear()
489 {
490  m_contexts.clearItems();
491  m_declarations.clearItems();
492  m_problems.clearItems();
493 }
494 
495 TopDUContextDynamicData::~TopDUContextDynamicData()
496 {
497  unmap();
498 }
499 
500 void KDevelop::TopDUContextDynamicData::unmap()
501 {
502  delete m_mappedFile;
503  m_mappedFile = nullptr;
504  m_mappedData = nullptr;
505  m_mappedDataSize = 0;
506 }
507 
508 bool TopDUContextDynamicData::fileExists(uint topContextIndex)
509 {
510  return QFile::exists(pathForTopContext(topContextIndex));
511 }
512 
513 QList<IndexedDUContext> TopDUContextDynamicData::loadImporters(uint topContextIndex)
514 {
515  QList<IndexedDUContext> ret;
516  loadTopDUContextData(topContextIndex, FullLoad, [&ret](const TopDUContextData* topData) {
517  ret.reserve(topData->m_importersSize());
518  FOREACH_FUNCTION(const IndexedDUContext &importer, topData->m_importers)
519  ret << importer;
520  });
521  return ret;
522 }
523 
524 QList<IndexedDUContext> TopDUContextDynamicData::loadImports(uint topContextIndex)
525 {
526  QList<IndexedDUContext> ret;
527  loadTopDUContextData(topContextIndex, FullLoad, [&ret](const TopDUContextData* topData) {
528  ret.reserve(topData->m_importedContextsSize());
529  FOREACH_FUNCTION(const DUContext::Import& import, topData->m_importedContexts)
530  ret << import.indexedContext();
531  });
532  return ret;
533 }
534 
535 IndexedString TopDUContextDynamicData::loadUrl(uint topContextIndex)
536 {
537  IndexedString url;
538  loadTopDUContextData(topContextIndex, PartialLoad, [&url](const TopDUContextData* topData) {
539  Q_ASSERT(topData->m_url.isEmpty() || topData->m_url.index() >> 16);
540  url = topData->m_url;
541  });
542  return url;
543 }
544 
545 void TopDUContextDynamicData::loadData() const
546 {
547  //This function has to be protected by an additional mutex, since it can be triggered from multiple threads at the same time
548  static QMutex mutex;
549  QMutexLocker lock(&mutex);
550  if (m_dataLoaded)
551  return;
552 
553  Q_ASSERT(!m_dataLoaded);
554  Q_ASSERT(m_data.isEmpty());
555 
556  auto* file = new QFile(pathForTopContext(m_topContext->ownIndex()));
557  bool open = file->open(QIODevice::ReadOnly);
558  Q_UNUSED(open);
559  Q_ASSERT(open);
560  Q_ASSERT(file->size());
561 
562  //Skip the offsets, we're already read them
563  //Skip top-context data
564  uint readValue;
565  file->read(reinterpret_cast<char*>(&readValue), sizeof(uint));
566  file->seek(readValue + file->pos());
567 
568  m_contexts.loadData(file);
569  m_declarations.loadData(file);
570  m_problems.loadData(file);
571 
572 #ifdef USE_MMAP
573 
574  m_mappedData = file->map(file->pos(), file->size() - file->pos());
575  if (m_mappedData) {
576  m_mappedFile = file;
577  m_mappedDataSize = file->size() - file->pos();
578  file->close(); //Close the file, so there is less open file descriptors(May be problematic)
579  } else {
580  qCDebug(LANGUAGE) << "Failed to map" << file->fileName();
581  }
582 
583 #endif
584 
585  if (!m_mappedFile) {
586  QByteArray data = file->readAll();
587  m_data.append({data, ( uint )data.size()});
588  delete file;
589  }
590 
591  m_dataLoaded = true;
592 }
593 
594 TopDUContext* TopDUContextDynamicData::load(uint topContextIndex)
595 {
596  QFile file(pathForTopContext(topContextIndex));
597  if (file.open(QIODevice::ReadOnly)) {
598  if (file.size() == 0) {
599  qCWarning(LANGUAGE) << "Top-context file is empty" << file.fileName();
600  return nullptr;
601  }
602 
603  uint readValue;
604  file.read(reinterpret_cast<char*>(&readValue), sizeof(uint));
605  //now readValue is filled with the top-context data size
606  QByteArray topContextData = file.read(readValue);
607 
608  auto* topData = reinterpret_cast<DUChainBaseData*>(topContextData.data());
609  auto* ret = dynamic_cast<TopDUContext*>(DUChainItemSystem::self().create(topData));
610  if (!ret) {
611  qCWarning(LANGUAGE) << "Cannot load a top-context from file" << file.fileName() <<
612  "- the required language-support for handling ID" << topData->classId << "is probably not loaded";
613  return nullptr;
614  }
615 
616  TopDUContextDynamicData& target(*ret->m_dynamicData);
617 
618  target.m_data.clear();
619  target.m_dataLoaded = false;
620  target.m_onDisk = true;
621  ret->rebuildDynamicData(nullptr, topContextIndex);
622  target.m_topContextData.append({topContextData, ( uint )0});
623  return ret;
624  } else {
625  return nullptr;
626  }
627 }
628 
629 bool TopDUContextDynamicData::isOnDisk() const
630 {
631  return m_onDisk;
632 }
633 
634 void TopDUContextDynamicData::deleteOnDisk()
635 {
636  if (!isOnDisk())
637  return;
638  qCDebug(LANGUAGE) << "deleting" << m_topContext->ownIndex() << m_topContext->url().str();
639 
640  if (!m_dataLoaded)
641  loadData();
642 
643  m_contexts.deleteOnDisk();
644  m_declarations.deleteOnDisk();
645  m_problems.deleteOnDisk();
646 
647  m_topContext->makeDynamic();
648 
649  m_onDisk = false;
650 
651  bool successfullyRemoved = QFile::remove(filePath());
652  Q_UNUSED(successfullyRemoved);
653  Q_ASSERT(successfullyRemoved);
654  qCDebug(LANGUAGE) << "deletion ready";
655 }
656 
657 QString KDevelop::TopDUContextDynamicData::filePath() const
658 {
659  return pathForTopContext(m_topContext->ownIndex());
660 }
661 
662 bool TopDUContextDynamicData::hasChanged() const
663 {
664  return !m_onDisk || m_topContext->d_func()->m_dynamic
665  || m_contexts.itemsHaveChanged() || m_declarations.itemsHaveChanged()
666  || m_problems.itemsHaveChanged();
667 }
668 
669 void TopDUContextDynamicData::store()
670 {
671 // qCDebug(LANGUAGE) << "storing" << m_topContext->url().str() << m_topContext->ownIndex() << "import-count:" << m_topContext->importedParentContexts().size();
672 
673  //Check if something has changed. If nothing has changed, don't store to disk.
674  bool contentDataChanged = hasChanged();
675  if (!contentDataChanged) {
676  return;
677  }
678 
682  if (!m_dataLoaded)
683  loadData();
684 
688  if (m_mappedData)
689  contentDataChanged = true;
690 
691  m_topContext->makeDynamic();
692  m_topContextData.clear();
693  Q_ASSERT(m_topContext->d_func()->m_ownIndex == m_topContext->ownIndex());
694 
695  uint topContextDataSize = DUChainItemSystem::self().dynamicSize(*m_topContext->d_func());
696  m_topContextData.append({QByteArray(DUChainItemSystem::self().dynamicSize(*m_topContext->d_func()),
697  topContextDataSize), 0u});
698  uint actualTopContextDataSize = 0;
699 
700  if (contentDataChanged) {
701  //We don't need these structures any more, since we have loaded all the declarations/contexts, and m_data
702  //will be reset which these structures pointed into
703  //Load all lazy declarations/contexts
704 
705  const auto oldData = m_data; //Keep the old data alive until everything is stored into a new data structure
706 
707  m_data.clear();
708 
709  uint newDataSize = 0;
710  for (const ArrayWithPosition& array : oldData) {
711  newDataSize += array.position;
712  }
713 
714  newDataSize = std::max(newDataSize, 10000u);
715 
716  //We always put 1 byte to the front, so we don't have zero data-offsets, since those are used for "invalid".
717  uint currentDataOffset = 1;
718  m_data.append({QByteArray(newDataSize, 0), currentDataOffset});
719 
720  m_itemRetrievalForbidden = true;
721 
722  m_contexts.storeData(currentDataOffset, oldData);
723  m_declarations.storeData(currentDataOffset, oldData);
724  m_problems.storeData(currentDataOffset, oldData);
725 
726  m_itemRetrievalForbidden = false;
727  }
728 
729  saveDUChainItem(m_topContextData, *m_topContext, actualTopContextDataSize, false);
730  Q_ASSERT(actualTopContextDataSize == topContextDataSize);
731  Q_ASSERT(m_topContextData.size() == 1);
732  Q_ASSERT(!m_topContext->d_func()->isDynamic());
733 
734  unmap();
735 
736  QDir().mkpath(basePath());
737 
738  QFile file(filePath());
739  if (file.open(QIODevice::WriteOnly)) {
740  file.resize(0);
741 
742  file.write(reinterpret_cast<const char*>(&topContextDataSize), sizeof(uint));
743  for (const ArrayWithPosition& pos : qAsConst(m_topContextData)) {
744  file.write(pos.array.constData(), pos.position);
745  }
746 
747  m_contexts.writeData(&file);
748  m_declarations.writeData(&file);
749  m_problems.writeData(&file);
750 
751  for (const ArrayWithPosition& pos : qAsConst(m_data)) {
752  file.write(pos.array.constData(), pos.position);
753  }
754 
755  m_onDisk = true;
756 
757  if (file.size() == 0) {
758  qCWarning(LANGUAGE) << "Saving zero size top ducontext data";
759  }
760  file.close();
761  } else {
762  qCWarning(LANGUAGE) << "Cannot open top-context for writing";
763  }
764 // qCDebug(LANGUAGE) << "stored" << m_topContext->url().str() << m_topContext->ownIndex() << "import-count:" << m_topContext->importedParentContexts().size();
765 }
766 
767 TopDUContextDynamicData::ItemDataInfo TopDUContextDynamicData::writeDataInfo(const ItemDataInfo& info,
768  const DUChainBaseData* data,
769  uint& totalDataOffset)
770 {
771  ItemDataInfo ret(info);
772  Q_ASSERT(info.dataOffset);
773  const auto size = DUChainItemSystem::self().dynamicSize(*data);
774  Q_ASSERT(size);
775 
776  if (m_data.back().array.size() - m_data.back().position < size) {
777  //Create a new m_data item
778  m_data.append({QByteArray(std::max(size, 10000u), 0), 0u});
779  }
780 
781  ret.dataOffset = totalDataOffset;
782 
783  uint pos = m_data.back().position;
784  m_data.back().position += size;
785  totalDataOffset += size;
786 
787  auto target = reinterpret_cast<DUChainBaseData*>(m_data.back().array.data() + pos);
788 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 800)
789 #pragma GCC diagnostic push
790 #pragma GCC diagnostic ignored "-Wclass-memaccess"
791 #endif
792  memcpy(target, data, size);
793 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && (((__GNUC__ * 100) + __GNUC_MINOR__) >= 800)
794 #pragma GCC diagnostic pop
795 #endif
796 
797  verifyDataInfo(ret, m_data);
798  return ret;
799 }
800 
801 uint TopDUContextDynamicData::allocateDeclarationIndex(Declaration* decl, bool temporary)
802 {
803  return m_declarations.allocateItemIndex(decl, temporary);
804 }
805 
806 uint TopDUContextDynamicData::allocateContextIndex(DUContext* context, bool temporary)
807 {
808  return m_contexts.allocateItemIndex(context, temporary);
809 }
810 
811 uint TopDUContextDynamicData::allocateProblemIndex(const ProblemPointer& problem)
812 {
813  return m_problems.allocateItemIndex(problem, false);
814 }
815 
816 bool TopDUContextDynamicData::isDeclarationForIndexLoaded(uint index) const
817 {
818  return m_declarations.isItemForIndexLoaded(index);
819 }
820 
821 bool TopDUContextDynamicData::isContextForIndexLoaded(uint index) const
822 {
823  return m_contexts.isItemForIndexLoaded(index);
824 }
825 
826 bool TopDUContextDynamicData::isTemporaryContextIndex(uint index) const
827 {
828  return !(index < (0x0fffffff / 2));
829 }
830 
831 bool TopDUContextDynamicData::isTemporaryDeclarationIndex(uint index) const
832 {
833  return !(index < (0x0fffffff / 2));
834 }
835 
836 DUContext* TopDUContextDynamicData::contextForIndex(uint index) const
837 {
838  if (!m_dataLoaded)
839  loadData();
840 
841  if (index == 0) {
842  return m_topContext;
843  }
844 
845  return m_contexts.itemForIndex(index);
846 }
847 
848 Declaration* TopDUContextDynamicData::declarationForIndex(uint index) const
849 {
850  if (!m_dataLoaded)
851  loadData();
852 
853  return m_declarations.itemForIndex(index);
854 }
855 
856 ProblemPointer TopDUContextDynamicData::problemForIndex(uint index) const
857 {
858  if (!m_dataLoaded)
859  loadData();
860 
861  return m_problems.itemForIndex(index);
862 }
863 
864 void TopDUContextDynamicData::clearDeclarationIndex(Declaration* decl)
865 {
866  m_declarations.clearItemIndex(decl, decl->m_indexInTopContext);
867 }
868 
869 void TopDUContextDynamicData::clearContextIndex(DUContext* context)
870 {
871  m_contexts.clearItemIndex(context, context->m_dynamicData->m_indexInTopContext);
872 }
873 
874 void TopDUContextDynamicData::clearProblems()
875 {
876  m_problems.clearItems();
877 }
KDevelop::DUContextDynamicData::m_indexInTopContext
uint m_indexInTopContext
Definition: ducontextdynamicdata.h:78
QMutex
KDevelop::TopDUContextDynamicData::isTemporaryContextIndex
bool isTemporaryContextIndex(uint index) const
Definition: topducontextdynamicdata.cpp:826
KDevelop::TopDUContextDynamicData::isContextForIndexLoaded
bool isContextForIndexLoaded(uint index) const
Definition: topducontextdynamicdata.cpp:821
KDevelop::TopDUContext::LocalIndexedDUContext
friend class LocalIndexedDUContext
Definition: topducontext.h:374
QString::number
QString number(int n, int base)
QFile::close
virtual void close()
QFile::resize
bool resize(qint64 sz)
KDevelop::TopDUContextDynamicData::load
static TopDUContext * load(uint topContextIndex)
Loads the top-context from disk, or returns zero on failure.
Definition: topducontextdynamicdata.cpp:594
KDevelop::TopDUContext::ownIndex
uint ownIndex() const
Definition: topducontext.cpp:537
QFile::remove
bool remove()
KDevelop::TopDUContextDynamicData::contextForIndex
DUContext * contextForIndex(uint index) const
Definition: topducontextdynamicdata.cpp:836
KDevelop::DUChainBase
Base class for definition-use chain objects.
Definition: duchainbase.h:131
QFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QByteArray::append
QByteArray & append(char ch)
KDevelop::TopDUContextDynamicData::~TopDUContextDynamicData
~TopDUContextDynamicData()
Definition: topducontextdynamicdata.cpp:495
QDir
LoadType
LoadType
Definition: topducontextdynamicdata.cpp:170
QVector::append
void append(const T &value)
KDevelop::TopDUContextDynamicData::ItemDataInfo
Flag used during destruction.
Definition: topducontextdynamicdata.h:109
ducontextdynamicdata.h
KDevelop::m_problems
KDEVPLATFORMLANGUAGE_EXPORT m_problems
Definition: topducontextdata.h:49
KDevelop::DUChainBase::makeDynamic
void makeDynamic()
After this was called, the data-pointer is dynamic. It is cloned if needed.
Definition: duchainbase.cpp:132
KDevelop::TopDUContextDynamicData::clearProblems
void clearProblems()
Definition: topducontextdynamicdata.cpp:874
KDevelop::TopDUContextData::m_url
IndexedString m_url
Definition: topducontextdata.h:85
QVector::back
reference back()
QList
QFile::exists
bool exists() const
KDevelop::TopDUContextDynamicData::ItemDataInfo::dataOffset
uint dataOffset
Definition: topducontextdynamicdata.h:111
KDevelop::TopDUContextDynamicData::allocateDeclarationIndex
uint allocateDeclarationIndex(Declaration *decl, bool temporary)
Allocates an index for the given declaration in this top-context.
Definition: topducontextdynamicdata.cpp:801
KDevelop::TopDUContextDynamicData::declarationForIndex
Declaration * declarationForIndex(uint index) const
Definition: topducontextdynamicdata.cpp:848
topducontext.h
QFile::fileName
QString fileName() const
KDevelop::Declaration
Represents a single declaration in a definition-use chain.
Definition: declaration.h:51
KDevelop::TopDUContextDynamicData::ArrayWithPosition
Definition: topducontextdynamicdata.h:115
problem.h
KDevelop::TopDUContextDynamicData::loadImports
static QList< IndexedDUContext > loadImports(uint topContextIndex)
Definition: topducontextdynamicdata.cpp:524
QExplicitlySharedDataPointer
Definition: topducontext.h:28
KDevelop::TopDUContextDynamicData
This class contains dynamic data of a top-context, and also the repository that contains all the data...
Definition: topducontextdynamicdata.h:37
QList::reserve
void reserve(int alloc)
KDevelop::TopDUContext::url
IndexedString url() const override
Definition: topducontext.cpp:1228
KDevelop::TopDUContextData
Definition: topducontextdata.h:51
FOREACH_FUNCTION
#define FOREACH_FUNCTION(item, container)
Foreach macro that takes a container and a function-name, and will iterate through the vector returne...
Definition: appendedlist.h:213
declaration.h
ducontextdata.h
KDevelop::DUChainItemSystem::copy
void copy(const DUChainBaseData &from, DUChainBaseData &to, bool constant) const
This just calls the correct constructor on the target.
Definition: duchainregister.cpp:84
KDevelop::TopDUContextDynamicData::allocateContextIndex
uint allocateContextIndex(DUContext *ctx, bool temporary)
Allocates an index for the given context in this top-context.
Definition: topducontextdynamicdata.cpp:806
declarationdata.h
KDevelop::DUChainBaseData::classId
quint16 classId
Definition: duchainbase.h:84
KDevelop::TopDUContextDynamicData::TopDUContextDynamicData
TopDUContextDynamicData(TopDUContext *topContext)
Definition: topducontextdynamicdata.cpp:473
QString
KDevelop::DUChainBaseData::isDynamic
bool isDynamic() const
Definition: duchainbase.h:86
KDevelop::TopDUContextDynamicData::clearDeclarationIndex
void clearDeclarationIndex(Declaration *decl)
Definition: topducontextdynamicdata.cpp:864
QDir::mkpath
bool mkpath(const QString &dirPath) const
KDevelop::TopDUContext
The top context in a definition-use chain for one source file.
Definition: topducontext.h:113
KDevelop::TopDUContextDynamicData::isDeclarationForIndexLoaded
bool isDeclarationForIndexLoaded(uint index) const
Definition: topducontextdynamicdata.cpp:816
KDevelop::Declaration::context
DUContext * context() const
Access the parent context of this declaration.
Definition: declaration.cpp:279
KDevelop::TopDUContextDynamicData::loadUrl
static IndexedString loadUrl(uint topContextIndex)
Loads only the url out of the data stored on disk for the top-context.
Definition: topducontextdynamicdata.cpp:535
KDevelop::TopDUContextDynamicData::clearContextIndex
void clearContextIndex(DUContext *ctx)
Definition: topducontextdynamicdata.cpp:869
QLatin1String
KDevelop::TopDUContextDynamicData::allocateProblemIndex
uint allocateProblemIndex(const ProblemPointer &problem)
Allocates an index for the given problem in this top-context.
Definition: topducontextdynamicdata.cpp:811
KDevelop::TopDUContextDynamicData::isTemporaryDeclarationIndex
bool isTemporaryDeclarationIndex(uint index) const
Definition: topducontextdynamicdata.cpp:831
KDevelop::TopDUContextDynamicData::problemForIndex
ProblemPointer problemForIndex(uint index) const
Definition: topducontextdynamicdata.cpp:856
QFile::size
virtual qint64 size() const
KDevelop::TopDUContextDynamicData::fileExists
static bool fileExists(uint topContextIndex)
Definition: topducontextdynamicdata.cpp:508
KDevelop::DUChainBase::setData
virtual void setData(DUChainBaseData *, bool constructorCalled=true)
This must only be used to change the storage-location or storage-kind(dynamic/constant) of the data,...
Definition: duchainbase.cpp:77
QIODevice::read
qint64 read(char *data, qint64 maxSize)
KDevelop::DUChainItemSystem::dynamicSize
uint dynamicSize(const DUChainBaseData &data) const
Calls the dynamicSize(..) member on the given data, in the most special class. Since we cannot use vi...
Definition: duchainregister.cpp:70
KDevelop::TopDUContextDynamicData::loadImporters
static QList< IndexedDUContext > loadImporters(uint topContextIndex)
Loads only the list of importers out of the data stored on disk for the top-context.
Definition: topducontextdynamicdata.cpp:513
QByteArray::constData
const char * constData() const
topducontextdynamicdata.h
KDevelop
Definition: abstractfunctiondeclaration.cpp:27
KDevelop::DUContext
A single context in source code, represented as a node in a directed acyclic graph.
Definition: ducontext.h:72
QByteArray::size
int size() const
QMutexLocker
KDevelop::TopDUContextDynamicData::isOnDisk
bool isOnDisk() const
Whether this top-context is on disk(Either has been loaded, or has been stored)
Definition: topducontextdynamicdata.cpp:629
QVector
KDevelop::TopDUContextDynamicData::clear
void clear()
Definition: topducontextdynamicdata.cpp:488
duchainregister.h
ducontext.h
QFile
KDevelop::DUChainBaseData
Definition: duchainbase.h:59
KDevelop::TopDUContextDynamicData::store
void store()
Stores this top-context to disk.
Definition: topducontextdynamicdata.cpp:669
topducontextdata.h
QByteArray::data
char * data()
KDevelop::DUContext::parentContext
DUContext * parentContext() const
Returns the immediate parent context of this context.
Definition: ducontext.cpp:512
QByteArray
QIODevice::write
qint64 write(const char *data, qint64 maxSize)
KDevelop::DUChainItemSystem::self
static DUChainItemSystem & self()
Access the static DUChainItemSystem instance.
Definition: duchainregister.cpp:93
KDevelop::IndexedDUContext
Represents a context only by its global indices.
Definition: indexedducontext.h:35
KDevelop::DUContext::Import
Represents an imported parent context.
Definition: ducontext.h:256
KDevelop::TopDUContextDynamicData::deleteOnDisk
void deleteOnDisk()
Stores all remnants of this top-context that are on disk. The top-context will be fully dynamic after...
Definition: topducontextdynamicdata.cpp:634
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Thu Mar 4 2021 23:31:17 by doxygen 1.8.16 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kdevplatform/language/duchain

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

kdevelop API Reference

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

Search



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

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