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.
1052 lines
36 KiB
1052 lines
36 KiB
/***************************************************************************
|
|
copyright : (C) 2006 by David Nolden
|
|
email : david.nolden.tdevelop@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 "simpletype.h"
|
|
#include "safetycounter.h"
|
|
#include "simpletypefunction.h"
|
|
#include <tdelocale.h>
|
|
|
|
TQMap<TQString, TQString> BuiltinTypes::m_types;
|
|
BuiltinTypes builtin; //Needed so BuiltinTypes::BuiltinTypes is called and the types are initialized
|
|
|
|
BuiltinTypes::BuiltinTypes() {
|
|
m_types[ "void" ] = i18n( "typeless" );
|
|
m_types[ "bool" ] = i18n("boolean value, 1 byte, ( \"true\" or \"false\" )");
|
|
m_types["char" ] = i18n("signed/unsigned character, 1 byte");
|
|
m_types["signed char" ] = i18n("signed character, 1 byte, ranged -128 to 127");
|
|
m_types["unsigned char"] = i18n("unsigned character, 1 byte, ranged 0 to 255");
|
|
m_types["wchar_t"] = i18n("wide character, 2 bytes, ranged 0 to 65.535");
|
|
m_types["long"] = m_types["long int"] = m_types["int"] = m_types["signed int"] = i18n("signed integer, 4 bytes, ranged -2.147.483.648 to 2.147.483.647");
|
|
m_types["unsigned"] = m_types["unsigned int"] = i18n("unsigned integer, 4 bytes, ranged 0 to 4.294.967.295");
|
|
m_types["short"] = m_types["short int"] = i18n("short integer, 2 bytes, ranged -32.768 to 32.768");
|
|
m_types["unsigned short int"] = i18n("unsigned short integer, 2 bytes, ranged 0 to 65.535");
|
|
m_types["float"] = i18n("floating point value, 4 bytes, ranged ca. -3,4E+38 to 3,4E+38");
|
|
m_types["double"] = i18n("double floating point value, 8 bytes, ranged ca. -1,8E+308 to 1,8E+308");
|
|
m_types["long double"] = i18n("double long floating point value, 10 bytes, ranged ca. -3,4E+4932 to 3,4E+4932");
|
|
m_types["size_t"] = i18n("unsigned integer, byte-count dependent on operating-system" );
|
|
|
|
}
|
|
|
|
bool BuiltinTypes::isBuiltin( const TypeDesc& desc ) {
|
|
return m_types.find( desc.name() ) != m_types.end();
|
|
}
|
|
|
|
TQString BuiltinTypes::comment( const TypeDesc& desc ) {
|
|
TQMap<TQString, TQString>::iterator it = m_types.find( desc.name() );
|
|
if( it != m_types.end() ) {
|
|
return *it;
|
|
} else {
|
|
return TQString();
|
|
}
|
|
}
|
|
|
|
extern SafetyCounter safetyCounter;
|
|
|
|
TypePointer SimpleType::m_globalNamespace;
|
|
SimpleType::TypeStore SimpleType::m_typeStore;
|
|
SimpleType::TypeStore SimpleType::m_destroyedStore;
|
|
TQString globalCurrentFile = "";
|
|
|
|
//SimpleType implementation
|
|
|
|
void SimpleType::resolve( Repository rep ) const {
|
|
if ( !m_resolved ) {
|
|
if ( m_globalNamespace ) {
|
|
if ( ( rep == RepoUndefined || rep == RepoBoth ) ) {
|
|
m_resolved = true;
|
|
if ( scope().isEmpty() || str().isEmpty() ) {
|
|
m_type = m_globalNamespace;
|
|
return ;
|
|
} else {
|
|
TypeDesc d( scope().join( "::" ) );
|
|
d.setIncludeFiles( m_includeFiles );
|
|
LocateResult t = m_globalNamespace->locateDecType( d );
|
|
if ( t && t->resolved() ) {
|
|
m_type = t->resolved();
|
|
return ;
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << scope().join( "::" ) << "\": The type could not be located in the global scope while resolving it" << endl );
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
ifVerbose( dbg() << "warning: no global namespace defined! " << endl );
|
|
}
|
|
|
|
TypePointer cm;
|
|
|
|
if ( rep == RepoUndefined || rep == RepoCodeModel ) {
|
|
if ( !m_type ) {
|
|
cm = TypePointer( new SimpleTypeCachedCodeModel( scope() ) );
|
|
} else {
|
|
cm = TypePointer( new SimpleTypeCachedCodeModel( &( *m_type ) ) );
|
|
}
|
|
|
|
if ( cm->hasNode() || rep == RepoCodeModel ) {
|
|
if ( cm->hasNode() ) {
|
|
ifVerbose( dbg() << "resolved \"" << str() << "\" from the code-model" << endl );
|
|
if ( cm->isNamespace() && rep != RepoCodeModel ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": is namespace, resolving proxy" << endl );
|
|
resolve( RepoBoth );
|
|
return ;
|
|
}
|
|
} else {
|
|
ifVerbose( dbg() << "forced \"" << str() << "\" to be resolved from code-model" << endl );
|
|
}
|
|
m_type = cm;
|
|
m_resolved = true;
|
|
return ;
|
|
}
|
|
}
|
|
if ( rep == RepoUndefined || rep == RepoCatalog ) {
|
|
|
|
if ( !m_type ) {
|
|
cm = TypePointer( new SimpleTypeCachedCatalog( scope() ) );
|
|
} else {
|
|
cm = TypePointer( new SimpleTypeCachedCatalog( &( *m_type ) ) );
|
|
}
|
|
|
|
if ( cm->hasNode() || rep == RepoCatalog ) {
|
|
if ( cm->hasNode() ) {
|
|
ifVerbose( dbg() << "resolved \"" << str() << "\" from the catalog" << endl );
|
|
if ( cm->isNamespace() && rep != RepoCatalog ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": is namespace, resolving proxy" << endl );
|
|
resolve( RepoBoth );
|
|
return ;
|
|
}
|
|
} else {
|
|
ifVerbose( dbg() << "forced \"" << str() << "\" to be resolved from catalog" << endl );
|
|
}
|
|
m_type = cm;
|
|
m_resolved = true;
|
|
return ;
|
|
}
|
|
}
|
|
|
|
if ( rep == RepoBoth ) {
|
|
cm = new SimpleTypeCachedNamespace( scope() );
|
|
m_type = cm;
|
|
m_resolved = true;
|
|
return ;
|
|
}
|
|
|
|
m_resolved = true;
|
|
ifVerbose( dbg() << "could not resolve \"" << m_type->desc().fullNameChain() << "\"" << endl );
|
|
}
|
|
}
|
|
|
|
void SimpleType::destroyStore() {
|
|
resetGlobalNamespace();
|
|
int cnt = m_typeStore.size();
|
|
kdDebug( 9007 ) << cnt << "types in type-store before destruction" << endl;
|
|
|
|
SafetyCounter s( 30000 );
|
|
while ( !m_typeStore.empty() && s ) {
|
|
TypeStore::iterator it = m_typeStore.begin();
|
|
TypePointer tp = *it;
|
|
m_destroyedStore.insert( tp );
|
|
m_typeStore.erase( it );
|
|
tp->breakReferences();
|
|
}
|
|
|
|
if ( !m_destroyedStore.empty() ) {
|
|
kdDebug( 9007 ) << "type-store is not empty, " << m_destroyedStore.size() << " types are left over" << endl;
|
|
for ( TypeStore::iterator it = m_destroyedStore.begin(); it != m_destroyedStore.end(); ++it ) {
|
|
kdDebug( 9007 ) << "type left: " << ( *it ) ->describe() << endl;
|
|
}
|
|
}
|
|
|
|
///move them over so they will be cleared again next time, hoping that they will vanish
|
|
m_typeStore = m_destroyedStore;
|
|
m_destroyedStore.clear();
|
|
}
|
|
|
|
///This does not necessarily make the TypeDesc's private, so before editing them
|
|
///their makePrivate must be called too
|
|
void SimpleType::makePrivate() {
|
|
m_type = m_type->clone();
|
|
}
|
|
|
|
const TQStringList& SimpleType::scope() const {
|
|
return m_type -> scope();
|
|
}
|
|
|
|
const TQString SimpleType::str() const {
|
|
return m_type -> str();
|
|
}
|
|
|
|
void SimpleType::init( const TQStringList& scope, const HashedStringSet& files, Repository rep ) {
|
|
m_includeFiles = files;
|
|
|
|
m_type = TypePointer( new SimpleTypeImpl( scope ) );
|
|
if ( rep != RepoUndefined )
|
|
resolve( rep );
|
|
}
|
|
|
|
SimpleType::SimpleType( ItemDom item ) : m_resolved( true ) {
|
|
m_type = TypePointer( new SimpleTypeCachedCodeModel( item ) );
|
|
}
|
|
/*
|
|
SimpleType::SimpleType( Tag tag ) : m_resolved(true) {
|
|
m_type = TypePointer( new SimpleTypeCatalog( tag ) );
|
|
}*/
|
|
//
|
|
//SimpleTypeImpl implementation
|
|
|
|
TQValueList<LocateResult> SimpleTypeImpl::getBases() {
|
|
TQValueList<LocateResult> ret;
|
|
TQStringList bases = getBaseStrings();
|
|
for( TQStringList::const_iterator it = bases.begin(); it != bases.end(); ++it ) {
|
|
TypeDesc d( *it );
|
|
d.setIncludeFiles( m_findIncludeFiles );
|
|
LocateResult res = locateDecType( d, LocateBase );
|
|
//if( res )
|
|
ret << res;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void SimpleTypeImpl::setFindIncludeFiles( const IncludeFiles& files ) {
|
|
m_findIncludeFiles = files;
|
|
}
|
|
|
|
IncludeFiles SimpleTypeImpl::getFindIncludeFiles() {
|
|
return m_findIncludeFiles;
|
|
}
|
|
|
|
/**
|
|
Searches for a member called "name", considering all types selected through "typ"*/
|
|
SimpleTypeImpl::TypeOfResult SimpleTypeImpl::typeOf( const TypeDesc& name, MemberInfo::MemberType typ ) {
|
|
Debug d( "#to#" );
|
|
if ( !d ) {
|
|
ifVerbose( dbg() << "stopping typeOf-evaluation because the recursion-depth is too high" << endl );
|
|
return TypeOfResult( LocateResult( TypeDesc( "CompletionError::too_much_recursion" ) ) );
|
|
}
|
|
ifVerbose( dbg() << "\"" << str() << "\"------------>: searching for type of member \"" << name.fullNameChain() << "\"" << endl );
|
|
|
|
TypeDesc td = resolveTemplateParams( name );
|
|
|
|
MemberInfo mem = findMember( td, typ );
|
|
|
|
if ( mem ) {
|
|
mem.type = resolveTemplateParams( mem.type );
|
|
|
|
ifVerbose( dbg() << "\"" << str() << "\": found member " << name.fullNameChain() << ", type: " << mem.type->fullNameChain() << endl );
|
|
if ( mem.memberType == MemberInfo::Function ) {
|
|
///For functions, find all functions with the same name, so that overloaded functions can be identified correctly
|
|
TypePointer ret = mem.build();
|
|
if ( ret && ret->asFunction() ) {
|
|
return TypeOfResult( LocateResult( ret->desc() ) );
|
|
} else {
|
|
ifVerbose( dbg() << "error, using old function-type-evaluation" << endl );
|
|
|
|
TypeDesc d( mem.type );
|
|
if( m_findIncludeFiles.size() != 0 )
|
|
d.setIncludeFiles( m_findIncludeFiles );
|
|
else
|
|
d.setIncludeFiles( name.includeFiles() );
|
|
|
|
return TypeOfResult( locateDecType( d ), mem.decl );
|
|
}
|
|
} else if ( mem.memberType == MemberInfo::Variable ) {
|
|
TypeDesc d( mem.type );
|
|
if( m_findIncludeFiles.size() != 0 )
|
|
d.setIncludeFiles( m_findIncludeFiles );
|
|
else
|
|
d.setIncludeFiles( name.includeFiles() );
|
|
|
|
return TypeOfResult( locateDecType( d ), mem.decl );
|
|
} else {
|
|
ifVerbose( dbg() << "while searching for the type of \"" << name.fullNameChain() << "\" in \"" << str() << "\": member has wrong type: \"" << mem.memberTypeToString() << "\"" << endl );
|
|
return TypeOfResult();
|
|
}
|
|
}
|
|
|
|
TypeOfResult ret = searchBases( td );
|
|
if ( !ret ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\"------------>: failed to resolve the type of member \"" << name.fullNameChain() << "\"" << endl );
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\"------------>: successfully resolved the type of the member \"" << name.fullNameChain() << "\"" << endl );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
SimpleTypeFunctionInterface* SimpleTypeImpl::asFunction() {
|
|
return dynamic_cast<SimpleTypeFunctionInterface*> ( this );
|
|
}
|
|
|
|
TQString SimpleTypeImpl::operatorToString( Operator op ) {
|
|
switch ( op ) {
|
|
case NoOp:
|
|
return "NoOp";
|
|
case IndexOp:
|
|
return "index-operator";
|
|
case ArrowOp:
|
|
return "arrow-operator";
|
|
case StarOp:
|
|
return "star-operator";
|
|
case AddrOp:
|
|
return "address-operator";
|
|
case ParenOp:
|
|
return "paren-operator";
|
|
default:
|
|
return TQString( "%1" ).arg( ( long ) op );
|
|
};
|
|
}
|
|
|
|
LocateResult SimpleTypeImpl::getFunctionReturnType( TQString functionName, TQValueList<LocateResult> params ) {
|
|
LocateResult t = typeOf( functionName, MemberInfo::Function ).type;
|
|
if ( t->resolved() && t->resolved() ->asFunction() ) {
|
|
return t->resolved() ->applyOperator( ParenOp, params );
|
|
} else {
|
|
ifVerbose( dbg() << "error : could not find function \"" << functionName << "\" in \"" << str() << "\"" << endl );
|
|
return LocateResult();
|
|
}
|
|
}
|
|
|
|
LocateResult SimpleTypeImpl::applyOperator( Operator op , TQValueList<LocateResult> params ) {
|
|
Debug d( "#applyn#" );
|
|
if ( !d || !safetyCounter )
|
|
return LocateResult();
|
|
|
|
ifVerbose( dbg() << "applying operator " << operatorToString( op ) << " to \"" << desc().fullNameChain() << "\"" << endl );
|
|
LocateResult ret;
|
|
if ( op == NoOp )
|
|
return LocateResult( desc() );
|
|
|
|
switch ( op ) {
|
|
case IndexOp:
|
|
return getFunctionReturnType( "operator [ ]", params );
|
|
break;
|
|
case StarOp:
|
|
return getFunctionReturnType( "operator *", params );
|
|
break;
|
|
case ArrowOp:
|
|
/** Dereference one more because the type must be a pointer */
|
|
ret = getFunctionReturnType( "operator ->", params );
|
|
if ( ret->totalPointerDepth() ) {
|
|
ret->setTotalPointerDepth( ret->totalPointerDepth() - 1 );
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\": " << " \"operator ->\" returns a type with the wrong pointer-depth" << endl );
|
|
}
|
|
return ret;
|
|
break;
|
|
case ParenOp:
|
|
/** Dereference one more because the type must be a pointer */
|
|
return getFunctionReturnType( "operator ( )", params );
|
|
default:
|
|
ifVerbose( dbg() << "wrong operator\n" );
|
|
}
|
|
|
|
return LocateResult();
|
|
}
|
|
|
|
TypeDesc SimpleTypeImpl::replaceTemplateParams( TypeDesc desc, TemplateParamInfo& paramInfo ) {
|
|
Debug d( "#repl#" );
|
|
if ( !d || !safetyCounter )
|
|
return desc;
|
|
|
|
TypeDesc ret = desc;
|
|
if ( !ret.hasTemplateParams() && !ret.next() ) {
|
|
TemplateParamInfo::TemplateParam t;
|
|
if ( paramInfo.getParam( t, desc.name() ) ) {
|
|
|
|
if ( t.value )
|
|
ret = t.value;
|
|
else if ( t.def )
|
|
ret = t.def;
|
|
|
|
if ( ret.name() != desc.name() )
|
|
ret.setTotalPointerDepth( ret.totalPointerDepth() + desc.totalPointerDepth() );
|
|
}
|
|
} else {
|
|
TypeDesc::TemplateParams& params = ret.templateParams();
|
|
for ( TypeDesc::TemplateParams::iterator it = params.begin(); it != params.end(); ++it ) {
|
|
*it = new TypeDescShared( replaceTemplateParams( **it, paramInfo ) );
|
|
}
|
|
}
|
|
|
|
if ( ret.next() ) {
|
|
ret.setNext( new TypeDescShared( replaceTemplateParams( *ret.next(), paramInfo ) ) );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
TypeDesc SimpleTypeImpl::resolveTemplateParams( LocateResult desc, LocateMode mode ) {
|
|
Debug d( "#resd#" );
|
|
if ( !d || !safetyCounter )
|
|
return desc;
|
|
|
|
LocateResult ret = desc;
|
|
if ( ret->hasTemplateParams() ) {
|
|
TypeDesc::TemplateParams & params = ret->templateParams();
|
|
for ( TypeDesc::TemplateParams::iterator it = params.begin(); it != params.end(); ++it ) {
|
|
if ( !( *it ) ->resolved() && !( *it ) ->hasFlag( ResolutionTried ) ) {
|
|
TypeDesc d( **it );
|
|
if( d.includeFiles().size() == 0 )
|
|
d.setIncludeFiles( this->getFindIncludeFiles() );
|
|
*it = locateDecType( d, mode );
|
|
( *it ) ->setFlag( ResolutionTried );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ret->next() ) {
|
|
ret->setNext( new TypeDescShared( resolveTemplateParams( *ret->next(), mode ) ) );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
class TemplateParamMatch {
|
|
public:
|
|
TemplateParamMatch() : m_matched( false ), m_maxDepth( 0 ), m_candidate( 0 ) {}
|
|
|
|
TemplateParamMatch( TypePointer candidate, const TypeDesc& params ) : m_matched( false ), m_maxDepth( 0 ), m_candidate( candidate ) {
|
|
m_candidateParams = candidate->getTemplateParamInfo();
|
|
TypeDesc specialization( candidate->specialization() );
|
|
|
|
TypeDesc cleanParams = params;
|
|
cleanParams.setName( "" );
|
|
|
|
m_matched = matchParameters( specialization, cleanParams );
|
|
|
|
if( m_matched ) {
|
|
//Make sure that all template-parameters were found
|
|
for( int a = 0; a < m_candidateParams.count(); a++ ) {
|
|
SimpleTypeImpl::TemplateParamInfo::TemplateParam t;
|
|
if( m_candidateParams.getParam( t, a ) ) {
|
|
if( !m_hadParameters.contains( t.name ) ) {
|
|
m_matched = false;
|
|
}
|
|
} else {
|
|
m_matched = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
///@todo: use all default-parameters if some are missing
|
|
///@todo: also use decoration like "const" or "&" for specialization.
|
|
bool matchParameters( const TypeDesc& specialization, const LocateResult& params, int depth = 0 ) {
|
|
if( depth > m_maxDepth ) m_maxDepth = depth;
|
|
|
|
if( specialization.name().isEmpty() ) {
|
|
if( specialization.templateParams().count() != params->templateParams().count() )
|
|
return false;
|
|
} else {
|
|
SimpleTypeImpl::TemplateParamInfo::TemplateParam t;
|
|
if( m_candidateParams.getParam( t, specialization.name() ) ) {
|
|
TypeDesc oldValue = t.value;
|
|
|
|
//Check if the decoration of the specialization matches the decoration of the arguments, if not we have a mismatch.
|
|
|
|
if( specialization.totalPointerDepth() > params->totalPointerDepth() ) {
|
|
return false; //The decoration does not match the given argument
|
|
} else {
|
|
depth += specialization.totalPointerDepth();
|
|
if( depth > m_maxDepth ) m_maxDepth = depth;
|
|
}
|
|
|
|
//Fill the template-parameter, or compare if the one we already found out matches this one
|
|
LocateResult val;
|
|
if( specialization.hasTemplateParams() ) {
|
|
val = params->decoratedName();
|
|
} else {
|
|
val = params; //No more parameters have to be checked, so take the value and return later
|
|
}
|
|
|
|
val->setTotalPointerDepth( val->totalPointerDepth() - specialization.totalPointerDepth() );
|
|
|
|
t.value = val;
|
|
|
|
if( m_hadParameters.contains( t.name ) && oldValue != t.value ) {
|
|
return false; ///We have a mismatch, two different values for the same template-parameter.
|
|
} else {
|
|
m_candidateParams.addParam( t );
|
|
m_hadParameters[ t.name ] = val;
|
|
if( !specialization.hasTemplateParams() ) return true;
|
|
}
|
|
} else {
|
|
if( m_candidate->locateDecType( specialization.decoratedName() )->decoratedName() != params->decoratedName() ) {
|
|
//We have a mismatch
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if( specialization.templateParams().count() != params->templateParams().count() ) {
|
|
return false; //mismatch in count of template-parameters
|
|
}
|
|
|
|
TypeDesc::TemplateParams::const_iterator specialIt = specialization.templateParams().begin();
|
|
TypeDesc::TemplateParams::const_iterator paramsIt = params->templateParams().begin();
|
|
|
|
while( specialIt != specialization.templateParams().end() && paramsIt != params->templateParams().end() ) {
|
|
if( !matchParameters( (*specialIt).desc(), (*paramsIt), depth+10 ) ) return false;
|
|
|
|
++paramsIt;
|
|
++specialIt;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
operator bool() const {
|
|
return m_matched;
|
|
}
|
|
|
|
///True if this match is better than the given one
|
|
bool operator > ( const TemplateParamMatch& rhs ) const {
|
|
if( !m_matched ) return false;
|
|
if(!rhs.m_matched ) return true;
|
|
return m_maxDepth > rhs.m_maxDepth;
|
|
}
|
|
|
|
TypePointer type() {
|
|
if( m_candidate ) {
|
|
TypePointer ret = m_candidate->clone();
|
|
ret->descForEdit().templateParams().clear();
|
|
for( int a = 0; a < m_candidateParams.count(); a++ ) {
|
|
SimpleTypeImpl::TemplateParamInfo::TemplateParam tp;
|
|
if( m_candidateParams.getParam( tp, a ) ) {
|
|
ret->descForEdit().templateParams().push_back( m_hadParameters[tp.name] );
|
|
} else {
|
|
ret->descForEdit().templateParams().push_back( LocateResult() ); //error
|
|
}
|
|
}
|
|
return ret;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
SimpleTypeImpl::TemplateParamInfo& templateParams() {
|
|
return m_candidateParams;
|
|
}
|
|
|
|
private:
|
|
TypePointer m_candidate;
|
|
SimpleTypeImpl::TemplateParamInfo m_candidateParams;
|
|
TQMap<TQString, LocateResult> m_hadParameters;
|
|
bool m_matched;
|
|
int m_maxDepth;
|
|
};
|
|
|
|
void SimpleTypeImpl::chooseSpecialization( MemberInfo& member ) {
|
|
|
|
if ( member.memberType != MemberInfo::NestedType )
|
|
return ;
|
|
if ( !member.type->hasTemplateParams() )
|
|
return ;
|
|
|
|
TypePointer type = member.build();
|
|
|
|
if ( !type )
|
|
return ;
|
|
|
|
//Get a list of all candidate-classes
|
|
TypePointer t = this;
|
|
if ( m_masterProxy )
|
|
t = m_masterProxy;
|
|
|
|
TQValueList<TypePointer> classes = t->getMemberClasses( type->desc() );
|
|
|
|
//Find the specialization that fits the given template-parameters the best
|
|
|
|
if ( !type->specialization().isEmpty() ) {
|
|
kdDebug( 9007 ) << "a specialized template-class was suggested as primary class while searching for specialization, search problematic" << endl;
|
|
//return;
|
|
} else {
|
|
TemplateParamInfo params = type->getTemplateParamInfo();
|
|
|
|
int dif = params.count() - member.type->templateParams().count();
|
|
|
|
if ( dif > 0 ) {
|
|
//fill up missing template-parameters with their default-parameters, maybe should be done in findMember
|
|
for ( int a = member.type->templateParams().count(); a < params.count(); a++ ) {
|
|
LocateResult r;
|
|
TemplateParamInfo::TemplateParam tp;
|
|
if ( params.getParam( tp, a ) ) {
|
|
r = t->locateDecType( tp.value );
|
|
}
|
|
member.type->templateParams().push_back( r );
|
|
}
|
|
}
|
|
}
|
|
|
|
//now find the class that is most specialized and matches the template-parameters
|
|
|
|
TemplateParamMatch bestMatch;
|
|
|
|
for ( TQValueList<TypePointer>::iterator it = classes.begin(); it != classes.end(); ++it ) {
|
|
if ( ( *it ) ->specialization().isEmpty() )
|
|
continue;
|
|
TemplateParamMatch match( ( *it ), member.type.desc() );
|
|
|
|
if ( match > bestMatch )
|
|
bestMatch = match;
|
|
}
|
|
|
|
if ( bestMatch ) {
|
|
TypePointer tp = bestMatch.type();
|
|
if ( tp ) {
|
|
member.setBuilt( tp );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
LocateResult SimpleTypeImpl::locateType( TypeDesc name , LocateMode mode , int dir , MemberInfo::MemberType typeMask ) {
|
|
Debug d( "#lo#" );
|
|
if( BuiltinTypes::isBuiltin( name ) )
|
|
return name;
|
|
|
|
if ( !name || !safetyCounter || !d ) {
|
|
return desc();
|
|
}
|
|
if ( !d ) {
|
|
ifVerbose( dbg() << "stopping location because the recursion-depth is too high" << endl );
|
|
return TypeDesc( "CompletionError::too_much_recursion" );
|
|
}
|
|
ifVerbose( dbg() << "\(" << uint(this) << ")\"" << str() << "\": locating type \"" << name.fullNameChain() << "\"" << endl );
|
|
if ( name.resolved() && !name.next() ) {
|
|
ifVerbose( dbg() << "\"" << desc().fullName() << "\": type \"" << name.fullNameChain() << "\" is already resolved, returning stored instance" << endl );
|
|
return name;
|
|
}
|
|
/*
|
|
if( name.resolved() && name.length() == name.resolved()->desc().length() ) {
|
|
ifVerbose( dbg() << "\"" << desc().fullName() << "\": type \"" << name.fullNameChain() << "\" is already resolved, returning stored instance" << endl;
|
|
SimpleType ret = SimpleType( name.resolved() );
|
|
|
|
if( ! (name == ret->desc()) ) {
|
|
ret.makePrivate(); ///Maybe some small parameters like the pointer-depth were changed, so customize those
|
|
ret->parseParams( name );
|
|
}
|
|
|
|
return ret;
|
|
}*/
|
|
/*
|
|
//This optimization is now disabled, because it allows following a wrong path.
|
|
if( name.next() ) {
|
|
//This is an optimization for better use of the cache: Find the elements separately, so searches
|
|
//For elements that start with the same scope will be speeded up.
|
|
LocateResult r = locateType( name.firstType(), mode, dir, typeMask );
|
|
if( r && r->resolved() && r.locateMode().valid ) {
|
|
ifVerbose( dbg() << "splitting location" );
|
|
TypeDesc d( *name.next() );
|
|
d.setIncludeFiles( name.includeFiles() );
|
|
return r->resolved()->locateType( d, (LocateMode)r.locateMode().mode, r.locateMode().dir );
|
|
}
|
|
}*/
|
|
|
|
LocateResult ret = name; ///In case the type cannot be located, this helps to find at least the best match
|
|
//LocateResult ret;
|
|
|
|
TypeDesc first = resolveTemplateParams( name.firstType(), mode );
|
|
|
|
MemberInfo mem = findMember( first, typeMask );
|
|
|
|
switch ( mem.memberType ) {
|
|
case MemberInfo::Namespace:
|
|
if ( mode & ExcludeNamespaces )
|
|
break;
|
|
case MemberInfo::NestedType: {
|
|
if ( mem.memberType == MemberInfo::NestedType && mode & ExcludeNestedTypes )
|
|
break;
|
|
|
|
SimpleType sub;
|
|
if ( TypePointer t = mem.build() ) {
|
|
sub = SimpleType( t );
|
|
#ifdef PHYSICAL_IMPORT
|
|
setSlaveParent( *sub );
|
|
#endif
|
|
} else {
|
|
///Should not happen..
|
|
kdDebug( 9007 ) << "\"" << str() << "\": Warning: the nested-type " << name.name() << " was found, but has no build-info" << endl;
|
|
return TypeDesc( "CompletionError::unknown" );
|
|
}
|
|
|
|
TypeDesc rest;
|
|
LocateMode newMode = addFlag( mode, ExcludeTemplates );
|
|
int newDir = 1;
|
|
if ( name.next() ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\": found nested type \"" << name.name() << "\", passing control to it\n" );
|
|
ret = sub->locateType( resolveTemplateParams( *name.next(), Normal ), newMode, newDir ); ///since template-names cannot be referenced from outside, exclude them for the first cycle
|
|
ret.increaseResolutionCount();
|
|
if ( ret->resolved() )
|
|
return ret.resetDepth();
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\": successfully located searched type \"" << name.fullNameChain() << "\"\n" );
|
|
ret->setResolved( sub.get() );
|
|
ret->resolved()->setFindIncludeFiles( name.includeFiles() );
|
|
ret.locateMode().valid = true;
|
|
ret.locateMode().mode = (uint)newMode;
|
|
ret.locateMode().dir = newDir;
|
|
return ret.resetDepth();
|
|
}
|
|
break;
|
|
}
|
|
case MemberInfo::Typedef:
|
|
if ( mode & ExcludeTypedefs )
|
|
break;
|
|
case MemberInfo::Template: {
|
|
if ( mem.memberType == MemberInfo::Template && ( mode & ExcludeTemplates ) )
|
|
break;
|
|
ifVerbose( dbg() << "\"" << str() << "\": found " << mem.memberTypeToString() << " \"" << name.name() << "\" -> \"" << mem.type->fullNameChain() << "\", recursing \n" );
|
|
if ( name.hasTemplateParams() ) {
|
|
ifVerbose( dbg() << "\"" << str() << "\":warning: \"" << name.fullName() << "\" is a " << mem.memberTypeToString() << ", but it has template-params itself! Not matching" << endl );
|
|
} else {
|
|
if ( mem.type->name() != name.name() ) {
|
|
|
|
MemberInfo m = mem;
|
|
if ( name.next() ) {
|
|
mem.type->makePrivate();
|
|
mem.type->append( name.next() );
|
|
}
|
|
ret = locateDecType( mem.type, remFlag( mode, ExcludeTemplates ) );
|
|
|
|
if ( mem.memberType == MemberInfo::Template )
|
|
ret.addResolutionFlag( HadTemplate );
|
|
if ( mem.memberType == MemberInfo::Typedef )
|
|
ret.addResolutionFlag( HadTypedef );
|
|
ret.increaseResolutionCount();
|
|
// if( mode & TraceAliases && ret->resolved() )
|
|
{
|
|
m.name = "";
|
|
|
|
if ( !scope().isEmpty() ) {
|
|
m.name = fullTypeUnresolvedWithScope() + "::";
|
|
}
|
|
m.name += name.nameWithParams();
|
|
//m.name += name.fullNameChain();
|
|
|
|
if ( name.next() ) {
|
|
if ( m.type.trace() ) {
|
|
ret.trace() ->prepend( *m.type.trace(), 1 );
|
|
}
|
|
ret.trace() ->prepend( m, *name.next() );
|
|
} else {
|
|
if ( m.type.trace() )
|
|
ret.trace() ->prepend( *m.type.trace(), 1 );
|
|
ret.trace() ->prepend( m );
|
|
}
|
|
}
|
|
|
|
if ( ret->resolved() )
|
|
return ret.resetDepth();
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\"recursive typedef/template found: \"" << name.fullNameChain() << "\" -> \"" << mem.type->fullNameChain() << "\"" << endl );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
///A Function is treated similar to a type
|
|
case MemberInfo::Function: {
|
|
if ( !name.next() ) {
|
|
TypePointer t = mem.build();
|
|
if ( t ) {
|
|
return t->desc();
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\"" << ": could not build function: \"" << name.fullNameChain() << "\"" );
|
|
}
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\"" << ": name-conflict: searched for \"" << name.fullNameChain() << "\" and found function \"" << mem.name << "\"" );
|
|
}
|
|
break;
|
|
};
|
|
///Currently there is no representation of a Variable as a SimpleType, so only the type of the variable is used.
|
|
case MemberInfo::Variable: {
|
|
return locateDecType( mem.type, remFlag( mode, ExcludeTemplates ) ).resetDepth();
|
|
}
|
|
}
|
|
|
|
///Ask bases but only on this level
|
|
if ( ! ( mode & ExcludeBases ) ) {
|
|
|
|
TQValueList<LocateResult> bases = getBases();
|
|
if ( !bases.isEmpty() ) {
|
|
TypeDesc nameInBase = resolveTemplateParams( name, LocateBase ); ///Resolve all template-params that are at least visible in the scope of the base-declaration
|
|
|
|
for ( TQValueList<LocateResult>::iterator it = bases.begin(); it != bases.end(); ++it ) {
|
|
if ( !( *it ) ->resolved() )
|
|
continue;
|
|
LocateResult t = ( *it ) ->resolved() ->locateType( nameInBase, addFlag( addFlag( mode, ExcludeTemplates ), ExcludeParents ), dir ); ///The searched Type cannot directly be a template-param in the base-class, so ExcludeTemplates. It's forgotten early enough.
|
|
if ( t->resolved() )
|
|
return t.increaseDepth();
|
|
else
|
|
if ( t > ret )
|
|
ret = t.increaseDepth();
|
|
}
|
|
}
|
|
}
|
|
|
|
///Ask parentsc
|
|
if ( !scope().isEmpty() && dir != 1 && ! ( mode & ExcludeParents ) ) {
|
|
LocateResult rett = parent() ->locateType( resolveTemplateParams( name, mode & ExcludeBases ? ExcludeBases : mode ), mode & ForgetModeUpwards ? Normal : mode );
|
|
if ( rett->resolved() )
|
|
return rett.increaseDepth();
|
|
else
|
|
if ( rett > ret )
|
|
ret = rett.increaseDepth();
|
|
}
|
|
|
|
///Ask the bases and allow them to search in their parents.
|
|
if ( ! ( mode & ExcludeBases ) ) {
|
|
TypeDesc baseName = resolveTemplateParams( name, LocateBase ); ///Resolve all template-params that are at least visible in the scope of the base-declaration
|
|
TQValueList<LocateResult> bases = getBases();
|
|
if ( !bases.isEmpty() ) {
|
|
for ( TQValueList<LocateResult>::iterator it = bases.begin(); it != bases.end(); ++it ) {
|
|
if ( !( *it ) ->resolved() )
|
|
continue;
|
|
LocateResult t = ( *it ) ->resolved() ->locateType( baseName, addFlag( mode, ExcludeTemplates ), dir ); ///The searched Type cannot directly be a template-param in the base-class, so ExcludeTemplates. It's forgotten early enough.
|
|
if ( t->resolved() )
|
|
return t.increaseDepth();
|
|
else
|
|
if ( t > ret )
|
|
ret = t.increaseDepth();
|
|
}
|
|
}
|
|
}
|
|
|
|
///Give the type a desc, so the nearest point to the searched type is stored
|
|
ifVerbose( dbg() << "\"" << str() << "\": search for \"" << name.fullNameChain() << "\" FAILED" << endl );
|
|
return ret;
|
|
}
|
|
|
|
void SimpleTypeImpl::breakReferences() {
|
|
TypePointer p( this ); ///necessary so this type is not deleted in between
|
|
m_parent = 0;
|
|
m_desc.resetResolved();
|
|
// m_trace.clear();
|
|
m_masterProxy = 0;
|
|
invalidateCache();
|
|
}
|
|
|
|
TypePointer SimpleTypeImpl::bigContainer() {
|
|
if ( m_masterProxy )
|
|
return m_masterProxy;
|
|
else
|
|
return TypePointer( this );
|
|
}
|
|
|
|
SimpleType SimpleTypeImpl::parent() {
|
|
if ( m_parent ) {
|
|
//ifVerbose( dbg() << "\"" << str() << "\": returning parent" << endl;
|
|
return SimpleType( m_parent );
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\": locating parent" << endl );
|
|
invalidateSecondaryCache();
|
|
TQStringList sc = scope();
|
|
|
|
if ( !sc.isEmpty() ) {
|
|
sc.pop_back();
|
|
SimpleType r = SimpleType( sc, m_desc.includeFiles() );
|
|
if ( &( *r.get() ) == this ) {
|
|
kdDebug( 9007 ) << "error: self set as parent: " << m_scope.join( "::" ) << "(" << m_scope.count() << ")" << ", " << sc.join( "::" ) << "(" << sc.count() << ")" /* << kdBacktrace()*/ << endl;
|
|
return SimpleType( new SimpleTypeImpl( "" ) );
|
|
}
|
|
m_parent = r.get();
|
|
return r;
|
|
} else {
|
|
ifVerbose( dbg() << "\"" << str() << "\"warning: returning parent of global scope!" << endl );
|
|
return SimpleType( new SimpleTypeImpl( "" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
const TypeDesc& SimpleTypeImpl::desc() {
|
|
if ( m_desc.name().isEmpty() )
|
|
m_desc.setName( cutTemplateParams( scope().back() ) );
|
|
m_desc.setResolved( this );
|
|
return m_desc;
|
|
}
|
|
|
|
TypeDesc& SimpleTypeImpl::descForEdit() {
|
|
desc();
|
|
invalidateCache();
|
|
return m_desc;
|
|
}
|
|
|
|
TQString SimpleTypeImpl::describeWithParams() {
|
|
TemplateParamInfo pinfo = getTemplateParamInfo();
|
|
int num = 0;
|
|
TemplateParamInfo::TemplateParam param;
|
|
TQString str = desc().name();
|
|
if ( desc().hasTemplateParams() ) {
|
|
str += "< ";
|
|
|
|
for ( TypeDesc::TemplateParams::const_iterator it = desc().templateParams().begin(); it != desc().templateParams().end(); ++it ) {
|
|
if ( pinfo.getParam( param, num ) && !param.name.isEmpty() )
|
|
str += param.name;
|
|
else
|
|
str += "[unknown name]";
|
|
|
|
str += " = " + ( *it ) ->fullNameChain() + ", ";
|
|
++num;
|
|
}
|
|
|
|
str.truncate( str.length() - 2 );
|
|
str += " >";
|
|
}
|
|
return str;
|
|
}
|
|
|
|
TQString SimpleTypeImpl::fullTypeResolved( int depth ) {
|
|
Debug d( "#tre#" );
|
|
|
|
TypeDesc t = desc();
|
|
if ( !scope().isEmpty() ) {
|
|
if ( depth > 10 )
|
|
return "KDevParseError::ToDeep";
|
|
if ( !safetyCounter )
|
|
return "KDevParseError::MaximumCountReached";
|
|
|
|
ifVerbose( dbg() << "fully resolving type " << t.fullName() << endl );
|
|
if ( scope().size() != 0 ) {
|
|
t = resolveTemplateParams( t, LocateBase );
|
|
}
|
|
}
|
|
|
|
return t.fullNameChain();
|
|
}
|
|
|
|
|
|
TQString SimpleTypeImpl::fullTypeUnresolvedWithScope( ) {
|
|
if ( m_parent && !m_parent->scope().isEmpty() ) {
|
|
return m_parent->fullTypeUnresolvedWithScope() + "::" + m_desc.fullNameChain();
|
|
} else {
|
|
return m_desc.fullNameChain();
|
|
}
|
|
}
|
|
|
|
TQString SimpleTypeImpl::fullTypeResolvedWithScope( int depth ) {
|
|
Q_UNUSED( depth );
|
|
if ( !m_scope.isEmpty() && parent() ) {
|
|
return parent() ->fullTypeResolvedWithScope() + "::" + fullTypeResolved();
|
|
} else {
|
|
return fullTypeResolved();
|
|
}
|
|
}
|
|
|
|
void SimpleTypeImpl::checkTemplateParams () {
|
|
invalidateCache();
|
|
if ( ! m_scope.isEmpty() ) {
|
|
TQString str = m_scope.back();
|
|
m_desc = str;
|
|
if ( !m_desc.name().isEmpty() ) {
|
|
m_scope.pop_back();
|
|
m_scope << m_desc.name();
|
|
} else {
|
|
kdDebug() << "checkTemplateParams() produced bad scope-tail: \"" << m_desc.name() << "\", \"" << m_scope.join( "::" ) << "\"" << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SimpleTypeImpl::setScope( const TQStringList& scope ) {
|
|
invalidateCache();
|
|
m_scope = scope;
|
|
if ( m_scope.count() == 1 && m_scope.front().isEmpty() ) {
|
|
//kdDebug() << "bad scope set " << kdBacktrace() << endl;
|
|
m_scope = TQStringList();
|
|
}
|
|
}
|
|
|
|
SimpleTypeImpl::TypeOfResult SimpleTypeImpl::searchBases ( const TypeDesc& name /*option!!*/ ) {
|
|
TQValueList<LocateResult> parents = getBases();
|
|
for ( TQValueList<LocateResult>::iterator it = parents.begin(); it != parents.end(); ++it ) {
|
|
if ( !( *it ) ->resolved() )
|
|
continue;
|
|
TypeOfResult type = ( *it ) ->resolved() ->typeOf( name );
|
|
if ( type )
|
|
return type;
|
|
}
|
|
return TypeOfResult();
|
|
}
|
|
|
|
void SimpleTypeImpl::setSlaveParent( SimpleTypeImpl& slave ) {
|
|
if ( ! m_masterProxy ) {
|
|
slave.setParent( this );
|
|
} else {
|
|
slave.setParent( m_masterProxy );
|
|
}
|
|
}
|
|
|
|
void SimpleTypeImpl::parseParams( TypeDesc desc ) {
|
|
invalidateCache();
|
|
m_desc = desc;
|
|
m_desc.clearInstanceInfo();
|
|
}
|
|
|
|
void SimpleTypeImpl::takeTemplateParams( TypeDesc desc ) {
|
|
invalidateCache();
|
|
m_desc.templateParams() = desc.templateParams();
|
|
}
|
|
|
|
//SimpleTypeImpl::TemplateParamInfo implementation
|
|
|
|
bool SimpleTypeImpl::TemplateParamInfo::getParam( TemplateParam& target, TQString name ) const {
|
|
TQMap<TQString, TemplateParam>::const_iterator it = m_paramsByName.find( name );
|
|
if ( it != m_paramsByName.end() ) {
|
|
target = *it;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SimpleTypeImpl::TemplateParamInfo::getParam( TemplateParam& target, int number ) const {
|
|
TQMap<int, TemplateParam>::const_iterator it = m_paramsByNumber.find( number );
|
|
if ( it != m_paramsByNumber.end() ) {
|
|
target = *it;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SimpleTypeImpl::TemplateParamInfo::removeParam( int number ) {
|
|
TQMap<int, TemplateParam>::iterator it = m_paramsByNumber.find( number );
|
|
if ( it != m_paramsByNumber.end() ) {
|
|
m_paramsByName.remove( ( *it ).name );
|
|
m_paramsByNumber.remove( it );
|
|
}
|
|
}
|
|
|
|
void SimpleTypeImpl::TemplateParamInfo::addParam( const TemplateParam& param ) {
|
|
m_paramsByNumber[ param.number ] = param;
|
|
m_paramsByName[ param.name ] = param;
|
|
}
|
|
|
|
int SimpleTypeImpl::TemplateParamInfo::count() const {
|
|
TQMap<int, TemplateParam>::const_iterator it = m_paramsByNumber.end();
|
|
if ( it != m_paramsByNumber.begin() ) {
|
|
--it;
|
|
return ( *it ).number + 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void SimpleTypeConfiguration::setGlobalNamespace( TypePointer globalNamespace ) {
|
|
if ( !globalNamespace->scope().isEmpty() ) {
|
|
kdDebug( 9007 ) << "error while setting global scope\n" << kdBacktrace() << endl;
|
|
SimpleType::setGlobalNamespace( new SimpleTypeImpl( "" ) );
|
|
} else {
|
|
SimpleType::setGlobalNamespace( globalNamespace );
|
|
}
|
|
}
|
|
|
|
// kate: indent-mode csands; tab-width 4;
|
|
|