mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 03:12:53 +00:00
388 lines
14 KiB
C++
388 lines
14 KiB
C++
/*
|
|
Copyright 2007 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 "parsingenvironment.h"
|
|
#include "topducontext.h"
|
|
#include "duchainregister.h"
|
|
#include "topducontextdynamicdata.h"
|
|
#include "duchain.h"
|
|
#include "duchainlock.h"
|
|
#include "topducontextdata.h"
|
|
#include <language/backgroundparser/parsejob.h>
|
|
#include <editor/modificationrevisionset.h>
|
|
|
|
#define ENSURE_READ_LOCKED if(indexedTopContext().isValid()) { ENSURE_CHAIN_READ_LOCKED }
|
|
#define ENSURE_WRITE_LOCKED if(indexedTopContext().isValid()) { ENSURE_CHAIN_READ_LOCKED }
|
|
|
|
|
|
namespace KDevelop
|
|
{
|
|
StaticParsingEnvironmentData* ParsingEnvironmentFile::m_staticData = 0;
|
|
|
|
#if 0
|
|
///Wrapper class around objects that are managed through the DUChain, and may contain arbitrary objects
|
|
///that support duchain-like store (IndexedString, StorableSet, and the likes). The object must not contain pointers
|
|
///or other non-persistent data.
|
|
///
|
|
///The object is stored during the normal duchain storage/cleanup cycles.
|
|
|
|
template<class T>
|
|
struct PersistentDUChainObject {
|
|
///@param fileName File-name that will be used to store the data of the object in the duchain directory
|
|
PersistentDUChainObject(QString fileName) {
|
|
object = (T*) new char[sizeof(T)];
|
|
if(!DUChain::self()->addPersistentObject(object, fileName, sizeof(T)))
|
|
{
|
|
//The constructor is called only if the object did not exist yet
|
|
new (object) T();
|
|
}
|
|
}
|
|
~PersistentDUChainObject() {
|
|
DUChain::self()->unregisterPersistentObject(object);
|
|
delete[] object;
|
|
}
|
|
|
|
T* object;
|
|
};
|
|
#endif
|
|
|
|
REGISTER_DUCHAIN_ITEM(ParsingEnvironmentFile);
|
|
|
|
TopDUContext::Features ParsingEnvironmentFile::features() const {
|
|
ENSURE_READ_LOCKED
|
|
|
|
return d_func()->m_features;
|
|
}
|
|
|
|
ParsingEnvironment::ParsingEnvironment() {
|
|
}
|
|
|
|
ParsingEnvironment::~ParsingEnvironment() {
|
|
}
|
|
|
|
IndexedString ParsingEnvironmentFile::url() const {
|
|
ENSURE_READ_LOCKED
|
|
return d_func()->m_url;
|
|
}
|
|
|
|
bool ParsingEnvironmentFile::needsUpdate(const ParsingEnvironment* /*environment*/) const {
|
|
ENSURE_READ_LOCKED
|
|
return d_func()->m_allModificationRevisions.needsUpdate();
|
|
}
|
|
|
|
bool ParsingEnvironmentFile::matchEnvironment(const ParsingEnvironment* /*environment*/) const {
|
|
ENSURE_READ_LOCKED
|
|
return true;
|
|
}
|
|
|
|
void ParsingEnvironmentFile::setTopContext(KDevelop::IndexedTopDUContext context) {
|
|
if(d_func()->m_topContext == context)
|
|
return;
|
|
ENSURE_WRITE_LOCKED
|
|
d_func_dynamic()->m_topContext = context;
|
|
|
|
//Enforce an update of the 'features satisfied' caches
|
|
TopDUContext::Features oldFeatures = features();
|
|
setFeatures(TopDUContext::Empty);
|
|
setFeatures(oldFeatures);
|
|
}
|
|
|
|
KDevelop::IndexedTopDUContext ParsingEnvironmentFile::indexedTopContext() const {
|
|
return d_func()->m_topContext;
|
|
}
|
|
|
|
const ModificationRevisionSet& ParsingEnvironmentFile::allModificationRevisions() const {
|
|
ENSURE_READ_LOCKED
|
|
return d_func()->m_allModificationRevisions;
|
|
}
|
|
|
|
void ParsingEnvironmentFile::addModificationRevisions(const ModificationRevisionSet& revisions) {
|
|
ENSURE_WRITE_LOCKED
|
|
d_func_dynamic()->m_allModificationRevisions += revisions;
|
|
}
|
|
|
|
ParsingEnvironmentFile::ParsingEnvironmentFile(ParsingEnvironmentFileData& data, const IndexedString& url) : DUChainBase(data) {
|
|
|
|
d_func_dynamic()->m_url = url;
|
|
d_func_dynamic()->m_modificationTime = ModificationRevision::revisionForFile(url);
|
|
|
|
addModificationRevision(url, d_func_dynamic()->m_modificationTime);
|
|
Q_ASSERT(d_func()->m_allModificationRevisions.index());
|
|
}
|
|
|
|
ParsingEnvironmentFile::ParsingEnvironmentFile(const IndexedString& url) : DUChainBase(*new ParsingEnvironmentFileData()) {
|
|
d_func_dynamic()->setClassId(this);
|
|
|
|
d_func_dynamic()->m_url = url;
|
|
d_func_dynamic()->m_modificationTime = ModificationRevision::revisionForFile(url);
|
|
|
|
addModificationRevision(url, d_func_dynamic()->m_modificationTime);
|
|
Q_ASSERT(d_func()->m_allModificationRevisions.index());
|
|
}
|
|
|
|
TopDUContext* ParsingEnvironmentFile::topContext() const {
|
|
ENSURE_READ_LOCKED
|
|
return indexedTopContext().data();
|
|
}
|
|
|
|
ParsingEnvironmentFile::~ParsingEnvironmentFile() {
|
|
}
|
|
|
|
ParsingEnvironmentFile::ParsingEnvironmentFile(ParsingEnvironmentFileData& data) : DUChainBase(data) {
|
|
//If this triggers, the item has most probably not been initialized with the correct constructor that takes an IndexedString.
|
|
Q_ASSERT(d_func()->m_allModificationRevisions.index());
|
|
}
|
|
|
|
int ParsingEnvironment::type() const {
|
|
return StandardParsingEnvironment;
|
|
}
|
|
|
|
int ParsingEnvironmentFile::type() const {
|
|
ENSURE_READ_LOCKED
|
|
return StandardParsingEnvironment;
|
|
}
|
|
|
|
bool ParsingEnvironmentFile::isProxyContext() const {
|
|
ENSURE_READ_LOCKED
|
|
return d_func()->m_isProxyContext;
|
|
}
|
|
|
|
void ParsingEnvironmentFile::setIsProxyContext(bool is) {
|
|
ENSURE_WRITE_LOCKED
|
|
d_func_dynamic()->m_isProxyContext = is;
|
|
}
|
|
|
|
QList< KSharedPtr<ParsingEnvironmentFile> > ParsingEnvironmentFile::imports() const {
|
|
ENSURE_READ_LOCKED
|
|
|
|
QList<IndexedDUContext> imp;
|
|
IndexedTopDUContext top = indexedTopContext();
|
|
if(top.isLoaded()) {
|
|
TopDUContext* topCtx = top.data();
|
|
FOREACH_FUNCTION(const DUContext::Import& import, topCtx->d_func()->m_importedContexts)
|
|
imp << import.indexedContext();
|
|
}else{
|
|
imp = TopDUContextDynamicData::loadImports(top.index());
|
|
}
|
|
|
|
QList< KSharedPtr<ParsingEnvironmentFile> > ret;
|
|
foreach(const IndexedDUContext &ctx, imp) {
|
|
KSharedPtr<ParsingEnvironmentFile> item = DUChain::self()->environmentFileForDocument(ctx.topContextIndex());
|
|
if(item) {
|
|
ret << item;
|
|
}else{
|
|
kDebug() << url().str() << indexedTopContext().index() << ": invalid import" << ctx.topContextIndex();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
QList< KSharedPtr<ParsingEnvironmentFile> > ParsingEnvironmentFile::importers() const {
|
|
ENSURE_READ_LOCKED
|
|
|
|
QList<IndexedDUContext> imp;
|
|
IndexedTopDUContext top = indexedTopContext();
|
|
if(top.isLoaded()) {
|
|
TopDUContext* topCtx = top.data();
|
|
FOREACH_FUNCTION(const IndexedDUContext& ctx, topCtx->d_func()->m_importers)
|
|
imp << ctx;
|
|
}else{
|
|
imp = TopDUContextDynamicData::loadImporters(top.index());
|
|
}
|
|
|
|
QList< KSharedPtr<ParsingEnvironmentFile> > ret;
|
|
foreach(const IndexedDUContext &ctx, imp) {
|
|
KSharedPtr<ParsingEnvironmentFile> f = DUChain::self()->environmentFileForDocument(ctx.topContextIndex());
|
|
if(f)
|
|
ret << f;
|
|
else
|
|
kDebug() << url().str() << indexedTopContext().index() << ": invalid importer context" << ctx.topContextIndex();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
QMutex featureSatisfactionMutex;
|
|
|
|
inline bool satisfied(TopDUContext::Features features, TopDUContext::Features required) {
|
|
return (features & required) == required;
|
|
}
|
|
|
|
///Makes sure the file has the correct features attached, and if minimumFeatures contains AllDeclarationsContextsAndUsesForRecursive, then also checks all imports.
|
|
bool ParsingEnvironmentFile::featuresMatch(TopDUContext::Features minimumFeatures, QSet<const ParsingEnvironmentFile*>& checked) const {
|
|
|
|
if(checked.contains(this))
|
|
return true;
|
|
|
|
checked.insert(this);
|
|
|
|
TopDUContext::Features localRequired = (TopDUContext::Features) (minimumFeatures | ParseJob::staticMinimumFeatures(url()));
|
|
|
|
//Check other 'local' requirements
|
|
localRequired = (TopDUContext::Features)(localRequired & (TopDUContext::AllDeclarationsContextsAndUses | TopDUContext::AST));
|
|
|
|
if(!satisfied(features(), localRequired))
|
|
return false;
|
|
|
|
if(ParseJob::hasStaticMinimumFeatures())
|
|
{
|
|
//Do a manual recursion to check whether any of the relevant contexts has static minimum features set
|
|
///@todo Only do this if one of the imports actually has static features attached (by RecursiveImports set intersection)
|
|
foreach(const ParsingEnvironmentFilePointer &import, imports())
|
|
if(!import->featuresMatch(minimumFeatures & TopDUContext::Recursive ? minimumFeatures : ((TopDUContext::Features)0), checked))
|
|
return false;
|
|
}else if(minimumFeatures & TopDUContext::Recursive)
|
|
{
|
|
QMutexLocker lock(&featureSatisfactionMutex);
|
|
|
|
TopDUContext::IndexedRecursiveImports recursiveImportIndices = d_func()->m_importsCache;
|
|
if(recursiveImportIndices.isEmpty()) {
|
|
//Unfortunately, we have to load the top-context
|
|
TopDUContext* top = topContext();
|
|
if(top)
|
|
recursiveImportIndices = top->recursiveImportIndices();
|
|
}
|
|
|
|
///@todo Do not create temporary intersected sets
|
|
|
|
//Use the features-cache to efficiently check the recursive satisfaction of the features
|
|
if(satisfied(minimumFeatures, TopDUContext::AST) && !((m_staticData->ASTSatisfied & recursiveImportIndices) == recursiveImportIndices))
|
|
return false;
|
|
|
|
if(satisfied(minimumFeatures, TopDUContext::AllDeclarationsContextsAndUses))
|
|
return (m_staticData->allDeclarationsAndUsesSatisfied & recursiveImportIndices) == recursiveImportIndices;
|
|
else if(satisfied(minimumFeatures, TopDUContext::AllDeclarationsAndContexts))
|
|
return (m_staticData->allDeclarationsSatisfied & recursiveImportIndices) == recursiveImportIndices;
|
|
else if(satisfied(minimumFeatures, TopDUContext::VisibleDeclarationsAndContexts))
|
|
return (m_staticData->visibleDeclarationsSatisfied & recursiveImportIndices) == recursiveImportIndices;
|
|
else if(satisfied(minimumFeatures, TopDUContext::SimplifiedVisibleDeclarationsAndContexts))
|
|
return (m_staticData->simplifiedVisibleDeclarationsSatisfied & recursiveImportIndices) == recursiveImportIndices;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ParsingEnvironmentFile::setFeatures(TopDUContext::Features features) {
|
|
if(d_func()->m_features == features)
|
|
return;
|
|
ENSURE_WRITE_LOCKED
|
|
d_func_dynamic()->m_features = features;
|
|
|
|
if(indexedTopContext().isValid())
|
|
{
|
|
QMutexLocker lock(&featureSatisfactionMutex);
|
|
|
|
if(!satisfied(features, TopDUContext::SimplifiedVisibleDeclarationsAndContexts))
|
|
m_staticData->simplifiedVisibleDeclarationsSatisfied.remove(indexedTopContext());
|
|
else
|
|
m_staticData->simplifiedVisibleDeclarationsSatisfied.insert(indexedTopContext());
|
|
|
|
if(!satisfied(features, TopDUContext::VisibleDeclarationsAndContexts))
|
|
m_staticData->visibleDeclarationsSatisfied.remove(indexedTopContext());
|
|
else
|
|
m_staticData->visibleDeclarationsSatisfied.insert(indexedTopContext());
|
|
|
|
if(!satisfied(features, TopDUContext::AllDeclarationsAndContexts))
|
|
m_staticData->allDeclarationsSatisfied.remove(indexedTopContext());
|
|
else
|
|
m_staticData->allDeclarationsSatisfied.insert(indexedTopContext());
|
|
|
|
if(!satisfied(features, TopDUContext::AllDeclarationsContextsAndUses))
|
|
m_staticData->allDeclarationsAndUsesSatisfied.remove(indexedTopContext());
|
|
else
|
|
m_staticData->allDeclarationsAndUsesSatisfied.insert(indexedTopContext());
|
|
|
|
if(!satisfied(features, TopDUContext::AST))
|
|
m_staticData->ASTSatisfied.remove(indexedTopContext());
|
|
else
|
|
m_staticData->ASTSatisfied.insert(indexedTopContext());
|
|
}
|
|
}
|
|
|
|
bool ParsingEnvironmentFile::featuresSatisfied(KDevelop::TopDUContext::Features minimumFeatures) const {
|
|
ENSURE_READ_LOCKED
|
|
QSet<const ParsingEnvironmentFile*> checked;
|
|
if(minimumFeatures & TopDUContext::ForceUpdate)
|
|
return false;
|
|
return featuresMatch(minimumFeatures, checked);
|
|
}
|
|
|
|
void ParsingEnvironmentFile::clearModificationRevisions() {
|
|
ENSURE_WRITE_LOCKED
|
|
d_func_dynamic()->m_allModificationRevisions.clear();
|
|
d_func_dynamic()->m_allModificationRevisions.addModificationRevision(d_func()->m_url, d_func()->m_modificationTime);
|
|
}
|
|
|
|
void ParsingEnvironmentFile::addModificationRevision(const IndexedString& url, const ModificationRevision& revision) {
|
|
ENSURE_WRITE_LOCKED
|
|
d_func_dynamic()->m_allModificationRevisions.addModificationRevision(url, revision);
|
|
{
|
|
//Test
|
|
Q_ASSERT(d_func_dynamic()->m_allModificationRevisions.index());
|
|
bool result = d_func_dynamic()->m_allModificationRevisions.removeModificationRevision(url, revision);
|
|
Q_UNUSED( result );
|
|
Q_ASSERT( result );
|
|
d_func_dynamic()->m_allModificationRevisions.addModificationRevision(url, revision);
|
|
}
|
|
}
|
|
|
|
void ParsingEnvironmentFile::setModificationRevision( const KDevelop::ModificationRevision& rev ) {
|
|
ENSURE_WRITE_LOCKED
|
|
|
|
Q_ASSERT(d_func_dynamic()->m_allModificationRevisions.index());
|
|
bool result = d_func_dynamic()->m_allModificationRevisions.removeModificationRevision(d_func()->m_url, d_func()->m_modificationTime);
|
|
Q_ASSERT( result );
|
|
Q_UNUSED( result );
|
|
|
|
#ifdef LEXERCACHE_DEBUG
|
|
if(debugging()) {
|
|
kDebug() << id(this) << "setting modification-revision" << rev.toString();
|
|
}
|
|
#endif
|
|
d_func_dynamic()->m_modificationTime = rev;
|
|
#ifdef LEXERCACHE_DEBUG
|
|
if(debugging()) {
|
|
kDebug() << id(this) << "new modification-revision" << m_modificationTime;
|
|
}
|
|
#endif
|
|
d_func_dynamic()->m_allModificationRevisions.addModificationRevision(d_func()->m_url, d_func()->m_modificationTime);
|
|
}
|
|
|
|
KDevelop::ModificationRevision ParsingEnvironmentFile::modificationRevision() const {
|
|
ENSURE_READ_LOCKED
|
|
return d_func()->m_modificationTime;
|
|
}
|
|
|
|
IndexedString ParsingEnvironmentFile::language() const {
|
|
return d_func()->m_language;
|
|
}
|
|
|
|
void ParsingEnvironmentFile::setLanguage(IndexedString language) {
|
|
d_func_dynamic()->m_language = language;
|
|
}
|
|
|
|
const KDevelop::TopDUContext::IndexedRecursiveImports& ParsingEnvironmentFile::importsCache() const
|
|
{
|
|
return d_func()->m_importsCache;
|
|
}
|
|
|
|
void ParsingEnvironmentFile::setImportsCache(const KDevelop::TopDUContext::IndexedRecursiveImports& importsCache)
|
|
{
|
|
d_func_dynamic()->m_importsCache = importsCache;
|
|
}
|
|
|
|
} //KDevelop
|