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

789 lines
20 KiB

/***************************************************************************
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 <tqtextstream.h>
#include <tdeglobal.h>
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 TQString& 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 TQString& 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->_TDEShared_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->_TDEShared_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
TQString TypeDesc::nameWithParams() const {
if ( !m_data )
return "";
TQString ret;
{
TQTextStream 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
TQString TypeDesc::nameWithParams() const {
if( compare( *this ) != 0 ) {
compare( *this );
}
if ( !m_data )
return "";
TQString 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
TQString TypeDesc::fullName( ) const {
if ( !m_data )
return "";
TQString ret = nameWithParams();
for ( int a = 0; a < m_data->m_functionDepth; ++a )
ret = TQString( 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<TypeDescData*>( 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<TypeDescData*>( m_data.data() ) ->hashKey2();
//kdDebug( 9007 ) << "computed hash-key: " << fullName() << ": " << ret << endl;
return ret;
}
TQString TypeDesc::fullNameChain( ) const {
if ( !m_data )
return "";
TQString ret = fullName();
if ( m_data->m_nextType ) {
ret += "::" + m_data->m_nextType->fullNameChain();
}
return m_data->m_dec.apply( ret );
}
TQString TypeDesc::fullTypeStructure() const {
if ( !m_data )
return "";
TQString 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;
}
TQStringList TypeDesc::fullNameList( ) const {
if ( !m_data )
return "";
TQStringList 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<TypeDesc*>( this ) ->maybeInit();
return m_data->m_templateParams;
}
TypeDescPointer TypeDesc::next() {
if ( !m_data )
return 0;
return m_data->m_nextType;
}
TDESharedPtr<const TypeDescShared> 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 TQString& 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( TQString stri ) {
m_data = 0;
maybeInit();
if ( stri.isEmpty() )
return ;
m_data->m_dec = stri; ///Store the decoration
TQStringList ls = splitType( stri );
TQString 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( TQString( 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 ) {
TQChar 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();
TQPtrList<ClassOrNamespaceNameAST> l = name->classOrNamespaceNameList();
TQPtrListIterator<ClassOrNamespaceNameAST> it( l );
TQString 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 TQString& string ) {
makeDataPrivate();
m_data->m_templateParams.clear();
ParamIterator it( "<>", string );
TQString 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;
}