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/simpletypecatalog.cpp

373 lines
13 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 "simpletypecatalog.h"
#include "simpletypefunction.h"
#include "safetycounter.h"
extern SafetyCounter safetyCounter;
extern CppCodeCompletion* cppCompletionInstance;
//SimpleTypeCatalog implementation
TypePointer SimpleTypeCatalog::clone() {
return new SimpleTypeCachedCatalog( this );
}
TQString SimpleTypeCatalog::specialization() const {
return m_tag.getSpecializationDeclaration();
}
void SimpleTypeCatalog::addAliasesTo( SimpleTypeNamespace* ns ) {
if ( m_tag.kind() != Tag::Kind_Namespace ) return;
TQValueList<Catalog::QueryArgument> args;
///Insert all namespace-imports
args << Catalog::QueryArgument( "scope", specializedScope() );
args << Catalog::QueryArgument( "kind", Tag::Kind_UsingDirective );
TQValueList<Tag> tags( cppCompletionInstance->m_repository->query( args ) );
for ( TQValueList<Tag>::iterator it = tags.begin(); it != tags.end(); ++it ) {
TypeDesc d( (*it).name() );
d.setIncludeFiles( HashedString((*it).fileName()) ); ///@todo implement the include-file-logic
ns->addAliasMap( TypeDesc(), d, HashedString((*it).fileName()), true, false, bigContainer() );
}
///Insert all namespace-aliases
args.clear();
args << Catalog::QueryArgument( "scope", specializedScope() );
args << Catalog::QueryArgument( "kind", Tag::Kind_NamespaceAlias );
tags = cppCompletionInstance->m_repository->query( args );
for ( TQValueList<Tag>::iterator it = tags.begin(); it != tags.end(); ++it ) {
TQVariant v = (*it).attribute( "alias" );
if ( v.type() == TQVariant::String ) {
TypeDesc d( v.asString() );
d.setIncludeFiles( HashedString((*it).fileName()) );
ns->addAliasMap( (*it).name(), d, HashedString((*it).fileName()), true, false, bigContainer() );
} else
kdDebug( 9007 ) << "namespace-alias has no alias-text" << endl;
}
}
TQValueList<TypePointer> SimpleTypeCatalog::getMemberClasses( const TypeDesc& name ) {
TQValueList<TypePointer> ret;
TQValueList<Catalog::QueryArgument> args;
args << Catalog::QueryArgument( "scope", specializedScope() );
args << Catalog::QueryArgument( "name", name.name() );
TQValueList<Tag> tags( cppCompletionInstance->m_repository->query( args ) );
for ( TQValueList<Tag>::iterator it = tags.begin(); it != tags.end(); ++it ) {
if ( (*it).kind() == Tag::Kind_Class ) {
///It would be better to return all matched class-names from within findMember and use them from there so all this will be cached too.
CatalogBuildInfo b( *it, name, TypePointer( this ) );
TypePointer t = b.buildCached();
if ( t ) ret << t;
}
}
return ret;
}
SimpleTypeImpl::MemberInfo SimpleTypeCatalog::findMember( TypeDesc name, SimpleTypeImpl::MemberInfo::MemberType type ) {
MemberInfo ret;
ret.name = name.name();
ret.memberType = MemberInfo::NotFound;
if ( !name ) return ret;
if ( ( type & MemberInfo::Template) ) {
LocateResult s = findTemplateParam( name.name() );
if ( s ) {
ret.memberType = MemberInfo::Template;
ret.type = s;
ret.decl.name = name.name();
ret.decl.file = m_tag.fileName();
m_tag.getStartPosition( &ret.decl.startLine, &ret.decl.startCol );
m_tag.getEndPosition( &ret.decl.endLine, &ret.decl.endCol );
}
}
TQValueList<Catalog::QueryArgument> args;
args << Catalog::QueryArgument( "scope", specializedScope() );
args << Catalog::QueryArgument( "name", name.name() );
TQValueList<Tag> tags( cppCompletionInstance->m_repository->query( args ) );
if ( tags.isEmpty() ) return ret;
///skip all using-directives
TQValueList<Tag>::iterator it = tags.begin();
while ( ( (*it).kind() == Tag::Kind_UsingDirective || (*it).kind() == Tag::Kind_NamespaceAlias ) && it != tags.end() )
++it;
if ( it == tags.end() ) return ret;
Tag tag = *it;
if ( tag.kind() == Tag::Kind_Variable && (type & MemberInfo::Variable) ) {
ret.memberType = MemberInfo::Variable;
ret.type = tagType( tag );
ret.decl.name = tag.name();
ret.decl.comment = tag.comment();
tag.getStartPosition( &ret.decl.startLine, &ret.decl.startCol );
tag.getEndPosition( &ret.decl.endLine, &ret.decl.endCol );
ret.decl.file = tag.fileName();
}
if ( tag.kind() == Tag::Kind_Enumerator && (type & MemberInfo::Variable) ) {
ret.memberType = MemberInfo::Variable;
if ( !tag.hasAttribute( "enum" ) ) {
ret.type = TypeDesc( "const int" );
} else {
ret.type = tag.attribute( "enum" ).asString();
if ( ret.type->name().isEmpty() )
ret.type = TypeDesc( "const int" );
}
ret.decl.name = tag.name();
ret.decl.comment = tag.comment();
tag.getStartPosition( &ret.decl.startLine, &ret.decl.startCol );
tag.getEndPosition( &ret.decl.endLine, &ret.decl.endCol );
ret.decl.file = tag.fileName();
} else if ( tag.kind() == Tag::Kind_Class && ( type & MemberInfo::NestedType ) ) {
//if( tag.hasSpecializationDeclaration() ) {
//Choose another tag(the main class, not a specialization).
bool hasSpecializationDeclaration = tag.hasSpecializationDeclaration();
bool isIncluded = name.includeFiles()[tag.fileName()];
if ( hasSpecializationDeclaration || !isIncluded ) {
for ( TQValueList<Tag>::const_iterator it = tags.begin(); it != tags.end(); ++it ) {
if ( (*it).kind() == Tag::Kind_Class && !(*it).hasSpecializationDeclaration() ) {
if ( name.includeFiles()[(*it).fileName()] ) {
tag = *it;
isIncluded = true;
hasSpecializationDeclaration = false;
} else if ( hasSpecializationDeclaration ) {
tag = *it;
hasSpecializationDeclaration = false;
isIncluded = false;
}
if ( isIncluded && !hasSpecializationDeclaration ) break;
}
}
}
//only accept non-specialized classes
if ( !tag.hasSpecializationDeclaration() ) {
ret.setBuildInfo( new CatalogBuildInfo( tag, name, TypePointer( this ) ) );
ret.memberType = MemberInfo::NestedType;
ret.type = name;
}
} else if ( tag.kind() == Tag::Kind_Typedef && ( type & MemberInfo::Typedef ) ) {
ret.memberType = MemberInfo::Typedef;
ret.type = tagType( tag );
ret.decl.name = tag.name();
ret.decl.comment = tag.comment();
tag.getStartPosition( &ret.decl.startLine, &ret.decl.startCol );
tag.getEndPosition( &ret.decl.endLine, &ret.decl.endCol );
ret.decl.file = tag.fileName();
} else if ( tag.kind() == Tag::Kind_Enum && ( type & MemberInfo::Typedef ) ) {
ret.memberType = MemberInfo::Typedef;
ret.type = TypeDesc( "const int" );
ret.decl.name = tag.name();
ret.decl.comment = tag.comment();
tag.getStartPosition( &ret.decl.startLine, &ret.decl.startCol );
tag.getEndPosition( &ret.decl.endLine, &ret.decl.endCol );
ret.decl.file = tag.fileName();
} else if ( (tag.kind() == Tag::Kind_FunctionDeclaration || tag.kind() == Tag::Kind_Function) && ( type & MemberInfo::Function ) ) {
ret.memberType = MemberInfo::Function;
ret.type = tagType( tag );
ret.type->increaseFunctionDepth();
ret.setBuildInfo( new SimpleTypeCatalogFunction::CatalogFunctionBuildInfo( tags, name, TypePointer( this ) ) );
} else if ( tag.kind() == Tag::Kind_Namespace && ( type & MemberInfo::Namespace ) ) {
ret.setBuildInfo( new CatalogBuildInfo( tag , name, TypePointer( this ) ) );
ret.memberType = MemberInfo::Namespace;
ret.type = name;
}
///Check if it is a template-name
//if( !ret.type) ret.memberType = MemberInfo::NotFound; //constructor..
if( ret.memberType == MemberInfo::Function || ret.memberType == MemberInfo::Variable || ret.memberType == MemberInfo::Template || ret.memberType == MemberInfo::Typedef || ret.memberType == MemberInfo::NestedType ) {
//For redirected types it is necessary to add the include-files of the context they were searched in.
//That is not quite correct, but it makes sure that at least the same namespace-aliases will be activated while the search for the type.
ret.type->addIncludeFiles( name.includeFiles() );
}
chooseSpecialization( ret );
return ret;
}
Tag SimpleTypeCatalog::findSubTag( const TQString& name ) {
if ( name.isEmpty() ) return Tag();
TQValueList<Catalog::QueryArgument> args;
TQTime t;
t.start();
args << Catalog::QueryArgument( "scope", specializedScope() );
args << Catalog::QueryArgument( "name", name );
TQValueList<Tag> tags( cppCompletionInstance->m_repository->query( args ) );
if ( ! tags.isEmpty() ) {
//ifVerbose( dbg() << "findTag: \"" << str() << "\": tag \"" << name << "\" found " << endl );
return tags.front();
} else {
//ifVerbose( dbg() << "findTag: \"" << str() << "\": tag \"" << name << "\" not found " << endl );
return Tag();
}
}
TQValueList<Tag> SimpleTypeCatalog::getBaseClassList( ) {
if ( scope().isEmpty() )
return TQValueList<Tag>();
return cppCompletionInstance->m_repository->getBaseClassList( scope().join("::") + specialization() );
}
void SimpleTypeCatalog::initFromTag() {
TQStringList l = m_tag.scope();
l << m_tag.name();
setScope( l );
}
void SimpleTypeCatalog::init() {
if ( !scope().isEmpty() ) {
TQStringList l = scope();
TQStringList cp = l;
cp.pop_back();
setScope( cp );
m_tag = findSubTag( l.back() );
setScope( l );
//initFromTag( ); ///must not be done, because it may initialize to wrong namespaces etc.
}
}
DeclarationInfo SimpleTypeCatalog::getDeclarationInfo() {
DeclarationInfo ret;
ret.name = fullTypeResolved();
if ( m_tag ) {
ret.file = m_tag.fileName();
m_tag.getStartPosition( &ret.startLine, &ret.startCol );
m_tag.getEndPosition( &ret.endLine, &ret.endCol );
ret.comment = m_tag.comment();
}
return ret;
}
TQStringList SimpleTypeCatalog::getBaseStrings() {
Debug d( "#getbases#" );
if ( !d || !safetyCounter ) {
//ifVerbose( dbg() << "\"" << str() << "\": recursion to deep while getting bases" << endl );
return TQStringList();
}
TQStringList ret;
TQMap<TQString, bool> bases;
// try with parentsc
TQTime t;
t.restart();
TQValueList<Tag> parents( getBaseClassList() );
TQValueList<Tag>::Iterator it = parents.begin();
while ( it != parents.end() ) {
Tag & tag = *it;
++it;
CppBaseClass<Tag> info( tag );
bases[ info.baseClass() ] = true;
}
return bases.keys();
}
SimpleTypeImpl::TemplateParamInfo SimpleTypeCatalog::getTemplateParamInfo() {
TemplateParamInfo ret;
if ( m_tag ) {
if ( m_tag.hasAttribute( "tpl" ) ) {
TQStringList l = m_tag.attribute( "tpl" ).asStringList();
TypeDesc::TemplateParams templateParams = m_desc.templateParams();
uint pi = 0;
TQStringList::const_iterator it = l.begin();
while ( it != l.end() ) {
TemplateParamInfo::TemplateParam curr;
curr.name = *it;
curr.number = pi;
++pi;
++it;
if ( it != l.end() ) {
curr.def = *it;
++it;
}
if ( pi < templateParams.count() )
curr.value = *templateParams[pi];
ret.addParam( curr );
};
}
}
return ret;
}
const LocateResult SimpleTypeCatalog::findTemplateParam( const TQString& name ) {
if ( m_tag ) {
if ( m_tag.hasAttribute( "tpl" ) ) {
TQStringList l = m_tag.attribute( "tpl" ).asStringList();
///we need the index, so count the items through
uint pi = 0;
TQStringList::const_iterator it = l.begin();
while ( it != l.end() && *it != name ) {
++pi;
++it;
if ( it != l.end() ) ++it;
};
TypeDesc::TemplateParams templateParams = m_desc.templateParams();
if ( it != l.end() && pi < templateParams.count() ) {
return *templateParams[pi];
} else {
if ( it != l.end() && *it == name && !(*it).isEmpty()) {
++it;
if ( it != l.end() && !(*it).isEmpty() ) {
ifVerbose( dbg() << "using default-template-type " << *it << " for " << name << endl );
return TypeDesc( *it ); ///return default-parameter
}
}
}
}
}
return LocateResult();
}
//SimpleTypeCatalog::CatalogBuildInfo implementation
TypePointer SimpleTypeCatalog::CatalogBuildInfo::build() {
if ( !m_tag )
return TypePointer();
else {
TypePointer tp = new SimpleTypeCachedCatalog( m_tag );
tp->parseParams( m_desc );
if ( m_parent ) tp->setParent( m_parent->bigContainer() );
return tp;
}
}