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

1082 lines
28 KiB

/***************************************************************************
* Copyright (C) 2003 by Roberto Raggi *
* roberto@kdevelop.org *
* *
* 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 "store_walker.h"
#include "ast_utils.h"
#include "urlutil.h"
#include "driver.h"
#include <kdebug.h>
#include <qfileinfo.h>
#include <qdir.h>
StoreWalker::StoreWalker( const QString& fileName, CodeModel* store )
: m_store( store ), m_anon( 0 )
{
m_fileName = URLUtil::canonicalPath( fileName );
m_hashedFileName = HashedString( m_fileName );
//kdDebug(9007) << "StoreWalker::StoreWalker(" << m_fileName << ")" << endl;
}
StoreWalker::~StoreWalker()
{}
void StoreWalker::parseTranslationUnit( const ParsedFile& ast )
{
m_file = m_store->create<FileModel>();
m_file->setName( m_fileName ); /// @todo ?!?
m_currentScope.clear();
m_currentNamespace.clear();
m_currentClass.clear();
ParsedFilePointer p = new ParsedFile( ast );
p->setTranslationUnit( 0 ); //Necessary so the memory is not bloated after the first parse
m_file->setParseResult( p.data() ); ///@todo beautify
m_currentAccess = CodeModelItem::Public;
m_inSlots = false;
m_inSignals = false;
m_inStorageSpec = false;
m_inTypedef = false;
m_currentDeclarator = 0;
m_anon = 0;
m_imports.clear();
m_imports << QPair<QMap<QString, ClassDom>, QStringList>(QMap<QString, ClassDom>(), QStringList());
TreeParser::parseTranslationUnit( ast );
m_imports.pop_back();
}
void StoreWalker::parseDeclaration( DeclarationAST* ast )
{
TreeParser::parseDeclaration( ast );
}
void StoreWalker::parseLinkageSpecification( LinkageSpecificationAST* ast )
{
int inStorageSpec = m_inStorageSpec;
m_inStorageSpec = true;
TreeParser::parseLinkageSpecification( ast );
m_inStorageSpec = inStorageSpec;
}
void StoreWalker::parseNamespace( NamespaceAST* ast )
{
if ( !m_currentClass.isEmpty() )
{
kdDebug( 9007 ) << "!!!!!!!!!!!!!!!!!!!!!!!!!! **error** !!!!!!!!!!!!!!!!!!!!" << endl;
return ;
}
int startLine, startColumn;
int endLine, endColumn;
ast->getStartPosition( &startLine, &startColumn );
ast->getEndPosition( &endLine, &endColumn );
QString nsName;
if ( !ast->namespaceName() || ast->namespaceName()->text().isEmpty() )
{
QFileInfo fileInfo( m_fileName );
QString shortFileName = fileInfo.baseName();
nsName.sprintf( "(%s_%d)", shortFileName.local8Bit().data(), m_anon++ );
}
else
{
nsName = ast->namespaceName() ->text();
}
NamespaceDom ns = findOrInsertNamespace( ast, nsName );
m_currentScope.push_back( nsName );
m_currentNamespace.push( ns );
TreeParser::parseNamespace( ast );
m_currentNamespace.pop();
m_currentScope.pop_back();
}
void StoreWalker::parseNamespaceAlias( NamespaceAliasAST* ast )
{
QString nsName;
QString aliasName;
if( !ast->namespaceName() || ast->namespaceName()->text().isEmpty() )
{
// anonymous namespace
}
else
nsName = ast->namespaceName()->text();
if( ast->aliasName() )
aliasName = ast->aliasName()->text();
if( !nsName.isNull() ) {
NamespaceAliasModel m;
m.setName( nsName );
m.setAliasName( aliasName );
m.setFileName( m_hashedFileName );
if( m_currentNamespace.empty() )
m_file->addNamespaceAlias( m );
else
m_currentNamespace.top() ->addNamespaceAlias( m );
}
TreeParser::parseNamespaceAlias( ast );
}
void StoreWalker::parseUsing( UsingAST* ast )
{
TreeParser::parseUsing( ast );
}
void StoreWalker::parseUsingDirective( UsingDirectiveAST* ast )
{
QString name;
if( ast->name() )
name = ast->name()->text();
if( !name.isNull() ) {
NamespaceImportModel m;
m.setName( name );
m.setFileName( m_hashedFileName );
if( m_currentNamespace.empty() )
m_file->addNamespaceImport( m );
else
m_currentNamespace.top() ->addNamespaceImport( m );
}
m_imports.back().second.push_back( name );
}
void StoreWalker::parseTypedef( TypedefAST* ast )
{
#if 0
DeclaratorAST * oldDeclarator = m_currentDeclarator;
if ( ast && ast->initDeclaratorList() && ast->initDeclaratorList() ->initDeclaratorList().count() > 0 )
{
QPtrList<InitDeclaratorAST> lst( ast->initDeclaratorList() ->initDeclaratorList() );
m_currentDeclarator = lst.at( 0 ) ->declarator();
}
m_inTypedef = true;
TreeParser::parseTypedef( ast );
m_inTypedef = false;
m_currentDeclarator = oldDeclarator;
#else
TypeSpecifierAST* typeSpec = ast->typeSpec();
InitDeclaratorListAST* declarators = ast->initDeclaratorList();
if ( typeSpec && declarators )
{
QString typeId;
if ( typeSpec->name() )
typeId = typeSpec->name() ->text();
QPtrList<InitDeclaratorAST> l( declarators->initDeclaratorList() );
QPtrListIterator<InitDeclaratorAST> it( l );
InitDeclaratorAST* initDecl = 0;
while ( 0 != ( initDecl = it.current() ) )
{
QString type, id;
if ( initDecl->declarator() )
{
type = typeOfDeclaration( typeSpec, initDecl->declarator() );
DeclaratorAST* d = initDecl->declarator();
while ( d->subDeclarator() )
{
d = d->subDeclarator();
}
if ( d->declaratorId() )
id = d->declaratorId() ->text();
}
TypeAliasDom typeAlias = m_store->create<TypeAliasModel>();
typeAlias->setFileName( m_fileName );
typeAlias->setName( id );
typeAlias->setType( type );
typeAlias->setComment( ast->comment() );
int line, col;
initDecl->getStartPosition( &line, &col );
typeAlias->setStartPosition( line, col );
initDecl->getEndPosition( &line, &col );
typeAlias->setEndPosition( line, col );
if ( m_currentClass.top() )
m_currentClass.top() ->addTypeAlias( typeAlias );
else if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addTypeAlias( typeAlias );
else
m_file->addTypeAlias( typeAlias );
#if 0
Tag tag;
tag.setKind( Tag::Kind_Typedef );
tag.setFileName( m_fileName );
tag.setName( id );
tag.setScope( m_currentScope );
tag.setAttribute( "t", type );
int line, col;
initDecl->getStartPosition( &line, &col );
tag.setStartPosition( line, col );
initDecl->getEndPosition( &line, &col );
tag.setEndPosition( line, col );
m_catalog->addItem( tag );
#endif
++it;
}
}
#endif
}
void StoreWalker::parseTemplateDeclaration( TemplateDeclarationAST* ast )
{
m_currentTemplateDeclarator.push( ast );
if ( ast->declaration() )
parseDeclaration( ast->declaration() );
TreeParser::parseTemplateDeclaration( ast );
m_currentTemplateDeclarator.pop();
}
void StoreWalker::parseSimpleDeclaration( SimpleDeclarationAST* ast )
{
TypeSpecifierAST * typeSpec = ast->typeSpec();
InitDeclaratorListAST* declarators = ast->initDeclaratorList();
CommentPusher push( *this, ast->comment() );
if ( typeSpec )
parseTypeSpecifier( typeSpec );
if ( declarators )
{
QPtrList<InitDeclaratorAST> l = declarators->initDeclaratorList();
QPtrListIterator<InitDeclaratorAST> it( l );
while ( it.current() )
{
parseDeclaration( ast->functionSpecifier(), ast->storageSpecifier(),
typeSpec, it.current() );
++it;
}
}
}
QStringList StoreWalker::findScope( const QStringList& scope ) {
ClassDom d = findClassFromScope( scope );
if( d ) {
QStringList ret = d->scope();
ret << d->name();
return ret;
}
return scope;
}
void StoreWalker::parseFunctionDefinition( FunctionDefinitionAST* ast )
{
TypeSpecifierAST * typeSpec = ast->typeSpec();
GroupAST* funSpec = ast->functionSpecifier();
GroupAST* storageSpec = ast->storageSpecifier();
if ( !ast->initDeclarator() )
return ;
DeclaratorAST* d = ast->initDeclarator() ->declarator();
if ( !d->declaratorId() )
return ;
bool isFriend = false;
bool isVirtual = false;
bool isStatic = false;
bool isInline = false;
if ( funSpec )
{
QPtrList<AST> l = funSpec->nodeList();
QPtrListIterator<AST> it( l );
while ( it.current() )
{
QString text = it.current() ->text();
if ( text == "virtual" )
isVirtual = true;
else if ( text == "inline" )
isInline = true;
++it;
}
}
if ( storageSpec )
{
QPtrList<AST> l = storageSpec->nodeList();
QPtrListIterator<AST> it( l );
while ( it.current() )
{
QString text = it.current() ->text();
if ( text == "friend" )
isFriend = true;
else if ( text == "static" )
isStatic = true;
++it;
}
}
int startLine, startColumn;
int endLine, endColumn;
ast->getStartPosition( &startLine, &startColumn );
ast->getEndPosition( &endLine, &endColumn );
QString id = d->declaratorId() ->unqualifiedName() ->text().stripWhiteSpace();
QStringList scope = scopeOfDeclarator( d, m_currentScope );
ClassDom c; ///c should be nonzero if it is a function-definition for a function within another class
if( !m_currentClass.top() ) {
///It is not a local definition within a class, so search the scope so it can be corrected using imports
c = findClassFromScope( scope );
}
if( c ) {
scope = c->scope();
scope << c->name();
}
FunctionDefinitionDom method = m_store->create<FunctionDefinitionModel>();
method->setScope( scope );
method->setName( id );
parseFunctionArguments( d, model_cast<FunctionDom>( method ) );
QString text = typeOfDeclaration( typeSpec, d );
if ( !text.isEmpty() )
method->setResultType( text );
method->setFileName( m_fileName );
method->setStartPosition( startLine, startColumn );
method->setEndPosition( endLine, endColumn );
if( !ast->comment().isEmpty() )
method->setComment( ast->comment() );
checkTemplateDeclarator( & (*method) );
if ( m_inSignals )
method->setSignal( true );
if ( m_inSlots )
method->setSlot( true );
if( c && c->isClass() )
method->setConstant( d->constant() != 0 );
else if ( m_currentClass.top() || ( method->name() == "main" && scope.isEmpty() ) )
{
method->setConstant( d->constant() != 0 );
method->setAccess( m_currentAccess );
method->setStatic( isStatic );
method->setVirtual( isVirtual );
if ( m_currentClass.top() )
m_currentClass.top() ->addFunction( model_cast<FunctionDom>( method ) );
else
m_file->addFunction( model_cast<FunctionDom>( method ) );
}
if ( m_currentClass.top() )
m_currentClass.top() ->addFunctionDefinition( method );
else if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addFunctionDefinition( method );
else
m_file->addFunctionDefinition( method );
}
void StoreWalker::parseLinkageBody( LinkageBodyAST* ast )
{
TreeParser::parseLinkageBody( ast );
}
void StoreWalker::parseTypeSpecifier( TypeSpecifierAST* ast )
{
TreeParser::parseTypeSpecifier( ast );
}
void StoreWalker::takeTemplateParams( TemplateModelItem& target, TemplateDeclarationAST* ast) {
TemplateParameterListAST* pl = ast->templateParameterList();
if( pl ) {
QPtrList<TemplateParameterAST> list = pl->templateParameterList();
TemplateParameterAST* curr = list.first();
while( curr != 0 ) {
QString a, b;
if( curr->typeParameter() && curr->typeParameter()->name() ) {
a = curr->typeParameter()->name()->text();
if( curr->typeParameter()->typeId() )
b = curr->typeParameter()->typeId()->text();
}
target.addTemplateParam( a, b );
CodeModelItem* cmi = dynamic_cast<CodeModelItem*>(&target);
QString nm = "0";
if(cmi) nm = cmi->name();
kdDebug() << "item " << nm << " taking template-parameters " << a << ", default=" << b << "\n";
curr = list.next();
}
}
}
void StoreWalker::checkTemplateDeclarator( TemplateModelItem* item ) {
if( !m_currentTemplateDeclarator.empty() && m_currentTemplateDeclarator.top() != 0) {
TemplateDeclarationAST* a = m_currentTemplateDeclarator.top();
m_currentTemplateDeclarator.pop();
m_currentTemplateDeclarator.push(0);
takeTemplateParams( *item, a );
}
}
int StoreWalker::mergeGroups( int g1, int g2 ) {
int ng = m_store->mergeGroups( g1, g2 );
for( QMap<QString, FileDom>::iterator it = m_overrides.begin(); it != m_overrides.end(); ++it ) {
int g =(*it)->groupId();
if( g == g1 || g == g2 )
(*it)->setGroupId( ng );
}
return ng;
}
void StoreWalker::parseClassSpecifier( ClassSpecifierAST* ast )
{
int startLine, startColumn;
int endLine, endColumn;
ast->getStartPosition( &startLine, &startColumn );
ast->getEndPosition( &endLine, &endColumn );
int oldAccess = m_currentAccess;
bool oldInSlots = m_inSlots;
bool oldInSignals = m_inSignals;
QString kind = ast->classKey() ->text();
if ( kind == "class" )
m_currentAccess = CodeModelItem::Private;
else
m_currentAccess = CodeModelItem::Public;
m_inSlots = false;
m_inSignals = false;
QString className;
if ( !ast->name() && m_currentDeclarator && m_currentDeclarator->declaratorId() )
{
className = m_currentDeclarator->declaratorId() ->text().stripWhiteSpace();
}
else if ( !ast->name() )
{
QFileInfo fileInfo( m_fileName );
QString shortFileName = fileInfo.baseName();
className.sprintf( "(%s_%d)", shortFileName.local8Bit().data(), m_anon++ );
}
else
{
className = ast->name() ->unqualifiedName() ->text().stripWhiteSpace();
}
ClassDom klass = m_store->create<ClassModel>();
klass->setStartPosition( startLine, startColumn );
klass->setEndPosition( endLine, endColumn );
klass->setFileName( m_fileName );
int i = className.find( '<' );
if( i != -1 ) {
klass->setSpecializationDeclaration( className.mid( i ) );
className = className.left( i );
}
klass->setName( className );
klass->setComment( ast->comment() );
checkTemplateDeclarator( &(*klass) );
bool embed = !scopeOfName( ast->name(), QStringList() ).isEmpty();
QStringList oldScope;
if( embed ) {
ClassDom embedderClass = findClassFromScope( m_currentScope + scopeOfName( ast->name(), QStringList() ));
if(embedderClass) {
if(embedderClass->fileName() != klass->fileName()) {
///since we are creating a link between both files, put them into the same parsing-group
FileDom dm = embedderClass->file();
if( dm ) {
m_file->setGroupId( mergeGroups( dm->groupId(), m_file->groupId() ) );
}else{
kdDebug() << "file " << embedderClass->fileName() << " missing in store \n";
}
}
oldScope = m_currentScope;
m_currentScope = embedderClass->scope();
m_currentScope.push_back( embedderClass->name() );
m_currentClass.push( embedderClass );
//m_file->addClass( klass );//experiment
}else{
kdDebug( 9007 ) << "could not find embedding class " << QStringList(m_currentScope + scopeOfName( ast->name(), QStringList() )).join("::") << " for " << className << endl;
embed = false;
}
}
if ( m_currentClass.top() )
m_currentClass.top() ->addClass( klass );
else if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addClass( klass );
else
m_file->addClass( klass );
klass->setScope( m_currentScope );
if ( ast->baseClause() )
parseBaseClause( ast->baseClause(), klass );
m_currentScope.push_back( className );
m_currentClass.push( klass );
//m_imports.push_back( QStringList() );
TreeParser::parseClassSpecifier( ast );
//m_imports.pop_back();
m_currentClass.pop();
m_currentScope.pop_back();
if( embed ) {
m_currentScope = oldScope;
m_currentClass.pop();
}
m_currentAccess = oldAccess;
m_inSlots = oldInSlots;
m_inSignals = oldInSignals;
}
void StoreWalker::parseEnumSpecifier( EnumSpecifierAST* ast )
{
if( ast->name() ) {
TypeAliasDom typeAlias = m_store->create<TypeAliasModel>();
typeAlias->setFileName( m_fileName );
typeAlias->setName( ast->name()->text() );
typeAlias->setType( "const int" );
typeAlias->setComment( ast->comment() );
int line, col;
ast->getStartPosition( &line, &col );
typeAlias->setStartPosition( line, col );
ast->getEndPosition( &line, &col );
typeAlias->setEndPosition( line, col );
if ( m_currentClass.top() )
m_currentClass.top() ->addTypeAlias( typeAlias );
else if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addTypeAlias( typeAlias );
else
m_file->addTypeAlias( typeAlias );
}
QPtrList<EnumeratorAST> l = ast->enumeratorList();
QPtrListIterator<EnumeratorAST> it( l );
while ( it.current() )
{
VariableDom attr = m_store->create<VariableModel>();
attr->setName( it.current() ->id() ->text() );
attr->setFileName( m_fileName );
attr->setAccess( m_currentAccess );
if( !ast->name() ) {
attr->setType( "const int" );
} else {
attr->setType( ast->name()->text() );
}
attr->setEnumeratorVariable( true );
attr->setComment( (*it)->comment() );
attr->setStatic( true );
int startLine, startColumn;
int endLine, endColumn;
it.current() ->getStartPosition( &startLine, &startColumn );
attr->setStartPosition( startLine, startColumn );
it.current() ->getEndPosition( &endLine, &endColumn );
attr->setEndPosition( endLine, endColumn );
if ( m_currentClass.top() )
m_currentClass.top() ->addVariable( attr );
else if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addVariable( attr );
else
m_file->addVariable( attr );
++it;
}
}
void StoreWalker::parseElaboratedTypeSpecifier( ElaboratedTypeSpecifierAST* ast )
{
TreeParser::parseElaboratedTypeSpecifier( ast );
}
void StoreWalker::parseTypeDeclaratation( TypeSpecifierAST* typeSpec )
{
parseTypeSpecifier( typeSpec );
}
void StoreWalker::parseDeclaration( GroupAST* funSpec, GroupAST* storageSpec,
TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl )
{
if ( m_inStorageSpec )
return ;
DeclaratorAST* d = decl->declarator();
if ( !d )
return ;
if ( !d->subDeclarator() && d->parameterDeclarationClause() )
return parseFunctionDeclaration( funSpec, storageSpec, typeSpec, decl );
DeclaratorAST* t = d;
while ( t && t->subDeclarator() )
t = t->subDeclarator();
QString id;
if ( t && t->declaratorId() && t->declaratorId() ->unqualifiedName() )
id = t->declaratorId() ->unqualifiedName() ->text();
if ( !scopeOfDeclarator( d, QStringList() ).isEmpty() )
{
kdDebug( 9007 ) << "skip declaration of " << QStringList(scopeOfDeclarator( d, QStringList() )).join("::") << "::" << id << endl;
return ;
}
VariableDom attr = m_store->create<VariableModel>();
attr->setName( id );
attr->setFileName( m_fileName );
attr->setComment( comment() );
if ( m_currentClass.top() )
m_currentClass.top() ->addVariable( attr );
else if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addVariable( attr );
else
m_file->addVariable( attr );
attr->setAccess( m_currentAccess );
QString text = typeOfDeclaration( typeSpec, d );
if ( !text.isEmpty() ) {
attr->setType( text );
}
bool isFriend = false;
//bool isVirtual = false;
bool isStatic = false;
//bool isInline = false;
//bool isInitialized = decl->initializer() != 0;
if ( storageSpec )
{
QPtrList<AST> l = storageSpec->nodeList();
QPtrListIterator<AST> it( l );
while ( it.current() )
{
QString text = it.current() ->text();
if ( text == "friend" )
isFriend = true;
else if ( text == "static" )
isStatic = true;
++it;
}
}
int startLine, startColumn;
int endLine, endColumn;
decl->getStartPosition( &startLine, &startColumn );
decl->getEndPosition( &endLine, &endColumn );
attr->setStartPosition( startLine, startColumn );
attr->setEndPosition( endLine, endColumn );
attr->setStatic( isStatic );
}
void StoreWalker::parseAccessDeclaration( AccessDeclarationAST * access )
{
QPtrList<AST> l = access->accessList();
QString accessStr = l.at( 0 ) ->text();
if ( accessStr == "public" )
m_currentAccess = CodeModelItem::Public;
else if ( accessStr == "protected" )
m_currentAccess = CodeModelItem::Protected;
else if ( accessStr == "private" )
m_currentAccess = CodeModelItem::Private;
else if ( accessStr == "signals" )
m_currentAccess = CodeModelItem::Protected;
else
m_currentAccess = CodeModelItem::Public;
m_inSlots = l.count() > 1 ? l.at( 1 ) ->text() == "slots" : false;
m_inSignals = l.count() >= 1 ? l.at( 0 ) ->text() == "signals" : false;
}
NamespaceDom StoreWalker::findOrInsertNamespace( NamespaceAST* ast, const QString & name )
{
if ( m_currentNamespace.top() && m_currentNamespace.top() ->hasNamespace( name ) )
return m_currentNamespace.top() ->namespaceByName( name );
if ( m_file->hasNamespace( name ) )
return m_file->namespaceByName( name );
int startLine, startColumn;
int endLine, endColumn;
ast->getStartPosition( &startLine, &startColumn );
ast->getEndPosition( &endLine, &endColumn );
NamespaceDom ns = m_store->create<NamespaceModel>();
ns->setFileName( m_fileName );
ns->setName( name );
ns->setStartPosition( startLine, startColumn );
ns->setEndPosition( endLine, endColumn );
ns->setComment( ast->comment() );
ns->setScope( m_currentScope );
if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addNamespace( ns );
else
m_file->addNamespace( ns );
return ns;
}
void StoreWalker::parseFunctionDeclaration( GroupAST* funSpec, GroupAST* storageSpec,
TypeSpecifierAST * typeSpec, InitDeclaratorAST * decl )
{
bool isFriend = false;
bool isVirtual = false;
bool isStatic = false;
bool isInline = false;
bool isPure = decl->initializer() != 0;
if ( funSpec )
{
QPtrList<AST> l = funSpec->nodeList();
QPtrListIterator<AST> it( l );
while ( it.current() )
{
QString text = it.current() ->text();
if ( text == "virtual" )
isVirtual = true;
else if ( text == "inline" )
isInline = true;
++it;
}
}
if ( storageSpec )
{
QPtrList<AST> l = storageSpec->nodeList();
QPtrListIterator<AST> it( l );
while ( it.current() )
{
QString text = it.current() ->text();
if ( text == "friend" )
isFriend = true;
else if ( text == "static" )
isStatic = true;
++it;
}
}
int startLine, startColumn;
int endLine, endColumn;
decl->getStartPosition( &startLine, &startColumn );
decl->getEndPosition( &endLine, &endColumn );
DeclaratorAST* d = decl->declarator();
QString id = d->declaratorId() ->unqualifiedName() ->text();
FunctionDom method = m_store->create<FunctionModel>();
method->setName( id );
method->setComment( comment() );
method->setFileName( m_fileName );
method->setStartPosition( startLine, startColumn );
method->setEndPosition( endLine, endColumn );
method->setAccess( m_currentAccess );
method->setStatic( isStatic );
method->setVirtual( isVirtual );
method->setAbstract( isPure );
parseFunctionArguments( d, method );
checkTemplateDeclarator( & (*method) );
if ( m_inSignals )
method->setSignal( true );
if ( m_inSlots )
method->setSlot( true );
QString text = typeOfDeclaration( typeSpec, d );
if ( !text.isEmpty() )
method->setResultType( text );
method->setConstant( d->constant() != 0 );
method->setScope( scopeOfDeclarator( d, m_currentScope ) );
if ( m_currentClass.top() )
m_currentClass.top() ->addFunction( method );
else if ( m_currentNamespace.top() )
m_currentNamespace.top() ->addFunction( method );
else
m_file->addFunction( method );
}
void StoreWalker::parseFunctionArguments( DeclaratorAST* declarator, FunctionDom method )
{
ParameterDeclarationClauseAST * clause = declarator->parameterDeclarationClause();
if ( clause && clause->parameterDeclarationList() )
{
ParameterDeclarationListAST * params = clause->parameterDeclarationList();
QPtrList<ParameterDeclarationAST> l( params->parameterList() );
QPtrListIterator<ParameterDeclarationAST> it( l );
while ( it.current() )
{
ParameterDeclarationAST * param = it.current();
++it;
ArgumentDom arg = m_store->create<ArgumentModel>();
if ( param->declarator() )
{
QString text = declaratorToString( param->declarator(), QString::null, true );
if ( !text.isEmpty() )
arg->setName( text );
}
QString tp = typeOfDeclaration( param->typeSpec(), param->declarator() );
if ( !tp.isEmpty() )
arg->setType( tp );
method->addArgument( arg );
}
}
}
QString StoreWalker::typeOfDeclaration( TypeSpecifierAST* typeSpec, DeclaratorAST* declarator )
{
if ( !typeSpec || !declarator )
return QString::null;
QString text;
text += typeSpec->text();
QPtrList<AST> ptrOpList = declarator->ptrOpList();
for ( QPtrListIterator<AST> it( ptrOpList ); it.current(); ++it )
{
text += it.current() ->text();
}
for( int a = 0; a < declarator->arrayDimensionList().count(); a++ )
text += "*";
return text;
}
void StoreWalker::parseBaseClause( BaseClauseAST * baseClause, ClassDom klass )
{
QPtrList<BaseSpecifierAST> l = baseClause->baseSpecifierList();
QPtrListIterator<BaseSpecifierAST> it( l );
while ( it.current() )
{
BaseSpecifierAST * baseSpecifier = it.current();
QString baseName;
if ( baseSpecifier->name() )
baseName = baseSpecifier->name() ->text();
klass->addBaseClass( baseName );
++it;
}
}
QStringList StoreWalker::scopeOfName( NameAST* id, const QStringList& startScope )
{
QStringList scope = startScope;
if ( id && id->classOrNamespaceNameList().count() )
{
if ( id->isGlobal() )
scope.clear();
QPtrList<ClassOrNamespaceNameAST> l = id->classOrNamespaceNameList();
QPtrListIterator<ClassOrNamespaceNameAST> it( l );
while ( it.current() )
{
if ( it.current() ->name() )
{
scope << it.current() ->name() ->text();
}
++it;
}
}
return scope;
}
///@todo respect the imports that result from the headers etc.
ClassDom StoreWalker::findClassFromScope( const QStringList& scope )
{
QString scopeText = scope.join("::");
if( !m_imports.isEmpty() ) {
QMapIterator<QString, ClassDom> it = m_imports.back().first.find( scopeText );
if( it != m_imports.back().first.end() ) {
return *it;
}
}
ClassDom c = classFromScope( scope );
if( c ) {
if( !m_imports.isEmpty() ) m_imports.back().first[ scopeText ] = c;
return c;
}
if(!m_imports.isEmpty() && !m_imports.back().second.isEmpty()) {
///try the same using one of the imports(performance-wise this is not good, but simple)
QStringList::iterator it = m_imports.back().second.begin();
while(it != m_imports.back().second.end()) {
QStringList scp = QStringList::split("::", *it) + m_currentScope + scope;
c = classFromScope( scp );
if( c ) {
if( !m_imports.isEmpty() ) m_imports.back().first[ scopeText ] = c;
return c;
}
++it;
}
}
return c;
}
ClassDom findScopeInFile( const QStringList& scope, NamespaceModel* glob ) {
if( !glob ) return ClassDom();
ClassModel* curr = glob ;
QStringList::const_iterator mit = scope.begin();
while(curr->isNamespace() && mit != scope.end() && ((NamespaceModel*)curr)->hasNamespace( *mit )) {
curr = &(*( ((NamespaceModel*)curr)->namespaceByName( *mit ) ));
++mit;
}
while((curr->isNamespace() || curr->isClass()) && mit != scope.end() && curr->hasClass( *mit )) {
ClassList cl = curr->classByName( *mit );
curr = &(**cl.begin() );
++mit;
}
if(mit == scope.end()) {
return curr;
} else {
return ClassDom(0);
}
}
ClassDom StoreWalker::classFromScope(const QStringList& scope) {
if(scope.isEmpty())return ClassDom(0);
//Since another instance of the current file may still be in the code-model this must be testede BEFORE the code-model
ClassDom c = findScopeInFile( scope, m_file.data() );
if( c ) return c;
NamespaceDom glob = m_store->globalNamespace();
if( !glob ) return ClassDom();
c = findScopeInFile( scope, glob );
QMap<QString, FileDom>::const_iterator it;
if( c ) {
///Check the file that overrides the code-model file
it = m_overrides.find( c->fileName() );
//Find the class within the file that is overriding the one in code-model.
if( it != m_overrides.end() ) {
return findScopeInFile( scope, *it );
} else {
return c;
}
} else {
///Search in all overrides, because they will be added later all at once
for( QMap<QString, FileDom>::const_iterator it = m_overrides.begin(); it != m_overrides.end(); ++it ) {
c = findScopeInFile( scope, *it );
if( c )
return c;
}
}
return ClassDom(0);
}
QStringList StoreWalker::scopeOfDeclarator( DeclaratorAST* d, const QStringList& startScope )
{
return scopeOfName( d->declaratorId(), startScope );
}
//kate: indent-mode csands; tab-width 4; space-indent off;