File indexing completed on 2024-05-12 04:37:58

0001 /*
0002     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "duchainbase.h"
0009 
0010 #include <QMutexLocker>
0011 #include <QThreadStorage>
0012 
0013 #include "duchainpointer.h"
0014 #include "parsingenvironment.h"
0015 #include <serialization/indexedstring.h>
0016 #include "topducontext.h"
0017 #include "duchainregister.h"
0018 #include <util/foregroundlock.h>
0019 #include <interfaces/icore.h>
0020 #include <interfaces/ilanguagecontroller.h>
0021 #include <backgroundparser/backgroundparser.h>
0022 #include <backgroundparser/documentchangetracker.h>
0023 
0024 namespace KDevelop {
0025 REGISTER_DUCHAIN_ITEM(DUChainBase);
0026 
0027 uint DUChainBaseData::classSize() const
0028 {
0029     return DUChainItemSystem::self().dataClassSize(*this);
0030 }
0031 
0032 DUChainBase::DUChainBase(const RangeInRevision& range)
0033     : d_ptr(new DUChainBaseData)
0034 {
0035     d_func_dynamic()->m_range = range;
0036     d_func_dynamic()->setClassId(this);
0037 }
0038 
0039 DUChainBase::DUChainBase(DUChainBaseData& dd, const RangeInRevision& range)
0040     : d_ptr(&dd)
0041 {
0042     d_func_dynamic()->m_range = range;
0043 }
0044 
0045 DUChainBase::DUChainBase(DUChainBaseData& dd)
0046     : d_ptr(&dd)
0047 {
0048 }
0049 
0050 DUChainBase::DUChainBase(DUChainBase& rhs)
0051     : d_ptr(new DUChainBaseData(*rhs.d_func()))
0052 {
0053     d_func_dynamic()->setClassId(this);
0054 }
0055 
0056 IndexedString DUChainBase::url() const
0057 {
0058     TopDUContext* top = topContext();
0059     if (top)
0060         return top->TopDUContext::url();
0061     else
0062         return IndexedString();
0063 }
0064 
0065 void DUChainBase::setData(DUChainBaseData* data, bool constructorCalled)
0066 {
0067     Q_ASSERT(data);
0068     Q_ASSERT(d_ptr);
0069 
0070     if (d_ptr->m_dynamic) {
0071         Q_ASSERT(constructorCalled);
0072         DUChainItemSystem::self().deleteDynamicData(d_ptr);
0073     } else if (constructorCalled) {
0074         // If the data object isn't dynamic, then it is part of a central repository, and cannot be deleted here.
0075         // we still need to call the destructor though
0076         KDevelop::DUChainItemSystem::self().callDestructor(static_cast<DUChainBaseData*>(d_ptr));
0077     }
0078 
0079     d_ptr = data;
0080 }
0081 
0082 DUChainBase::~DUChainBase()
0083 {
0084     if (m_ptr)
0085         m_ptr->m_base = nullptr;
0086 
0087     if (d_ptr->m_dynamic) {
0088         DUChainItemSystem::self().deleteDynamicData(d_ptr);
0089         d_ptr = nullptr;
0090     }
0091 }
0092 
0093 TopDUContext* DUChainBase::topContext() const
0094 {
0095     ///@todo Move the reference to the top-context right into this class, as it's common to all inheriters
0096     return nullptr;
0097 }
0098 
0099 namespace {
0100 QMutex weakPointerMutex;
0101 }
0102 
0103 const QExplicitlySharedDataPointer<DUChainPointerData>& DUChainBase::weakPointer() const
0104 {
0105     if (!m_ptr) {
0106         QMutexLocker lock(&weakPointerMutex); // The mutex is used to make sure we don't create m_ptr twice at the same time
0107         m_ptr = new DUChainPointerData(const_cast<DUChainBase*>(this));
0108         m_ptr->m_base = const_cast<DUChainBase*>(this);
0109     }
0110 
0111     return m_ptr;
0112 }
0113 
0114 void DUChainBase::rebuildDynamicData(DUContext* parent, uint ownIndex)
0115 {
0116     Q_UNUSED(parent)
0117     Q_UNUSED(ownIndex)
0118 }
0119 
0120 void DUChainBase::makeDynamic()
0121 {
0122     Q_ASSERT(d_ptr);
0123     if (!d_func()->m_dynamic) {
0124         Q_ASSERT(d_func()->classId);
0125         DUChainBaseData* newData = DUChainItemSystem::self().cloneData(*d_func());
0126         {
0127             auto* const baseData = static_cast<DUChainBaseData*>(d_ptr);
0128             const DUChainReferenceCountingEnabler rcEnabler(d_ptr, DUChainItemSystem::self().dynamicSize(*baseData));
0129             //We don't delete the previous data, because it's embedded in the top-context when it isn't dynamic.
0130             //However we do call the destructor, to keep semantic stuff like reference-counting within the data class working correctly.
0131             DUChainItemSystem::self().callDestructor(baseData);
0132         }
0133         d_ptr = newData;
0134         Q_ASSERT(d_ptr);
0135         Q_ASSERT(d_func()->m_dynamic);
0136         Q_ASSERT(d_func()->classId);
0137     }
0138 }
0139 
0140 RangeInRevision DUChainBase::range() const
0141 {
0142     return d_func()->m_range;
0143 }
0144 
0145 KTextEditor::Range DUChainBase::rangeInCurrentRevision() const
0146 {
0147     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
0148 
0149     if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
0150         qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
0151         return tracker->transformToCurrentRevision(d_func()->m_range, revision);
0152     }
0153 
0154     // If the document is not open, we can simply cast the range over, as no translation can be done
0155     return d_func()->m_range.castToSimpleRange();
0156 }
0157 
0158 PersistentMovingRange::Ptr DUChainBase::createRangeMoving() const
0159 {
0160     VERIFY_FOREGROUND_LOCKED
0161     return PersistentMovingRange::Ptr(new PersistentMovingRange(rangeInCurrentRevision(), url()));
0162 }
0163 
0164 CursorInRevision DUChainBase::transformToLocalRevision(const KTextEditor::Cursor& cursor) const
0165 {
0166     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
0167 
0168     if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
0169         qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
0170         return tracker->transformToRevision(cursor, revision);
0171     }
0172 
0173     return CursorInRevision::castFromSimpleCursor(cursor);
0174 }
0175 
0176 RangeInRevision DUChainBase::transformToLocalRevision(const KTextEditor::Range& range) const
0177 {
0178     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
0179 
0180     if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
0181         qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
0182         return tracker->transformToRevision(range, revision);
0183     }
0184 
0185     return RangeInRevision::castFromSimpleRange(range);
0186 }
0187 
0188 KTextEditor::Range DUChainBase::transformFromLocalRevision(const KDevelop::RangeInRevision& range) const
0189 {
0190     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
0191 
0192     if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
0193         qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
0194         return tracker->transformToCurrentRevision(range, revision);
0195     }
0196 
0197     return range.castToSimpleRange();
0198 }
0199 
0200 KTextEditor::Cursor DUChainBase::transformFromLocalRevision(const KDevelop::CursorInRevision& cursor) const
0201 {
0202     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
0203 
0204     if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
0205         qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
0206         return tracker->transformToCurrentRevision(cursor, revision);
0207     }
0208 
0209     return cursor.castToSimpleCursor();
0210 }
0211 
0212 void DUChainBase::setRange(const RangeInRevision& range)
0213 {
0214     d_func_dynamic()->m_range = range;
0215 }
0216 
0217 QThreadStorage<bool> shouldCreateConstantDataStorage;
0218 
0219 bool& DUChainBaseData::shouldCreateConstantData()
0220 {
0221     return shouldCreateConstantDataStorage.localData();
0222 }
0223 }