/*************************************************************************** cppcodecompletion.cpp - description ------------------- 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 "typedesc.h" #include "stringhelpers.h" #include "simpletype.h" #include "driver.h" #include "lexer.h" #include "parser.h" #include #include const char* TypeDesc::functionMark = "[function] "; ///Activated because of expressions like "const char* const"(the other algorithm chooses the const) //#define USELEXER using namespace StringHelpers; struct LocateResult::D { TypeDesc m_desc; }; LocateResult& LocateResult::operator = ( const TypeDesc& rhs ) { *this = LocateResult( rhs ); return *this; } LocateResult::LocateResult() : d( new D() ), m_resolutionCount( 0 ), m_flags( NoFlag ), m_trace( 0 ), m_locateDepth( 0 ) {} LocateResult::LocateResult( const TypeDesc& desc ) : d( new D() ), m_resolutionCount( 0 ), m_flags( NoFlag ), m_trace( 0 ), m_locateDepth( 0 ) { d->m_desc = desc; } LocateResult::LocateResult( const TypeDescPointer& desc ) : d( new D() ), m_resolutionCount( 0 ), m_flags( NoFlag ), m_trace( 0 ), m_locateDepth( 0 ) { d->m_desc = *desc; } LocateResult::LocateResult( TypeDescShared* desc ) : d( new D() ), m_resolutionCount( 0 ), m_flags( NoFlag ), m_trace( 0 ), m_locateDepth( 0 ) { d->m_desc = *desc; } LocateResult::LocateResult( const LocateResult& rhs ) : d( new D() ), m_resolutionCount( rhs.m_resolutionCount ), m_flags( rhs.m_flags ), m_trace( 0 ), m_locateDepth( rhs.m_locateDepth ) { d->m_desc = rhs.d->m_desc; if ( rhs.m_trace ) m_trace = new TypeTrace( *rhs.m_trace ); } LocateResult::~LocateResult() { if ( m_trace ) delete m_trace; delete d; } LocateResult& LocateResult::operator = ( const LocateResult& rhs ) { if ( &rhs == this ) return * this; d->m_desc = rhs.d->m_desc; m_locateDepth = rhs.m_locateDepth; m_flags = rhs.m_flags; m_resolutionCount = rhs.m_resolutionCount; if ( m_trace ) delete m_trace; if ( !rhs.m_trace ) { m_trace = 0; } else { m_trace = new TypeTrace( *rhs.m_trace ); } return *this; } LocateResult::operator const TypeDesc&() const { return d->m_desc; } LocateResult::operator TypeDesc&() { return d->m_desc; } TypeDesc& LocateResult::desc() { return d->m_desc; } const TypeDesc& LocateResult::desc() const { return d->m_desc; } const TypeDesc* LocateResult::operator ->() const { return &d->m_desc; } TypeDesc* LocateResult::operator ->() { return &d->m_desc; } LocateResult::operator bool() const { return d->m_desc; } /* LocateResult::operator TypeDescPointer() { if ( !m_desc ) m_desc = new TypeDescShared(); return m_desc; }*/ void LocateResult::addResolutionFlag( ResolutionFlags flag ) { m_flags = addFlag( flag, m_flags ); } bool LocateResult::hasResolutionFlag( ResolutionFlags flag ) const { return ( bool ) ( m_flags & flag ); } TypeTrace* LocateResult::trace() { if ( !m_trace ) m_trace = new TypeTrace(); return m_trace; } TypeDesc::TypeDesc() {} TypeDesc::TypeDesc( const QString& name ) { init( name ); } TypeDesc::TypeDesc( const TypeDesc& rhs ) { *this = rhs; } bool TypeDesc::isValidType() const { if ( !m_data ) return false; if ( m_data->m_cleanName.find( "->" ) != -1 || m_data->m_cleanName.contains( '.' ) || m_data->m_cleanName.contains( ' ' ) || m_data->m_cleanName.isEmpty() ) return false; for ( TemplateParams::const_iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { if ( !( *it ) ->isValidType() ) return false; } if ( m_data->m_nextType ) if ( !m_data->m_nextType->isValidType() ) return false; return true; } TypeDesc& TypeDesc::operator = ( const TypeDesc& rhs ) { m_data = rhs.m_data; return *this; } void TypeDesc::prependDecoration( const QString& str ) { makePrivate(); m_data->m_dec.prepend( str ); } int TypeDesc::depth() const { if ( !m_data ) return 0; int ret = 1; for ( TemplateParams::const_iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { ret = kMax( ( *it ) ->depth() + 1, ret ); } if ( m_data->m_nextType ) { ret = kMax( m_data->m_nextType->depth(), ret ); } return ret; } int TypeDesc::length() const { if ( !m_data ) return 0; if ( !m_data->m_nextType && m_data->m_cleanName.isEmpty() ) return 0; return m_data->m_nextType ? 1 + m_data->m_nextType->length() : 1; } HashedStringSet TypeDesc::includeFiles() const { if( !m_data ) return HashedStringSet(); return m_data->m_includeFiles; } void TypeDesc::setIncludeFiles( const HashedStringSet& files ) { makeDataPrivate(); m_data->m_includeFiles = files; for ( TemplateParams::iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { (*it)->setIncludeFiles( files ); } if( m_data->m_nextType ) { if( m_data->m_nextType->_KShared_count() != 1 ) m_data->m_nextType = new TypeDescShared( *(m_data->m_nextType) ); m_data->m_nextType->setIncludeFiles( files ); } } void TypeDesc::addIncludeFiles( const HashedStringSet& files ) { makeDataPrivate(); m_data->m_includeFiles += files; for ( TemplateParams::iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { (*it)->addIncludeFiles( files ); } if( m_data->m_nextType ) { if( m_data->m_nextType->_KShared_count() != 1 ) m_data->m_nextType = new TypeDescShared( *(m_data->m_nextType) ); m_data->m_nextType->addIncludeFiles( files ); } } size_t TypeDescData::hashKey() { size_t ret = 0; if ( m_hashValid ) { ret = m_hashKey; } else { ret += 89 * m_pointerDepth; ret += 101 * m_functionDepth; int len = m_cleanName.length(); for ( int a = 0; a < len; a++ ) ret += m_cleanName[ a ].unicode() * 3 * (11*(a+1)); int n = 1; for ( TemplateParams::const_iterator it = m_templateParams.begin(); it != m_templateParams.end() ; ++it ) { ret += 107 * n * ( *it ) ->hashKey(); n++; } m_hashKey = ret; m_hashValid = true; } if ( m_nextType ) ret += 109 * m_nextType->hashKey(); return ret; } size_t TypeDescData::hashKey2() { size_t ret = 0; if( m_hash2Valid ) { ret = m_hashKey2; } else { ret += 13 * m_pointerDepth; ret += 17 * m_functionDepth; int len = m_cleanName.length(); for ( int a = 0; a < len; a++ ) ret += m_cleanName[ a ].unicode() * 19 * (7*(a+1)); int n = 1; for ( TemplateParams::const_iterator it = m_templateParams.begin(); it != m_templateParams.end() ; ++it ) { ret += 23 * n * ( *it ) ->hashKey2(); n++; } m_hashKey2 = ret; m_hash2Valid = true; } if ( m_nextType ) ret += 29 * m_nextType->hashKey2(); return ret; } ///Something is wrong with this function.. so i use the string-comparison int TypeDesc::compare ( const TypeDesc& rhs ) const { if ( m_data == rhs.m_data ) return 0; if ( !m_data ) return -1; if ( !rhs.m_data ) return 1; /*static int dpth = 0; dpth++; if( dpth == 1 && (*this == rhs) )kdDebug( 9007 ) << "failed comparing " << fullNameChain() << " and " << rhs.fullNameChain() << " hashes: " << hashKey() << " " << rhs.hashKey() << endl; dpth--;*/ if ( m_data->m_functionDepth != rhs.m_data->m_functionDepth ) { if ( m_data->m_functionDepth < rhs.m_data->m_functionDepth ) return -1; else return 1; } if ( m_data->m_pointerDepth != rhs.m_data->m_pointerDepth ) { if ( m_data->m_pointerDepth < rhs.m_data->m_pointerDepth ) return -1; else return 1; } if ( m_data->m_cleanName != rhs.m_data->m_cleanName ) { if ( m_data->m_cleanName < rhs.m_data->m_cleanName ) return -1; else return 1; } if ( m_data->m_templateParams.size() != rhs.m_data->m_templateParams.size() ) { if ( m_data->m_templateParams.size() < rhs.m_data->m_templateParams.size() ) return -1; else return 1; } TemplateParams::const_iterator it2 = rhs.m_data->m_templateParams.begin(); TemplateParams::const_iterator it = m_data->m_templateParams.begin(); for ( ; it != m_data->m_templateParams.end() && it2 != rhs.m_data->m_templateParams.end(); ) { int cmp = ( *it ) ->compare( **it2 ); if ( cmp != 0 ) { return cmp; } ++it2; ++it; } if ( !( ( bool ) m_data->m_nextType ) != ( ( bool ) rhs.m_data->m_nextType ) ) { if ( m_data->m_nextType ) return 1; else return -1; } if ( m_data->m_nextType && rhs.m_data->m_nextType ) return m_data->m_nextType->compare( *rhs.m_data->m_nextType ); return 0; } #ifdef USE_TEXT_STREAM QString TypeDesc::nameWithParams() const { if ( !m_data ) return ""; QString ret; { QTextStream s( &ret, IO_WriteOnly ); s << m_data->m_cleanName; if ( !m_data->m_templateParams.isEmpty() ) { s << "<"; bool first = true; for ( TemplateParams::const_iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { if ( !first ) s << ", "; s << ( *it ) ->fullNameChain(); first = false; } } s << ">"; } return ret; } #else QString TypeDesc::nameWithParams() const { if( compare( *this ) != 0 ) { compare( *this ); } if ( !m_data ) return ""; QString ret = m_data->m_cleanName; if ( !m_data->m_templateParams.isEmpty() ) { ret += "<"; bool first = true; for ( TemplateParams::const_iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { if ( !first ) ret += ", "; ret += ( *it ) ->fullNameChain(); first = false; } ret += ">"; } return ret; } #endif QString TypeDesc::fullName( ) const { if ( !m_data ) return ""; QString ret = nameWithParams(); for ( int a = 0; a < m_data->m_functionDepth; ++a ) ret = QString( functionMark ) + ret; for ( int a = 0; a < m_data->m_pointerDepth; ++a ) ret += "*"; return m_data->m_dec.apply( ret ); } size_t TypeDesc::hashKey() const { if ( !m_data ) return 0; size_t ret = const_cast( m_data.data() ) ->hashKey(); //kdDebug( 9007 ) << "computed hash-key: " << fullName() << ": " << ret << endl; return ret; } size_t TypeDesc::hashKey2() const { if ( !m_data ) return 0; size_t ret = const_cast( m_data.data() ) ->hashKey2(); //kdDebug( 9007 ) << "computed hash-key: " << fullName() << ": " << ret << endl; return ret; } QString TypeDesc::fullNameChain( ) const { if ( !m_data ) return ""; QString ret = fullName(); if ( m_data->m_nextType ) { ret += "::" + m_data->m_nextType->fullNameChain(); } return m_data->m_dec.apply( ret ); } QString TypeDesc::fullTypeStructure() const { if ( !m_data ) return ""; QString ret = m_data->m_cleanName; if ( !m_data->m_templateParams.isEmpty() ) { ret += "<"; for ( TemplateParams::const_iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { ret += ( *it ) ->fullTypeStructure(); ret += ", "; } ret.truncate( ret.length() - 2 ); ret += ">"; } return ret; } QStringList TypeDesc::fullNameList( ) const { if ( !m_data ) return ""; QStringList ret; ret << fullName(); if ( m_data->m_nextType ) { ret += m_data->m_nextType->fullNameList(); } return ret; } /// The template-params may be changed in-place /// this list is local, but the params pointed by them not TypeDesc::TemplateParams& TypeDesc::templateParams() { makeDataPrivate(); return m_data->m_templateParams; } const TypeDesc::TemplateParams& TypeDesc::templateParams() const { const_cast( this ) ->maybeInit(); return m_data->m_templateParams; } TypeDescPointer TypeDesc::next() { if ( !m_data ) return 0; return m_data->m_nextType; } KSharedPtr TypeDesc::next() const { if ( !m_data ) return 0; return m_data->m_nextType.data(); } bool TypeDesc::hasTemplateParams() const { if ( !m_data ) return false; return !m_data->m_templateParams.isEmpty(); } void TypeDesc::setNext( TypeDescPointer type ) { makeDataPrivate(); m_data->m_nextType = type; } void TypeDesc::append( TypeDescPointer type ) { if ( type ) { makeDataPrivate(); if ( m_data->m_nextType ) m_data->m_nextType->append( type ); else m_data->m_nextType = type; } } TypePointer TypeDesc::resolved() const { if ( !m_data ) return 0; return m_data->m_resolved; } void TypeDesc::setResolved( TypePointer resolved ) { makeDataPrivate(); m_data->m_resolved = resolved; } void TypeDesc::resetResolved() { if ( !m_data ) return ; makeDataPrivate(); m_data->m_resolved = 0; if ( m_data->m_nextType ) m_data->m_nextType->resetResolved(); } ///Resets the resolved-pointers of this type, and all template-types void TypeDesc::resetResolvedComplete() { if ( !m_data ) return ; makeDataPrivate(); resetResolved(); for ( TemplateParams::iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) ( *it ) ->resetResolvedComplete(); } ///these might be changed in future to an own data-member void TypeDesc::increaseFunctionDepth() { makeDataPrivate(); m_data->m_functionDepth++; } void TypeDesc::decreaseFunctionDepth() { makeDataPrivate(); if ( m_data->m_functionDepth > 0 ) m_data->m_functionDepth--; } int TypeDesc::functionDepth() const { if ( !m_data ) return 0; return m_data->m_functionDepth; } void TypeDesc::takeInstanceInfo( const TypeDesc& rhs ) { makeDataPrivate(); if( !rhs.m_data ) return; m_data->m_pointerDepth += rhs.m_data->m_pointerDepth; m_data->m_dec += rhs.m_data->m_dec; } void TypeDesc::clearInstanceInfo() { if ( !m_data ) return ; makeDataPrivate(); m_data->m_pointerDepth = 0; m_data->m_dec.clear(); } void TypeDesc::takeTemplateParams( const QString& string ) { makeDataPrivate(); m_data->m_templateParams.clear(); for ( ParamIterator it( "<>", string ); it; ++it ) m_data->m_templateParams.append( new TypeDescShared( *it ) ); } void TypeDesc::makeDataPrivate() { if ( !m_data ) { maybeInit(); return ; } if ( m_data.count() > 1 ) { m_data = new TypeDescData( *m_data ); } m_data->invalidateKey(); } TypeDesc& TypeDesc::makePrivate() { makeDataPrivate(); TemplateParams nList; for ( TemplateParams::const_iterator it = m_data->m_templateParams.begin(); it != m_data->m_templateParams.end(); ++it ) { TypeDescPointer tp( new TypeDescShared( ) ); *tp = **it; tp->makePrivate(); nList.append( tp ); } m_data->m_templateParams = nList; if ( m_data->m_nextType ) { TypeDescPointer tmp = m_data->m_nextType; m_data->m_nextType = new TypeDescShared(); *m_data->m_nextType = *tmp; m_data->m_nextType->makePrivate(); } return *this; } int TypeDesc::totalPointerDepth() const { if( next() ) return next()->totalPointerDepth(); else return pointerDepth(); } void TypeDesc::setTotalPointerDepth( int d ) { makePrivate(); if( next() ) next()->setTotalPointerDepth( d ); else setPointerDepth( d ); } void TypeDesc::maybeInit() { if ( m_data ) return ; m_data = new TypeDescData(); m_data->m_pointerDepth = 0; m_data->m_functionDepth = 0; m_data->m_nextType = 0; m_data->m_flags = Standard; } /* bool TypeDesc::decorationSmaller( const TypeDesc& rhs ) { maybeInit(); rhs.maybeInit(); return m_data->m_dec.smaller( rhs.m_data.m_dec ); } int TypeDesc::decorationDepth() { if( !m_data ) return 0; return m_data->m_dec.depth(); }*/ void TypeDesc::init( QString stri ) { m_data = 0; maybeInit(); if ( stri.isEmpty() ) return ; m_data->m_dec = stri; ///Store the decoration QStringList ls = splitType( stri ); QString str = ls.front().stripWhiteSpace(); ///Extract multiple types that may be written as a scope and put them to the next-types-list if ( !ls.isEmpty() ) { ls.pop_front(); if ( !ls.isEmpty() ) { m_data->m_nextType = TypeDescPointer( new TypeDescShared( ls.join( "::" ) ) ); } } while ( str.startsWith( QString( functionMark ) ) ) { m_data->m_functionDepth++; str = str.mid( strlen( functionMark ) ).stripWhiteSpace(); } bool isFunction = false, shorten = true; //Little hack done for performance-reasons, to do less comparing if( str.length() >= 4 ) { QChar c = str[0]; switch( c.latin1() ) { case 's': if( str[1] == 'h' ) { if( str.startsWith( "short" ) ) shorten = false; } else if( str[1] == 'i' ) { if( str.startsWith( "signed" ) ) shorten = false; } break; case 'l': if( str.startsWith( "long" ) ) shorten = false; break; case 'u': if( str.startsWith( "unsigned" ) ) shorten = false; break; case 'o': if( str.startsWith( "operator " ) ) { isFunction = true; shorten = false; } } } ///Since function-names are also processed by this function, this check has to be done if( shorten ) { ///Remove any prefixes like const or typename(very limited algorithm) int len = str.find( "<" ); if ( len == -1 ) len = str.length(); int currentStart = 0; bool wasEmpty = false; for ( int a = 0; a < len; a++ ) { if ( str[ a ] == ' ' ) { wasEmpty = true; } else if( wasEmpty && isValidIdentifierSign( str[a] ) ){ currentStart = a; wasEmpty = false; } } str = str.mid( currentStart ); } #ifdef USELEXER Driver d; Lexer lex( &d ); lex.setSource( str ); Parser parser( &d, &lex ); TypeSpecifierAST::Node typeSpec; if ( parser.parseTypeSpecifier( typeSpec ) ) { NameAST * name = typeSpec->name(); QPtrList l = name->classOrNamespaceNameList(); QPtrListIterator it( l ); QString type; while ( it.current() ) { if ( it.current() ->name() ) { type += it.current() ->name() ->text() + "::"; } ++it; } if ( name->unqualifiedName() && name->unqualifiedName() ->name() ) { type += name->unqualifiedName() ->name() ->text(); } m_data->m_cleanName = type.stripWhiteSpace(); takeTemplateParams( str ); m_data->m_pointerDepth = countExtract( '*', str ); } #else if( !isFunction ) { takeData( str ); m_data->m_pointerDepth = countExtract( '*', str ); } else { m_data->m_cleanName = str; } #endif } void TypeDesc::takeData( const QString& string ) { makeDataPrivate(); m_data->m_templateParams.clear(); ParamIterator it( "<>", string ); QString name = it.prefix(); name.remove( "*" ); name.remove( "&" ); m_data->m_cleanName = name.stripWhiteSpace(); for ( ; it; ++it ) m_data->m_templateParams.append( new TypeDescShared( *it ) ); } TypeDesc operator + ( const TypeDesc& lhs, const TypeDesc& rhs ) { TypeDesc ret = lhs; ret.makePrivate(); ret.append( new TypeDescShared( rhs ) ); return ret; }