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.
tdevelop/languages/cpp/simpletypenamespace.cpp

437 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;
}