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 }