/*************************************************************************** * Copyright (C) 2003 by Roberto Raggi * * roberto@tdevelop.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 "tag_creator.h" #include "catalog.h" #include "ast_utils.h" #include "cpp_tags.h" #include "doxydoc.h" #include "driver.h" #include #include #include DoxyDoc* TagCreator::m_documentation = new DoxyDoc( TQStringList() ); TagCreator::TagCreator( const TQString& fileName, Catalog* c ) : m_catalog( c ), m_fileName( fileName ), m_anon( 0 ) { } TagCreator::~TagCreator() { } void TagCreator::destroyDocumentation() { delete m_documentation; } void TagCreator::setDocumentationDirectories( const TQStringList& str ) { if ( m_documentation ) delete m_documentation; m_documentation = new DoxyDoc( str ); } void TagCreator::parseDeclaration( DeclarationAST* ast ) { if( ast->nodeType() == NodeType_AccessDeclaration || m_currentAccess.isEmpty() || m_currentAccess.contains("private") || ///In order to correctly evaluate templates, the private members are necessary too m_currentAccess.contains("public") || m_currentAccess.contains("protected") || m_currentAccess.contains("signals") ) { TreeParser::parseDeclaration( ast ); } } void TagCreator::parseTranslationUnit( const ParsedFile& ast ) { m_currentScope.clear(); m_currentAccess = TQString(); m_inSlots = false; m_inSignals = false; m_anon = 0; m_imports.clear(); m_inClass = false; m_imports << TQStringList(); Tag tag; tag.setKind( Tag::Kind_TranslationUnit ); tag.setFileName( m_fileName ); tag.setName( m_fileName ); TQByteArray data; TQDataStream stream(data, IO_WriteOnly ); ast.write( stream ); tag.setAttribute( "cppparsedfile", data ); tag.setAttribute( "includedFrom", ast.includedFrom() ); tag.setAttribute( "skippedLines", TQString("%1").arg( ast.skippedLines()) ); tag.setAttribute( "macroValueHash", TQString("%1").arg( ast.usedMacros().valueHash()) ); tag.setAttribute( "macroIdHash", TQString("%1").arg( ast.usedMacros().idHash() ) ); tag.setScope( m_currentScope ); if( !ast->comment().isEmpty() ) tag.setComment( ast->comment() ); m_catalog->addItem( tag ); TreeParser::parseTranslationUnit( ast ); m_imports.pop_back(); } void TagCreator::parseNamespaceAlias( NamespaceAliasAST* ast ) { TQString nsName; TQString aliasName; if( !ast->namespaceName() || ast->namespaceName()->text().isEmpty() ) { // anonymous namespace } else nsName = ast->namespaceName()->text(); if( ast->aliasName() ) aliasName = ast->aliasName()->text(); Tag tag; tag.setKind( Tag::Kind_Namespace ); tag.setFileName( m_fileName ); tag.setName( nsName ); ///nsName is the new name of the namespace tag.setAttribute( "alias", aliasName ); ///aliasName is the name of the real namespace tag.setScope( m_currentScope ); if( !ast->comment().isEmpty() ) tag.setComment( ast->comment() ); int line, col; ast->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); ast->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); m_catalog->addItem( tag ); TreeParser::parseNamespaceAlias( ast ); } void TagCreator::parseNamespace( NamespaceAST* ast ) { TQString nsName; if( !ast->namespaceName() || ast->namespaceName()->text().isEmpty() ) { // anonymous namespace } else nsName = ast->namespaceName()->text(); Tag tag; tag.setKind( Tag::Kind_Namespace ); tag.setFileName( m_fileName ); tag.setName( nsName ); tag.setScope( m_currentScope ); if( !ast->comment().isEmpty() ) tag.setComment( ast->comment() ); int line, col; ast->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); ast->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); m_catalog->addItem( tag ); m_currentScope.push_back( nsName ); TreeParser::parseNamespace( ast ); m_currentScope.pop_back(); } void TagCreator::parseElaboratedTypeSpecifier( ElaboratedTypeSpecifierAST* ast ) { TreeParser::parseElaboratedTypeSpecifier( ast ); } void TagCreator::parseUsingDirective( UsingDirectiveAST* ast ) { TQString name; if( ast->name() ) name = ast->name()->text(); if( !name.isNull() ){ Tag tag; tag.setKind( Tag::Kind_UsingDirective ); tag.setFileName( m_fileName ); tag.setName( name ); tag.setScope( m_currentScope ); int line, col; ast->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); ast->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); m_catalog->addItem( tag ); } m_imports.back().push_back( name ); } void TagCreator::parseTypedef( TypedefAST* ast ) { TypeSpecifierAST* typeSpec = ast->typeSpec(); InitDeclaratorListAST* declarators = ast->initDeclaratorList(); if( typeSpec && declarators ){ TQString typeId; if( typeSpec->name() ) typeId = typeSpec->name()->text(); TQPtrList l( declarators->initDeclaratorList() ); TQPtrListIterator it( l ); InitDeclaratorAST* initDecl = 0; while( 0 != (initDecl = it.current()) ) { TQString 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(); } Tag tag; if( !ast->comment().isEmpty() ) tag.setComment( ast->comment() ); 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 ); ++it; } } } void TagCreator::parseTemplateDeclaration( TemplateDeclarationAST* ast ) { m_currentTemplateDeclarator.push( ast ); if ( ast->declaration() ) parseDeclaration( ast->declaration() ); TreeParser::parseTemplateDeclaration( ast ); m_currentTemplateDeclarator.pop(); } void TagCreator::parseSimpleDeclaration( SimpleDeclarationAST* ast ) { CommentPusher push( *this, ast->comment() ); TypeSpecifierAST* typeSpec = ast->typeSpec(); InitDeclaratorListAST* declarators = ast->initDeclaratorList(); if( typeSpec ) parseTypeSpecifier( typeSpec ); if( declarators ) { TQPtrList l = declarators->initDeclaratorList(); TQPtrListIterator it( l ); while( it.current() ) { parseMyDeclaration( ast->functionSpecifier(), ast->storageSpecifier(), typeSpec, it.current() ); ++it; } } } void TagCreator::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 ) { TQPtrList l = funSpec->nodeList(); TQPtrListIterator it( l ); while ( it.current() ) { TQString text = it.current() ->text(); if ( text == "virtual" ) isVirtual = true; else if ( text == "inline" ) isInline = true; ++it; } } if ( storageSpec ) { TQPtrList l = storageSpec->nodeList(); TQPtrListIterator it( l ); while ( it.current() ) { TQString text = it.current() ->text(); if ( text == "friend" ) isFriend = true; else if ( text == "static" ) isStatic = true; ++it; } } TQString id = d->declaratorId() ->unqualifiedName() ->text().stripWhiteSpace(); TQString scopeStr = scopeOfDeclarator( d ); Tag tag; if( !comment() ) tag.setComment( ast->comment() ); CppFunction tagBuilder( tag ); tag.setKind( Tag::Kind_Function ); tag.setFileName( m_fileName ); tag.setName( id ); tag.setScope( TQStringList::split( ".", scopeStr ) ); if( !ast->comment().isEmpty() ) tag.setComment( ast->comment() ); int line, col; ast->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); ast->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); tagBuilder.setType( typeOfDeclaration( typeSpec, d ) ); parseFunctionArguments( tag, d ); checkTemplateDeclarator( tag ); TQString arguments = tag.attribute( "a" ).toStringList().join( "," ); tag.setAttribute( "description", m_documentation->functionDescription( scopeStr.replace( TQRegExp( "." ), ":" ), id, typeOfDeclaration( typeSpec, d ), arguments ) ); tagBuilder.setAccess( TagUtils::stringToAccess( m_currentAccess ) ); tagBuilder.setFriend( isFriend ); tagBuilder.setVirtual( isVirtual ); tagBuilder.setStatic( isStatic ); tagBuilder.setInline( isInline ); tagBuilder.setPure( false ); tagBuilder.setConst( d->constant() != 0 ); tagBuilder.setSignal( m_inSignals ); tagBuilder.setSlot( m_inSlots ); m_catalog->addItem( tag ); if ( !m_currentAccess.isEmpty() ) { tag.setKind( Tag::Kind_FunctionDeclaration ); m_catalog->addItem( tag ); } } void TagCreator::parseLinkageBody( LinkageBodyAST* ast ) { TQPtrList l = ast->declarationList(); TQPtrListIterator it( l ); while ( it.current() ) { parseDeclaration( it.current() ); ++it; } } void TagCreator::checkTemplateDeclarator( Tag& tag ) { if( !m_currentTemplateDeclarator.empty() && m_currentTemplateDeclarator.top() != 0) { TemplateDeclarationAST* a = m_currentTemplateDeclarator.top(); m_currentTemplateDeclarator.pop(); m_currentTemplateDeclarator.push(0); ///the template-declarator belongs to exactly this declaration takeTemplateParams( tag, a ); } } void TagCreator::takeTemplateParams( Tag& target, TemplateDeclarationAST* ast) { TemplateParameterListAST* pl = ast->templateParameterList(); if( pl ) { TQPtrList list = pl->templateParameterList(); TemplateParameterAST* curr = list.first(); while( curr != 0 ) { TQString a, b; if( curr->typeParameter() ) { if( curr->typeParameter()->name() ) a = curr->typeParameter()->name()->text(); if( curr->typeParameter()->typeId() ) b = curr->typeParameter()->typeId()->text(); } target.addTemplateParam( a, b ); curr = list.next(); } } } void TagCreator::parseClassSpecifier( ClassSpecifierAST* ast ) { int startLine, startColumn; int endLine, endColumn; ast->getStartPosition( &startLine, &startColumn ); ast->getEndPosition( &endLine, &endColumn ); TQString oldAccess = m_currentAccess; bool oldInSlots = m_inSlots; bool oldInSignals = m_inSignals; TQString kind = ast->classKey() ->text(); if ( kind == "class" ) m_currentAccess = "private"; else m_currentAccess = "public"; m_inSlots = false; m_inSignals = false; TQString className; if ( !ast->name() ) { //TQFileInfo fileInfo( m_fileName ); //TQString shortFileName = fileInfo.baseName(); //className.sprintf( "(%s_%d)", shortFileName.local8Bit(), m_anon++ ); } else { className = ast->name() ->text(); } Tag tag; if( !ast->comment().isEmpty() ) tag.setComment( ast->comment() ); tag.setKind( Tag::Kind_Class ); tag.setFileName( m_fileName ); int i = className.find( '<' ); TQString specialization; if( i != -1 ) { specialization = className.mid( i ); tag.setSpecializationDeclaration( specialization ); className = className.left( i ); } tag.setName( className ); tag.setScope( m_currentScope ); int line, col; ast->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); ast->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); checkTemplateDeclarator( tag ); m_catalog->addItem( tag ); if ( ast->baseClause() ) parseBaseClause( tag.path()+specialization, ast->baseClause() ); m_currentScope.push_back( className + specialization ); int oldInClass = m_inClass; m_inClass = true; TreeParser::parseClassSpecifier( ast ); m_currentScope.pop_back(); m_inClass = oldInClass; m_currentAccess = oldAccess; m_inSlots = oldInSlots; m_inSignals = oldInSignals; } void TagCreator::parseEnumSpecifier( EnumSpecifierAST* ast ) { Tag tag; if( !ast->comment().isEmpty() ) tag.setComment( ast->comment() ); tag.setKind( Tag::Kind_Enum ); tag.setFileName( m_fileName ); if ( ast->name() ) tag.setName( ast->name() ->text() ); tag.setScope( m_currentScope ); int line, col; ast->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); ast->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); m_catalog->addItem( tag ); TQPtrList l = ast->enumeratorList(); TQPtrListIterator it( l ); while ( it.current() ) { TQString name = it.current() ->id() ->text(); Tag tag; tag.setKind( Tag::Kind_Enumerator ); tag.setComment( it.current()->comment() ); tag.setFileName( m_fileName ); tag.setName( name ); tag.setScope( m_currentScope ); if( ast->name() ) { tag.setAttribute( "enum", ast->name()->text() ); } else { tag.setAttribute( "enum", "const int" ); } int line, col; it.current() ->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); it.current() ->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); m_catalog->addItem( tag ); ++it; } TreeParser::parseEnumSpecifier( ast ); } void TagCreator::parseMyDeclaration( GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl ) { 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(); TQString id; if ( t && t->declaratorId() && t->declaratorId() ->unqualifiedName() ) id = t->declaratorId() ->unqualifiedName() ->text(); TQString scopeStr = scopeOfDeclarator( d ); TQString type = typeOfDeclaration( typeSpec, d ); bool isFriend = false; //bool isVirtual = false; bool isStatic = false; //bool isInline = false; //bool isInitialized = decl->initializer() != 0; if ( storageSpec ) { TQPtrList l = storageSpec->nodeList(); TQPtrListIterator it( l ); while ( it.current() ) { TQString text = it.current() ->text(); if ( text == "friend" ) isFriend = true; else if ( text == "static" ) isStatic = true; ++it; } } Tag tag; CppVariable tagBuilder( tag ); tag.setKind( Tag::Kind_Variable ); tag.setFileName( m_fileName ); tag.setName( id ); tag.setScope( TQStringList::split( ".", scopeStr ) ); if( !comment().isEmpty() ) tag.setComment( comment() ); int line, col; decl->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); decl->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); tagBuilder.setType( type ); tagBuilder.setFriend( isFriend ); tagBuilder.setStatic( isStatic ); tagBuilder.setAccess( TagUtils::stringToAccess( m_currentAccess ) ); m_catalog->addItem( tag ); } void TagCreator::parseAccessDeclaration( AccessDeclarationAST * access ) { TQPtrList l = access->accessList(); m_currentAccess = l.at( 0 )->text(); if( m_currentAccess == "signals" ) m_currentAccess = "protected"; m_inSlots = l.count() > 1 ? l.at( 1 )->text() == "slots" : false; m_inSignals = l.count() >= 1 ? l.at( 0 )->text() == "signals" : false; } void TagCreator::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 ) { TQPtrList l = funSpec->nodeList(); TQPtrListIterator it( l ); while ( it.current() ) { TQString text = it.current() ->text(); if ( text == "virtual" ) isVirtual = true; else if ( text == "inline" ) isInline = true; ++it; } } if ( storageSpec ) { TQPtrList l = storageSpec->nodeList(); TQPtrListIterator it( l ); while ( it.current() ) { TQString 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(); TQString id = d->declaratorId() ->unqualifiedName() ->text(); TQString type = typeOfDeclaration( typeSpec, d ); Tag tag; CppFunction tagBuilder( tag ); if( !comment().isEmpty() ) tag.setComment( comment() ); tag.setKind( Tag::Kind_FunctionDeclaration ); tag.setFileName( m_fileName ); tag.setName( id ); tag.setScope( m_currentScope ); int line, col; decl->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); decl->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); tagBuilder.setType( type ); tagBuilder.setFriend( isFriend ); tagBuilder.setVirtual( isVirtual ); tagBuilder.setStatic( isStatic ); tagBuilder.setInline( isInline ); tagBuilder.setPure( isPure ); tagBuilder.setConst( d->constant() != 0 ); tagBuilder.setSignal( m_inSignals ); tagBuilder.setSlot( m_inSlots ); parseFunctionArguments( tag, d ); checkTemplateDeclarator( tag ); TQString arguments = tag.attribute( "a" ).toStringList().join( "," ); TQString scopeStr = m_currentScope.join( "::" ); tag.setAttribute( "description", m_documentation->functionDescription( scopeStr, id, type, arguments ) ); m_catalog->addItem( tag ); } void TagCreator::parseFunctionArguments( Tag& tag, DeclaratorAST* declarator ) { ParameterDeclarationClauseAST* clause = declarator->parameterDeclarationClause(); TQStringList types; TQStringList args; if( clause && clause->parameterDeclarationList() ){ ParameterDeclarationListAST* params = clause->parameterDeclarationList(); TQPtrList l( params->parameterList() ); TQPtrListIterator it( l ); while( it.current() ){ ParameterDeclarationAST* param = it.current(); ++it; TQString name; if( param->declarator() ){ name = declaratorToString(param->declarator(), TQString(), true ); } TQString type = typeOfDeclaration( param->typeSpec(), param->declarator() ); types << type; args << name; } if( clause->ellipsis() ){ types << "..."; args << ""; } } CppFunction tagBuilder( tag ); tagBuilder.setArguments( types ); tagBuilder.setArgumentNames( args ); } TQString TagCreator::typeOfDeclaration( TypeSpecifierAST* typeSpec, DeclaratorAST* declarator ) { if( !typeSpec || !declarator ) return TQString(); TQString text; text += typeSpec->text(); text = text.simplifyWhiteSpace(); TQPtrList ptrOpList = declarator->ptrOpList(); for( TQPtrListIterator it(ptrOpList); it.current(); ++it ) text += it.current()->text(); for( int a = 0; a < declarator->arrayDimensionList().count(); a++ ) text += "*"; return text; } void TagCreator::parseBaseClause( const TQString& className, BaseClauseAST * baseClause ) { TQPtrList l = baseClause->baseSpecifierList(); TQPtrListIterator it( l ); while ( it.current() ) { BaseSpecifierAST * baseSpecifier = it.current(); TQString access; if ( baseSpecifier->access() ) access = baseSpecifier->access() ->text(); bool isVirtual = baseSpecifier->isVirtual() != 0; if( baseSpecifier->name() == 0 ) return; ///Workaround for some bug elsewhere TQString baseName; if ( baseSpecifier->name() ) baseName = baseSpecifier->name() ->text(); Tag tag; CppBaseClass tagBuilder( tag ); tag.setKind( Tag::Kind_Base_class ); tag.setFileName( m_fileName ); tag.setName( className ); tag.setScope( m_currentScope ); tagBuilder.setBaseClass( baseName ); tagBuilder.setVirtual( isVirtual ); tagBuilder.setAccess( TagUtils::stringToAccess( access ) ); int line, col; baseClause->getStartPosition( &line, &col ); tag.setStartPosition( line, col ); baseClause->getEndPosition( &line, &col ); tag.setEndPosition( line, col ); m_catalog->addItem( tag ); ++it; } } TQString TagCreator::scopeOfDeclarator( DeclaratorAST* d ) { TQStringList scope = m_currentScope; if ( d && d->declaratorId() && d->declaratorId() ->classOrNamespaceNameList().count() ) { if ( d->declaratorId() ->isGlobal() ) scope.clear(); TQPtrList l = d->declaratorId() ->classOrNamespaceNameList(); TQPtrListIterator it( l ); while ( it.current() ) { if ( it.current() ->name() ) scope << it.current() ->name() ->text(); ++it; } } return scope.join( "." ); } int TagUtils::stringToAccess( const TQString & access ) { TQStringList l = TQStringList() << "public" << "protected" << "private" << "public slots" << "protected slots" << "private slots" << "signals"; int idx = l.findIndex( access ); return idx == -1 ? 0 : idx+1; } TQString TagUtils::accessToString( int id ) { if( id == 0 ) return "unknown"; TQStringList l = TQStringList() << "public" << "protected" << "private" << "public slots" << "protected slots" << "private slots" << "signals"; if( l.at(id-1) != l.end() ) return l[ id-1 ]; return TQString(); } //kate: indent-mode csands; tab-width 4; space-indent off;