diff options
Diffstat (limited to 'languages/cpp/store_walker.cpp')
-rw-r--r-- | languages/cpp/store_walker.cpp | 1081 |
1 files changed, 1081 insertions, 0 deletions
diff --git a/languages/cpp/store_walker.cpp b/languages/cpp/store_walker.cpp new file mode 100644 index 00000000..cd66dd23 --- /dev/null +++ b/languages/cpp/store_walker.cpp @@ -0,0 +1,1081 @@ +/*************************************************************************** +* 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; |