summaryrefslogtreecommitdiffstats
path: root/languages/cpp/typedesc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/cpp/typedesc.cpp')
-rw-r--r--languages/cpp/typedesc.cpp788
1 files changed, 788 insertions, 0 deletions
diff --git a/languages/cpp/typedesc.cpp b/languages/cpp/typedesc.cpp
new file mode 100644
index 00000000..2e4e28a0
--- /dev/null
+++ b/languages/cpp/typedesc.cpp
@@ -0,0 +1,788 @@
+/***************************************************************************
+ cppcodecompletion.cpp - description
+ -------------------
+ copyright : (C) 2006 by David Nolden
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 <qtextstream.h>
+
+#include <kglobal.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 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<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;
+}
+
+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<TypeDesc*>( this ) ->maybeInit();
+ return m_data->m_templateParams;
+}
+
+TypeDescPointer TypeDesc::next() {
+ if ( !m_data )
+ return 0;
+ return m_data->m_nextType;
+}
+
+KSharedPtr<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 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<ClassOrNamespaceNameAST> l = name->classOrNamespaceNameList();
+ QPtrListIterator<ClassOrNamespaceNameAST> 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;
+}
+
+