You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
439 lines
18 KiB
439 lines
18 KiB
/***************************************************************************
|
|
copyright : (C) 2006 by David Nolden
|
|
email : david.nolden.kdevelop@art-master.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
#include <tqtl.h>
|
|
#include <typeinfo>
|
|
#include "simpletypenamespace.h"
|
|
#include "simpletypecachebinder.h"
|
|
|
|
#include "safetycounter.h"
|
|
|
|
//#define PHYSICAL_IMPORT
|
|
//Necessary, because else nested members cannot search the correct scope
|
|
#define PHYSICALLY_IMPORT_NAMESPACES
|
|
|
|
extern SafetyCounter safetyCounter;
|
|
|
|
//SimpleTypeNamespace implementation
|
|
|
|
TypePointer SimpleTypeNamespace::clone() {
|
|
return new SimpleTypeCachedNamespace( this );
|
|
}
|
|
|
|
SimpleTypeNamespace::SimpleTypeNamespace( const TQStringList& fakeScope, const TQStringList& realScope ) : SimpleTypeImpl( fakeScope ), m_currentSlaveId(0) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": created namespace-proxy with real scope \"" << realScope.join( "::" ) << "\"" << endl );
|
|
SimpleType cm = SimpleType( realScope, HashedStringSet(), RepoCodeModel );
|
|
SimpleType ct = SimpleType( realScope, HashedStringSet(), RepoCatalog );
|
|
cm = SimpleType( cm->clone() );
|
|
ct = SimpleType( ct->clone() );
|
|
cm->setMasterProxy( this );
|
|
ct->setMasterProxy( this );
|
|
addImport( cm->desc() );
|
|
addImport( ct->desc() );
|
|
}
|
|
|
|
SimpleTypeNamespace::SimpleTypeNamespace( const TQStringList& fakeScope ) : SimpleTypeImpl( fakeScope ), m_currentSlaveId(0) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": created namespace-proxy" << endl );
|
|
}
|
|
|
|
SimpleTypeNamespace::SimpleTypeNamespace( SimpleTypeNamespace* ns ) : SimpleTypeImpl( ns ), m_currentSlaveId(0) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": cloning namespace" << endl );
|
|
m_aliases = ns->m_aliases;
|
|
m_activeSlaves = ns->m_activeSlaves;
|
|
m_activeSlaveGroups = ns->m_activeSlaveGroups;
|
|
}
|
|
|
|
void SimpleTypeNamespace::breakReferences() {
|
|
m_aliases.clear();
|
|
m_activeSlaves.clear();
|
|
SimpleTypeImpl::breakReferences();
|
|
}
|
|
|
|
|
|
SimpleTypeImpl::MemberInfo SimpleTypeNamespace::findMember( TypeDesc name, MemberInfo::MemberType type ) {
|
|
std::set<HashedString> ignore;
|
|
SimpleTypeImpl::MemberInfo ret = findMember( name, type, ignore );
|
|
///chooseSpecialization( ret ); should not be necessary
|
|
return ret;
|
|
}
|
|
|
|
TQValueList<TypePointer> SimpleTypeNamespace::getMemberClasses( const TypeDesc& name ) {
|
|
std::set<HashedString> ignore;
|
|
|
|
return getMemberClasses( name, ignore );
|
|
}
|
|
|
|
TQValueList<TypePointer> SimpleTypeNamespace::getMemberClasses( const TypeDesc& name, std::set<HashedString>& ignore ) {
|
|
HashedString myName = HashedString( scope().join( "::" ) +"%"+typeid( *this ).name() );
|
|
if ( ignore.find( myName ) != ignore.end() || !safetyCounter )
|
|
return TQValueList<TypePointer>();
|
|
|
|
ignore.insert( myName );
|
|
|
|
TQValueList<TypePointer> ret;
|
|
|
|
SlaveList l = getSlaves( name.includeFiles() );
|
|
for ( SlaveList::iterator it = l.begin(); it != l.end(); ++it ) {
|
|
if (( *it ).first.first.resolved() ) {
|
|
SimpleTypeNamespace* ns = dynamic_cast<SimpleTypeNamespace*>(( *it ).first.first.resolved().data() );
|
|
if ( !ns ) {
|
|
HashedString thatName = HashedString(( *it ).first.first.resolved()->scope().join( "::" ) +"%"+typeid( *( *it ).first.first.resolved() ).name() );
|
|
if ( ignore.find( thatName ) != ignore.end() ) continue;
|
|
ignore.insert( thatName );
|
|
ret += ( *it ).first.first.resolved()->getMemberClasses( name );
|
|
} else {
|
|
ret += ns->getMemberClasses( name, ignore );
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
SimpleTypeImpl::MemberInfo SimpleTypeNamespace::findMember( TypeDesc name, MemberInfo::MemberType type, std::set
|
|
<HashedString>& ignore ) {
|
|
MemberInfo mem;
|
|
mem.name = "";
|
|
mem.memberType = MemberInfo::NotFound;
|
|
HashedString myName = HashedString( scope().join( "::" ) +"%"+typeid( *this ).name() );
|
|
if ( ignore.find( myName ) != ignore.end() || !safetyCounter )
|
|
return mem;
|
|
ignore.insert( myName );
|
|
|
|
SlaveList l = getSlaves( name.includeFiles() );
|
|
|
|
ImportList m_aliasImports;
|
|
|
|
AliasMap::iterator itt = m_aliases.find( name.name() );
|
|
|
|
if ( itt != m_aliases.end() && !( *itt ).empty() ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": namespace-sub-aliases \"" << name.name() << "\"" << "\" requested, locating targets" << endl );
|
|
|
|
for ( ImportList::iterator it = ( *itt ).begin(); it != ( *itt ).end(); ++it ) {
|
|
if ( !( /*name.includeFiles().size() < 1 ||*/ ( *it ).files <= name.includeFiles() ) ) continue; //filter the slave by the include-files
|
|
|
|
ifVerbose( dbg() << "\"" << str() << "\": namespace-sub-aliases \"" << name.name() << "\": taking target \"" << ( *it ).import.fullNameChain() << "\"" << endl );
|
|
/*TypeDesc d( (*it).import );
|
|
d.setIncludeFiles( name.includeFiles() );*/
|
|
m_aliasImports.insert( *it ); //@todo: what include-files should be used for searching the namespace?
|
|
/*LocateResult l = locateDecType( d, SimpleTypeImpl::Normal, 0, SimpleTypeImpl::MemberInfo::Namespace );
|
|
if ( !l || !l->resolved() || !dynamic_cast<SimpleTypeNamespace*>( l->resolved().data() ) ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": namespace-sub-aliases \"" << name.name() << "\" -> \"" << ( *it ).import.fullNameChain() << "\" could not be resolved" << endl );
|
|
} else {
|
|
m_aliasImports.insert( Import( d.includeFiles(), l, this ) );
|
|
}*/
|
|
}
|
|
}
|
|
|
|
for ( SlaveList::iterator it = l.begin(); it != l.end(); ++it ) {
|
|
if ( !( *it ).first.first.resolved() )
|
|
continue;
|
|
if ( ignore.find( HashedString(( *it ).first.first.resolved()->scope().join( "::" ) +"%"+ typeid( *( *it ).first.first.resolved() ).name() ) ) != ignore.end() ) continue;
|
|
|
|
ifVerbose( dbg() << "\"" << str() << "\": redirecting search for \"" << name.name() << "\" to \"" << ( *it ) .first.first.fullNameChain() << "\"" << endl );
|
|
if ( !( *it ).first.first.resolved() ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": while search for \"" << name.name() << "\": Imported namespace \"" << ( *it ) .first.first.fullNameChain() << "\" is not resolved(should have been resolved in updateAliases)" << endl );
|
|
continue;
|
|
}
|
|
ifVerbose( dbg() << "\"Class-type: " << typeid( *( *it ).first.first.resolved().data() ).name() << ")" << endl );
|
|
SimpleTypeNamespace* ns = dynamic_cast<SimpleTypeNamespace*>(( *it ).first.first.resolved().data() );
|
|
|
|
if ( ns )
|
|
mem = ns->findMember( name , type, ignore );
|
|
else
|
|
mem = ( *it ).first.first.resolved()->findMember( name, type );
|
|
|
|
if ( mem ) {
|
|
if ( mem.memberType != MemberInfo::Namespace ) {
|
|
#ifdef PHYSICAL_IMPORT
|
|
TypePointer b = mem.build();
|
|
if ( b && !( b->parent()->masterProxy().data() == this ) ) {
|
|
b = b ->clone(); //expensive, cache is not shared
|
|
b->setParent( this );
|
|
|
|
mem.setBuilt( b );
|
|
}
|
|
#else
|
|
if( mem.memberType == MemberInfo::NestedType )
|
|
chooseSpecialization( mem );
|
|
TypePointer b = mem.build();
|
|
if( b && b->parent() && b->parent()->masterProxy().data() == this )
|
|
b->setParent( this );
|
|
#endif
|
|
return mem;
|
|
} else {
|
|
TypePointer b = mem.build();
|
|
|
|
if ( b )
|
|
m_aliasImports.insert( Import( IncludeFiles(), b->desc(), TypePointer() ) );
|
|
else
|
|
ifVerbose( dbg() << "\"" << str() << "\": found namespace \"" << name.name() << "\", but it is not resolved" << endl );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !m_aliasImports.empty() ) {
|
|
return setupMemberInfo( name.fullNameList().join( "::" ), m_aliasImports );
|
|
|
|
}
|
|
|
|
return mem;
|
|
}
|
|
|
|
// LocateResult SimpleTypeNamespace::locateSlave( const SlaveList::const_iterator& target, const IncludeFiles& includeFiles ) {
|
|
// for( SlaveList::const_iterator it = m_activeSlaves.begin(); it != target; ++it ) {
|
|
//
|
|
// }
|
|
// }
|
|
|
|
SimpleTypeImpl::MemberInfo SimpleTypeNamespace::setupMemberInfo( const TQStringList& subName, const ImportList& imports ) {
|
|
MemberInfo mem;
|
|
mem.name = subName.join( "::" );
|
|
mem.memberType = MemberInfo::NotFound;
|
|
TQStringList sc = scope();
|
|
sc += subName;
|
|
mem.type = sc.join( "::" );
|
|
mem.memberType = MemberInfo::Namespace;
|
|
mem.setBuildInfo( new NamespaceBuildInfo( sc, imports ) );
|
|
return mem;
|
|
}
|
|
|
|
///This must be optimized
|
|
void SimpleTypeNamespace::addAliasMap( const TypeDesc& name, const TypeDesc& alias, const IncludeFiles& files, bool recurse, bool symmetric, const TypePointer& perspective ) {
|
|
Debug db;
|
|
if ( !db ) {
|
|
kdDebug( 9007 ) << str() << " addAliasMap: cannot add alias \"" << name.fullNameChain() << "\" -> \"" << alias.fullNameChain() << "\", recursion too deep" << endl;
|
|
return ;
|
|
}
|
|
if ( name.next() ) kdDebug( 9007 ) << "addAliasMap warning: type-alias-name has order higher than one: " << name.fullNameChain() << ", only " << name.name() << " will be used" << endl;
|
|
if ( name == alias )
|
|
return ;
|
|
|
|
if ( symmetric )
|
|
addAliasMap( alias, name, files, recurse, false );
|
|
|
|
invalidateSecondaryCache();
|
|
invalidatePrimaryCache( true ); //Only not-found items are cleared updated here for performance-reasons(found items will stay cached)
|
|
|
|
AliasMap::iterator it = m_aliases.find( name.name() );
|
|
if ( it == m_aliases.end() )
|
|
it = m_aliases.insert( name.name(), ImportList() );
|
|
|
|
Import a( files, alias, perspective );
|
|
std::pair< ImportList::const_iterator, ImportList::const_iterator > rng = ( *it ).equal_range( a );
|
|
while ( rng.first != rng.second ) {
|
|
if ( rng.first->files == files )
|
|
return ; //The same alias, with the same files, has already been added.
|
|
++rng.first;
|
|
}
|
|
|
|
( *it ).insert( a );
|
|
ifVerbose( dbg() << "\"" << str() << "\": adding namespace-alias \"" << name.name() << ( !symmetric ? "\" -> \"" : "\" = \"" ) << alias.name() << "\" files:\n[ " << files.print().c_str() << "]\n" << endl );
|
|
ifVerbose( if ( alias.resolved() ) dbg() << "Resolved type of the imported namespace: " << typeid( *alias.resolved() ).name() );
|
|
|
|
if ( name.name().isEmpty() ) {
|
|
addImport( alias, files, perspective );
|
|
}
|
|
}
|
|
|
|
std::set<size_t> SimpleTypeNamespace::updateAliases( const IncludeFiles& files/*, bool isRecursion */) {
|
|
std::set<size_t> possibleSlaves;
|
|
if ( m_activeSlaves.empty() || !safetyCounter.ok() ) return possibleSlaves;
|
|
// if( !isRecursion ) {
|
|
// ///Test the cache
|
|
// SlavesCache::const_iterator it = m_slavesCache.find( files );
|
|
// if( it != m_slavesCache.end() && it->second.first == m_slavesCache.size() ) return; ///The cache already contains a valid entry, and the work is done
|
|
// }
|
|
|
|
m_activeSlaveGroups.findGroups( files, possibleSlaves );
|
|
if( possibleSlaves.empty() ) return possibleSlaves;
|
|
|
|
std::list<size_t> disabled;
|
|
for( std::set<size_t>::const_reverse_iterator it = possibleSlaves.rbegin(); it != possibleSlaves.rend(); ++it ) {
|
|
//Disable all slaves with higher ids
|
|
SlaveMap::iterator current = m_activeSlaves.find( *it );
|
|
if( current == m_activeSlaves.end() ) {
|
|
kdDebug( 9007 ) << "ERROR" << endl;
|
|
}
|
|
|
|
SlaveDesc& d( current->second );
|
|
|
|
if ( !d.first.first.resolved() ) {
|
|
for( SlaveMap::const_iterator itr = current; itr != m_activeSlaves.end(); ++it ) {
|
|
if( m_activeSlaveGroups.isDisabled( itr->first ) ) break; //stop searching when hitting the first disabled one(assuming that all behind are disabled too)
|
|
disabled.push_back( itr->first );
|
|
m_activeSlaveGroups.disableSet( itr->first );
|
|
}
|
|
|
|
TypeDesc descS = d.first.first;
|
|
TypePointer p = d.second; //perspective
|
|
|
|
HashedStringSet importIncludeFiles = d.first.second;
|
|
|
|
if ( !p ) p = this;
|
|
|
|
TypeDesc desc = p->locateDecType( descS, SimpleTypeImpl::Normal, 0, SimpleTypeImpl::MemberInfo::Namespace );
|
|
if ( !desc.resolved() ) {
|
|
///If the namespace could not be found, help out by including the include-files of the current search
|
|
descS.setIncludeFiles( descS.includeFiles() + files );
|
|
desc = p->locateDecType( descS, SimpleTypeImpl::Normal, 0, SimpleTypeImpl::MemberInfo::Namespace );
|
|
}
|
|
if ( desc.resolved() ) {
|
|
///If exactly the same namespace was already imported use the earlier imported instance, so they can share a single cache
|
|
///@todo make more efficient.
|
|
for ( SlaveMap::const_iterator it = m_activeSlaves.begin(); it != m_activeSlaves.end(); ++it ) {
|
|
if (( *it ).second.first.first.resolved() && ( *it ).second.first.first.resolved()->scope() == desc.resolved()->scope() && typeid( *( *it ).second.first.first.resolved().data() ) == typeid( desc.resolved().data() ) ) {
|
|
desc.setResolved(( *it ).second.first.first.resolved() );
|
|
break;
|
|
}
|
|
}
|
|
#ifdef PHYSICALLY_IMPORT_NAMESPACES
|
|
if ( desc.resolved()->masterProxy().data() != this ) {
|
|
desc.setResolved( desc.resolved()->clone() ); //expensive, cache is not shared
|
|
desc.resolved()->setMasterProxy( this ); //Possible solution: don't use this, simply set the parents of all found members correctly
|
|
}
|
|
#endif
|
|
d.first.first = desc;
|
|
}
|
|
}
|
|
}
|
|
|
|
for( std::list<size_t>::const_iterator it = disabled.begin(); it != disabled.end(); ++it ) {
|
|
m_activeSlaveGroups.enableSet( *it );
|
|
}
|
|
|
|
return possibleSlaves;
|
|
}
|
|
|
|
|
|
void SimpleTypeNamespace::addAliases( TQString map, const IncludeFiles& files ) {
|
|
while ( !map.isEmpty() ) {
|
|
int mid = map.find( "=" );
|
|
int mid2 = map.find( "<<" );
|
|
int found = mid;
|
|
int len = 1;
|
|
if ( mid2 != -1 && ( mid2 < found || found == -1 ) ) {
|
|
found = mid2;
|
|
len = 2;
|
|
}
|
|
if ( found == -1 )
|
|
break;
|
|
|
|
int end = map.find( ";", found + len );
|
|
if ( end == -1 ) {
|
|
//break;
|
|
end = map.length();
|
|
}
|
|
if ( end - ( found + len ) < 0 )
|
|
break;
|
|
|
|
addAliasMap( map.left( found ).stripWhiteSpace(), map.mid( found + len, end - found - len ).stripWhiteSpace(), files, true, found == mid );
|
|
map = map.mid( end + 1 );
|
|
}
|
|
}
|
|
|
|
void SimpleTypeNamespace::invalidatePrimaryCache( bool onlyNegative ) {
|
|
//m_slavesCache.clear();
|
|
SimpleTypeImpl::invalidatePrimaryCache( onlyNegative );
|
|
}
|
|
|
|
void SimpleTypeNamespace::addImport( const TypeDesc& import, const IncludeFiles& files, TypePointer perspective ) {
|
|
//ifVerbose( dbg() << "
|
|
if ( !perspective ) perspective = this;
|
|
invalidateCache();
|
|
TypeDesc d = import;
|
|
if ( d.resolved() ) {
|
|
#ifdef PHYSICALLY_IMPORT_NAMESPACES
|
|
|
|
if( d.resolved()->masterProxy().data() != this ) {
|
|
d.setResolved( d.resolved()->clone() ); //Expensive because of lost caching, think about how necessary this is
|
|
d.resolved()->setMasterProxy( this );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
m_activeSlaves[ ++m_currentSlaveId ] = std::make_pair( std::make_pair( d, files ) , perspective );
|
|
m_activeSlaveGroups.addSet( m_currentSlaveId, files );
|
|
|
|
if( d.resolved() ) ///Must be called after the above, because it may insert new slaves, and the order in m_activeSlaves MUST be preserved
|
|
d.resolved()->addAliasesTo( this );
|
|
}
|
|
|
|
bool SimpleTypeNamespace::hasNode() const {
|
|
return true;
|
|
}
|
|
|
|
SimpleTypeNamespace::SlaveList SimpleTypeNamespace::getSlaves( const IncludeFiles& files ) {
|
|
/* ///Test the cache
|
|
SlavesCache::const_iterator it = m_slavesCache.find( files );
|
|
if( it != m_slavesCache.end() && it->second.first == m_activeSlaves.size() ) return it->second.second; ///The cache already contains a valid entry, and the work is done*/
|
|
|
|
std::set<size_t> allSlaves = updateAliases( files );
|
|
SlaveList ret;
|
|
#ifdef IMPORT_DEBUG
|
|
for ( SlaveList::const_iterator it = m_activeSlaves.begin(); it != m_activeSlaves.end(); ++it ) {
|
|
#ifdef IMPORT_DEBUG
|
|
ifVerbose( dbg() << "\"" << str() << "\": Checking whether \"" << (*it).second.first.first.fullNameChain() << "\" should be imported, current include-files: " << files.print().c_str() << "\nNeeded include-files: " << (*it).second.first.second.print().c_str() << "\n"; )
|
|
#endif
|
|
if ( !(( *it ).second.first.second <= files ) ) {
|
|
#ifdef IMPORT_DEBUG
|
|
ifVerbose( dbg() << "not imported." );
|
|
#endif
|
|
continue;
|
|
}
|
|
#ifdef IMPORT_DEBUG
|
|
ifVerbose( dbg() << "imported." << endl );
|
|
#endif
|
|
ret.push_back( *it.second );
|
|
}
|
|
#else
|
|
ifVerbose( dbg() << str() << " getSlaves() called for \n[ " << files.print().c_str() << endl );
|
|
|
|
for( std::set<size_t>::const_iterator it = allSlaves.begin(); it != allSlaves.end(); ++it ) {
|
|
SlaveMap::const_iterator itr = m_activeSlaves.find( *it );
|
|
if( itr != m_activeSlaves.end() ) {
|
|
ifVerbose( dbg() << str() << "getSlaves() returning " << (*itr).second.first.first.fullNameChain() << endl );
|
|
ret.push_back( (*itr).second );
|
|
} else {
|
|
kdDebug( 9007 ) << "ERROR in getSlaves()";
|
|
}
|
|
}
|
|
#endif
|
|
/*if( it == m_slavesCache.end() || it->second.first < m_activeSlaves.size()
|
|
) {
|
|
m_slavesCache.insert( std::make_pair( files, std::make_pair( m_activeSlaves.size(), ret ) ) );
|
|
}*/
|
|
return ret;
|
|
}
|
|
|
|
//SimpleTypeNamespace::NamespaceBuildInfo implementation
|
|
|
|
TypePointer SimpleTypeNamespace::NamespaceBuildInfo::build() {
|
|
if ( m_built )
|
|
return m_built;
|
|
m_built = new SimpleTypeCachedNamespace( m_fakeScope );
|
|
for ( ImportList::iterator it = m_imports.begin(); it != m_imports.end(); ++it ) {
|
|
TypeDesc i = ( *it ).import;
|
|
if ( i.resolved() ) {
|
|
// i.setResolved( i.resolved()->clone() );
|
|
}
|
|
|
|
(( SimpleTypeCachedNamespace* ) m_built.data() ) ->addAliasMap( TypeDesc(), i, ( *it ).files, true, false, ( *it ).perspective );
|
|
}
|
|
return m_built;
|
|
}
|
|
|
|
// kate: indent-mode csands; tab-width 4;
|