kde-extraapps/kdevplatform/language/duchain/duchainbase.cpp
2015-07-26 14:23:17 +03:00

243 lines
7.5 KiB
C++

/* This is part of KDevelop
Copyright 2006 Hamish Rodda <rodda@kde.org>
Copyright 2007/2008 David Nolden <david.nolden.kdevelop@art-master.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "duchainbase.h"
#include <QMutexLocker>
#include <QThreadStorage>
#include "duchainpointer.h"
#include "parsingenvironment.h"
#include "indexedstring.h"
#include "topducontext.h"
#include "duchainregister.h"
#include <editor/simplerange.h>
#include <interfaces/foregroundlock.h>
#include <interfaces/icore.h>
#include <interfaces/ilanguagecontroller.h>
#include <backgroundparser/backgroundparser.h>
#include <backgroundparser/documentchangetracker.h>
#include <ktexteditor/movinginterface.h>
#include <editor/persistentmovingrange.h>
namespace KDevelop
{
REGISTER_DUCHAIN_ITEM(DUChainBase);
uint DUChainBaseData::classSize() const {
return DUChainItemSystem::self().dataClassSize(*this);
}
DUChainBase::DUChainBase(const RangeInRevision& range)
: d_ptr(new DUChainBaseData), m_ptr( 0L )
{
d_func_dynamic()->m_range = range;
d_func_dynamic()->setClassId(this);
}
DUChainBase::DUChainBase( DUChainBaseData & dd, const RangeInRevision& range )
: d_ptr( &dd ), m_ptr( 0 )
{
d_func_dynamic()->m_range = range;
}
DUChainBase::DUChainBase( DUChainBaseData & dd )
: d_ptr( &dd ), m_ptr( 0 )
{
}
DUChainBase::DUChainBase( DUChainBase& rhs )
: d_ptr( new DUChainBaseData(*rhs.d_func()) ), m_ptr( 0 )
{
d_func_dynamic()->setClassId(this);
}
IndexedString DUChainBase::url() const
{
TopDUContext* top = topContext();
if(top)
return top->TopDUContext::url();
else
return IndexedString();
}
void DUChainBase::setData(DUChainBaseData* data, bool constructorCalled)
{
Q_ASSERT(data);
Q_ASSERT(d_ptr);
if(constructorCalled)
KDevelop::DUChainItemSystem::self().callDestructor(static_cast<DUChainBaseData*>(d_ptr));
if(d_ptr->m_dynamic) // If the data object isn't dynamic, then it is part of a central repository, and cannot be deleted here.
delete d_ptr;
d_ptr = data;
}
DUChainBase::~DUChainBase()
{
if (m_ptr)
m_ptr->m_base = 0;
if(d_ptr->m_dynamic)
{
KDevelop::DUChainItemSystem::self().callDestructor(d_ptr);
delete d_ptr;
d_ptr = 0;
}
}
TopDUContext* DUChainBase::topContext() const
{
///@todo Move the reference to the top-context right into this class, as it's common to all inheriters
return 0;
}
namespace {
QMutex weakPointerMutex;
};
const KSharedPtr<DUChainPointerData>& DUChainBase::weakPointer() const
{
if (!m_ptr) {
QMutexLocker lock(&weakPointerMutex); // The mutex is used to make sure we don't create m_ptr twice at the same time
m_ptr = new DUChainPointerData(const_cast<DUChainBase*>(this));
m_ptr->m_base = const_cast<DUChainBase*>(this);
}
return m_ptr;
}
void DUChainBase::rebuildDynamicData(DUContext* parent, uint ownIndex)
{
Q_UNUSED(parent)
Q_UNUSED(ownIndex)
}
void DUChainBase::makeDynamic() {
Q_ASSERT(d_ptr);
if(!d_func()->m_dynamic) {
Q_ASSERT(d_func()->classId);
DUChainBaseData* newData = DUChainItemSystem::self().cloneData(*d_func());
enableDUChainReferenceCounting(d_ptr, DUChainItemSystem::self().dynamicSize(*static_cast<DUChainBaseData*>(d_ptr)));
//We don't delete the previous data, because it's embedded in the top-context when it isn't dynamic.
//However we do call the destructor, to keep semantic stuff like reference-counting within the data class working correctly.
KDevelop::DUChainItemSystem::self().callDestructor(static_cast<DUChainBaseData*>(d_ptr));
disableDUChainReferenceCounting(d_ptr);
d_ptr = newData;
Q_ASSERT(d_ptr);
Q_ASSERT(d_func()->m_dynamic);
Q_ASSERT(d_func()->classId);
}
}
RangeInRevision DUChainBase::range() const
{
return d_func()->m_range;
}
SimpleRange DUChainBase::rangeInCurrentRevision() const
{
DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
if(tracker && topContext() && topContext()->parsingEnvironmentFile())
{
qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
return tracker->transformToCurrentRevision(d_func()->m_range, revision);
}
// If the document is not open, we can simply cast the range over, as no translation can be done
return d_func()->m_range.castToSimpleRange();
}
PersistentMovingRange::Ptr DUChainBase::createRangeMoving() const
{
VERIFY_FOREGROUND_LOCKED
return PersistentMovingRange::Ptr(new PersistentMovingRange(rangeInCurrentRevision(), url()));
}
CursorInRevision DUChainBase::transformToLocalRevision(const KDevelop::SimpleCursor& cursor) const
{
DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
if(tracker && topContext() && topContext()->parsingEnvironmentFile())
{
qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
return tracker->transformToRevision(cursor, revision);
}
return CursorInRevision::castFromSimpleCursor(cursor);
}
RangeInRevision DUChainBase::transformToLocalRevision(const KDevelop::SimpleRange& range) const
{
DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
if(tracker && topContext() && topContext()->parsingEnvironmentFile())
{
qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
return tracker->transformToRevision(range, revision);
}
return RangeInRevision::castFromSimpleRange(range);
}
SimpleRange DUChainBase::transformFromLocalRevision(const KDevelop::RangeInRevision& range) const
{
DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
if(tracker && topContext() && topContext()->parsingEnvironmentFile())
{
qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
return tracker->transformToCurrentRevision(range, revision);
}
return range.castToSimpleRange();
}
SimpleCursor DUChainBase::transformFromLocalRevision(const KDevelop::CursorInRevision& cursor) const
{
DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url());
if(tracker && topContext() && topContext()->parsingEnvironmentFile())
{
qint64 revision = topContext()->parsingEnvironmentFile()->modificationRevision().revision;
return tracker->transformToCurrentRevision(cursor, revision);
}
return cursor.castToSimpleCursor();
}
void DUChainBase::setRange(const RangeInRevision& range)
{
d_func_dynamic()->m_range = range;
}
QThreadStorage<bool> shouldCreateConstantDataStorage;
bool& DUChainBaseData::shouldCreateConstantData()
{
return shouldCreateConstantDataStorage.localData();
}
}
// kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on