1 /*
2 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
3 SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6 */
7
8 #include "duchainbase.h"
9
10 #include <QMutexLocker>
11 #include <QThreadStorage>
12
13 #include "duchainpointer.h"
14 #include "parsingenvironment.h"
15 #include <serialization/indexedstring.h>
16 #include "topducontext.h"
17 #include "duchainregister.h"
18 #include <util/foregroundlock.h>
19 #include <interfaces/icore.h>
20 #include <interfaces/ilanguagecontroller.h>
21 #include <backgroundparser/backgroundparser.h>
22 #include <backgroundparser/documentchangetracker.h>
23
24 namespace KDevelop {
25 REGISTER_DUCHAIN_ITEM(DUChainBase);
26
classSize() const27 uint DUChainBaseData::classSize() const
28 {
29 return DUChainItemSystem::self().dataClassSize(*this);
30 }
31
DUChainBase(const RangeInRevision & range)32 DUChainBase::DUChainBase(const RangeInRevision& range)
33 : d_ptr(new DUChainBaseData)
34 {
35 d_func_dynamic()->m_range = range;
36 d_func_dynamic()->setClassId(this);
37 }
38
DUChainBase(DUChainBaseData & dd,const RangeInRevision & range)39 DUChainBase::DUChainBase(DUChainBaseData& dd, const RangeInRevision& range)
40 : d_ptr(&dd)
41 {
42 d_func_dynamic()->m_range = range;
43 }
44
DUChainBase(DUChainBaseData & dd)45 DUChainBase::DUChainBase(DUChainBaseData& dd)
46 : d_ptr(&dd)
47 {
48 }
49
DUChainBase(DUChainBase & rhs)50 DUChainBase::DUChainBase(DUChainBase& rhs)
51 : d_ptr(new DUChainBaseData(*rhs.d_func()))
52 {
53 d_func_dynamic()->setClassId(this);
54 }
55
url() const56 IndexedString DUChainBase::url() const
57 {
58 TopDUContext* top = topContext();
59 if (top)
60 return top->TopDUContext::url();
61 else
62 return IndexedString();
63 }
64
setData(DUChainBaseData * data,bool constructorCalled)65 void DUChainBase::setData(DUChainBaseData* data, bool constructorCalled)
66 {
67 Q_ASSERT(data);
68 Q_ASSERT(d_ptr);
69
70 if (d_ptr->m_dynamic) {
71 Q_ASSERT(constructorCalled);
72 DUChainItemSystem::self().deleteDynamicData(d_ptr);
73 } else if (constructorCalled) {
74 // If the data object isn't dynamic, then it is part of a central repository, and cannot be deleted here.
75 // we still need to call the destructor though
76 KDevelop::DUChainItemSystem::self().callDestructor(static_cast<DUChainBaseData*>(d_ptr));
77 }
78
79 d_ptr = data;
80 }
81
~DUChainBase()82 DUChainBase::~DUChainBase()
83 {
84 if (m_ptr)
85 m_ptr->m_base = nullptr;
86
87 if (d_ptr->m_dynamic) {
88 DUChainItemSystem::self().deleteDynamicData(d_ptr);
89 d_ptr = nullptr;
90 }
91 }
92
topContext() const93 TopDUContext* DUChainBase::topContext() const
94 {
95 ///@todo Move the reference to the top-context right into this class, as it's common to all inheriters
96 return nullptr;
97 }
98
99 namespace {
100 QMutex weakPointerMutex;
101 }
102
weakPointer() const103 const QExplicitlySharedDataPointer<DUChainPointerData>& DUChainBase::weakPointer() const
104 {
105 if (!m_ptr) {
106 QMutexLocker lock(&weakPointerMutex); // The mutex is used to make sure we don't create m_ptr twice at the same time
107 m_ptr = new DUChainPointerData(const_cast<DUChainBase*>(this));
108 m_ptr->m_base = const_cast<DUChainBase*>(this);
109 }
110
111 return m_ptr;
112 }
113
rebuildDynamicData(DUContext * parent,uint ownIndex)114 void DUChainBase::rebuildDynamicData(DUContext* parent, uint ownIndex)
115 {
116 Q_UNUSED(parent)
117 Q_UNUSED(ownIndex)
118 }
119
makeDynamic()120 void DUChainBase::makeDynamic()
121 {
122 Q_ASSERT(d_ptr);
123 if (!d_func()->m_dynamic) {
124 Q_ASSERT(d_func()->classId);
125 DUChainBaseData* newData = DUChainItemSystem::self().cloneData(*d_func());
126 {
127 auto* const baseData = static_cast<DUChainBaseData*>(d_ptr);
128 const DUChainReferenceCountingEnabler rcEnabler(d_ptr, DUChainItemSystem::self().dynamicSize(*baseData));
129 //We don't delete the previous data, because it's embedded in the top-context when it isn't dynamic.
130 //However we do call the destructor, to keep semantic stuff like reference-counting within the data class working correctly.
131 DUChainItemSystem::self().callDestructor(baseData);
132 }
133 d_ptr = newData;
134 Q_ASSERT(d_ptr);
135 Q_ASSERT(d_func()->m_dynamic);
136 Q_ASSERT(d_func()->classId);
137 }
138 }
139
range() const140 RangeInRevision DUChainBase::range() const
141 {
142 return d_func()->m_range;
143 }
144
rangeInCurrentRevision() const145 KTextEditor::Range DUChainBase::rangeInCurrentRevision() const
146 {
147 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
148
149 if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
150 qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
151 return tracker->transformToCurrentRevision(d_func()->m_range, revision);
152 }
153
154 // If the document is not open, we can simply cast the range over, as no translation can be done
155 return d_func()->m_range.castToSimpleRange();
156 }
157
createRangeMoving() const158 PersistentMovingRange::Ptr DUChainBase::createRangeMoving() const
159 {
160 VERIFY_FOREGROUND_LOCKED
161 return PersistentMovingRange::Ptr(new PersistentMovingRange(rangeInCurrentRevision(), url()));
162 }
163
transformToLocalRevision(const KTextEditor::Cursor & cursor) const164 CursorInRevision DUChainBase::transformToLocalRevision(const KTextEditor::Cursor& cursor) const
165 {
166 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
167
168 if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
169 qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
170 return tracker->transformToRevision(cursor, revision);
171 }
172
173 return CursorInRevision::castFromSimpleCursor(cursor);
174 }
175
transformToLocalRevision(const KTextEditor::Range & range) const176 RangeInRevision DUChainBase::transformToLocalRevision(const KTextEditor::Range& range) const
177 {
178 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
179
180 if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
181 qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
182 return tracker->transformToRevision(range, revision);
183 }
184
185 return RangeInRevision::castFromSimpleRange(range);
186 }
187
transformFromLocalRevision(const KDevelop::RangeInRevision & range) const188 KTextEditor::Range DUChainBase::transformFromLocalRevision(const KDevelop::RangeInRevision& range) const
189 {
190 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
191
192 if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
193 qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
194 return tracker->transformToCurrentRevision(range, revision);
195 }
196
197 return range.castToSimpleRange();
198 }
199
transformFromLocalRevision(const KDevelop::CursorInRevision & cursor) const200 KTextEditor::Cursor DUChainBase::transformFromLocalRevision(const KDevelop::CursorInRevision& cursor) const
201 {
202 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
203
204 if (tracker && topContext() && topContext()->parsingEnvironmentFile()) {
205 qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
206 return tracker->transformToCurrentRevision(cursor, revision);
207 }
208
209 return cursor.castToSimpleCursor();
210 }
211
setRange(const RangeInRevision & range)212 void DUChainBase::setRange(const RangeInRevision& range)
213 {
214 d_func_dynamic()->m_range = range;
215 }
216
217 QThreadStorage<bool> shouldCreateConstantDataStorage;
218
shouldCreateConstantData()219 bool& DUChainBaseData::shouldCreateConstantData()
220 {
221 return shouldCreateConstantDataStorage.localData();
222 }
223 }
224