2009-03-25 13:42:47 +01:00
/**************************************************************************
* *
* * This file is part of Qt Creator
* *
2010-03-05 11:25:49 +01:00
* * Copyright ( c ) 2010 Nokia Corporation and / or its subsidiary ( - ies ) .
2009-03-25 13:42:47 +01:00
* *
2009-06-17 00:01:27 +10:00
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
2009-03-25 13:42:47 +01:00
* *
* * Commercial Usage
* *
* * Licensees holding valid Qt Commercial licenses may use this file in
* * accordance with the Qt Commercial License Agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
* * a written agreement between you and Nokia .
* *
* * GNU Lesser General Public License Usage
* *
* * Alternatively , this file may be used under the terms of the GNU Lesser
* * General Public License version 2.1 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 2.1 requirements
* * will be met : http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
* *
* * If you are unsure which license is appropriate for your use , please
2009-08-14 09:30:56 +02:00
* * contact the sales department at http : //qt.nokia.com/contact.
2009-03-25 13:42:47 +01:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "watchutils.h"
2009-04-29 14:15:09 +02:00
# include "watchhandler.h"
2009-09-18 16:55:17 +02:00
# include "gdb/gdbmi.h"
2009-04-29 14:15:09 +02:00
# include <utils/qtcassert.h>
2009-03-25 13:42:47 +01:00
2009-10-01 16:38:08 +02:00
# include <coreplugin/ifile.h>
2009-05-14 14:29:37 +02:00
# include <texteditor/basetexteditor.h>
# include <texteditor/basetextmark.h>
# include <texteditor/itexteditor.h>
# include <texteditor/texteditorconstants.h>
# include <cpptools/cppmodelmanagerinterface.h>
# include <cpptools/cpptoolsconstants.h>
# include <cplusplus/ExpressionUnderCursor.h>
2009-10-16 16:26:28 +02:00
# include <cplusplus/Overview.h>
# include <Symbols.h>
# include <Scope.h>
2009-05-14 14:29:37 +02:00
# include <extensionsystem/pluginmanager.h>
2009-03-25 13:42:47 +01:00
# include <QtCore/QDebug>
# include <QtCore/QTime>
# include <QtCore/QStringList>
2009-04-29 14:15:09 +02:00
# include <QtCore/QCoreApplication>
# include <QtCore/QTextStream>
2009-10-16 16:26:28 +02:00
# include <QtCore/QHash>
2009-04-29 14:15:09 +02:00
2009-05-14 14:29:37 +02:00
# include <QtGui/QTextCursor>
# include <QtGui/QPlainTextEdit>
2009-04-29 14:15:09 +02:00
# include <string.h>
# include <ctype.h>
enum { debug = 0 } ;
2009-10-16 16:26:28 +02:00
// Debug helpers for code model. @todo: Move to some CppTools library?
namespace CPlusPlus {
static void debugCppSymbolRecursion ( QTextStream & str , const Overview & o ,
const Symbol & s , bool doRecurse = true ,
int recursion = 0 )
{
for ( int i = 0 ; i < recursion ; i + + )
str < < " " ;
str < < " Symbol: " < < o . prettyName ( s . name ( ) ) < < " at line " < < s . line ( ) ;
if ( s . isFunction ( ) )
str < < " function " ;
if ( s . isClass ( ) )
str < < " class " ;
if ( s . isDeclaration ( ) )
str < < " declaration " ;
if ( s . isBlock ( ) )
str < < " block " ;
if ( doRecurse & & s . isScopedSymbol ( ) ) {
const ScopedSymbol * scoped = s . asScopedSymbol ( ) ;
const int size = scoped - > memberCount ( ) ;
str < < " scoped symbol of " < < size < < ' \n ' ;
for ( int m = 0 ; m < size ; m + + )
debugCppSymbolRecursion ( str , o , * scoped - > memberAt ( m ) , true , recursion + 1 ) ;
} else {
str < < ' \n ' ;
}
}
QDebug operator < < ( QDebug d , const Symbol & s )
{
QString output ;
CPlusPlus : : Overview o ;
QTextStream str ( & output ) ;
debugCppSymbolRecursion ( str , o , s , true , 0 ) ;
d . nospace ( ) < < output ;
return d ;
}
QDebug operator < < ( QDebug d , const Scope & scope )
{
QString output ;
Overview o ;
QTextStream str ( & output ) ;
const int size = scope . symbolCount ( ) ;
str < < " Scope of " < < size ;
if ( scope . isNamespaceScope ( ) )
str < < " namespace " ;
if ( scope . isClassScope ( ) )
str < < " class " ;
if ( scope . isEnumScope ( ) )
str < < " enum " ;
if ( scope . isBlockScope ( ) )
str < < " block " ;
if ( scope . isFunctionScope ( ) )
str < < " function " ;
if ( scope . isPrototypeScope ( ) )
str < < " prototype " ;
if ( const Symbol * owner = scope . owner ( ) ) {
str < < " owner: " ;
debugCppSymbolRecursion ( str , o , * owner , false , 0 ) ;
} else {
str < < " 0-owner \n " ;
}
for ( int s = 0 ; s < size ; s + + )
debugCppSymbolRecursion ( str , o , * scope . symbolAt ( s ) , true , 2 ) ;
d . nospace ( ) < < output ;
return d ;
}
} // namespace CPlusPlus
2009-03-25 13:42:47 +01:00
namespace Debugger {
namespace Internal {
2010-01-05 16:51:55 +01:00
QByteArray dotEscape ( QByteArray str )
2009-03-25 13:42:47 +01:00
{
2010-01-05 16:51:55 +01:00
str . replace ( ' ' , ' . ' ) ;
str . replace ( ' \\ ' , ' . ' ) ;
str . replace ( ' / ' , ' . ' ) ;
2009-03-25 13:42:47 +01:00
return str ;
}
QString currentTime ( )
{
return QTime : : currentTime ( ) . toString ( QLatin1String ( " hh:mm:ss.zzz " ) ) ;
}
bool isSkippableFunction ( const QString & funcName , const QString & fileName )
{
if ( fileName . endsWith ( QLatin1String ( " kernel/qobject.cpp " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " kernel/moc_qobject.cpp " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " kernel/qmetaobject.cpp " ) ) )
return true ;
2009-08-20 11:49:56 +02:00
if ( fileName . endsWith ( QLatin1String ( " kernel/qmetaobject_p.h " ) ) )
return true ;
2009-03-25 13:42:47 +01:00
if ( fileName . endsWith ( QLatin1String ( " .moc " ) ) )
return true ;
2010-02-01 12:43:56 +01:00
if ( funcName . endsWith ( QLatin1String ( " ::qt_metacall " ) ) )
2009-03-25 13:42:47 +01:00
return true ;
2010-02-01 12:43:56 +01:00
if ( funcName . endsWith ( QLatin1String ( " ::d_func " ) ) )
2009-08-20 11:49:56 +02:00
return true ;
2010-02-01 12:43:56 +01:00
if ( funcName . endsWith ( QLatin1String ( " ::q_func " ) ) )
2009-08-20 11:49:56 +02:00
return true ;
2009-03-25 13:42:47 +01:00
return false ;
}
bool isLeavableFunction ( const QString & funcName , const QString & fileName )
{
if ( funcName . endsWith ( QLatin1String ( " QObjectPrivate::setCurrentSender " ) ) )
return true ;
2009-08-20 11:49:56 +02:00
if ( funcName . endsWith ( QLatin1String ( " QMutexPool::get " ) ) )
return true ;
2009-03-25 13:42:47 +01:00
if ( fileName . endsWith ( QLatin1String ( " kernel/qmetaobject.cpp " ) )
& & funcName . endsWith ( QLatin1String ( " QMetaObject::methodOffset " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " kernel/qobject.h " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " kernel/qobject.cpp " ) )
& & funcName . endsWith ( QLatin1String ( " QObjectConnectionListVector::at " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " kernel/qobject.cpp " ) )
& & funcName . endsWith ( QLatin1String ( " ~QObject " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " thread/qmutex.cpp " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " thread/qthread.cpp " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " thread/qthread_unix.cpp " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " thread/qmutex.h " ) ) )
return true ;
if ( fileName . contains ( QLatin1String ( " thread/qbasicatomic " ) ) )
return true ;
if ( fileName . contains ( QLatin1String ( " thread/qorderedmutexlocker_p " ) ) )
return true ;
if ( fileName . contains ( QLatin1String ( " arch/qatomic " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " tools/qvector.h " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " tools/qlist.h " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " tools/qhash.h " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " tools/qmap.h " ) ) )
return true ;
2009-08-20 11:49:56 +02:00
if ( fileName . endsWith ( QLatin1String ( " tools/qshareddata.h " ) ) )
return true ;
2009-03-25 13:42:47 +01:00
if ( fileName . endsWith ( QLatin1String ( " tools/qstring.h " ) ) )
return true ;
if ( fileName . endsWith ( QLatin1String ( " global/qglobal.h " ) ) )
return true ;
return false ;
}
bool hasLetterOrNumber ( const QString & exp )
{
const QChar underscore = QLatin1Char ( ' _ ' ) ;
for ( int i = exp . size ( ) ; - - i > = 0 ; )
if ( exp . at ( i ) . isLetterOrNumber ( ) | | exp . at ( i ) = = underscore )
return true ;
return false ;
}
bool hasSideEffects ( const QString & exp )
{
// FIXME: complete?
return exp . contains ( QLatin1String ( " -= " ) )
| | exp . contains ( QLatin1String ( " += " ) )
| | exp . contains ( QLatin1String ( " /= " ) )
2009-05-05 20:33:31 +02:00
| | exp . contains ( QLatin1String ( " %= " ) )
2009-03-25 13:42:47 +01:00
| | exp . contains ( QLatin1String ( " *= " ) )
| | exp . contains ( QLatin1String ( " &= " ) )
| | exp . contains ( QLatin1String ( " |= " ) )
| | exp . contains ( QLatin1String ( " ^= " ) )
| | exp . contains ( QLatin1String ( " -- " ) )
| | exp . contains ( QLatin1String ( " ++ " ) ) ;
}
bool isKeyWord ( const QString & exp )
{
// FIXME: incomplete
return exp = = QLatin1String ( " class " )
| | exp = = QLatin1String ( " const " )
| | exp = = QLatin1String ( " do " )
| | exp = = QLatin1String ( " if " )
| | exp = = QLatin1String ( " return " )
| | exp = = QLatin1String ( " struct " )
| | exp = = QLatin1String ( " template " )
| | exp = = QLatin1String ( " void " )
| | exp = = QLatin1String ( " volatile " )
| | exp = = QLatin1String ( " while " ) ;
}
bool isPointerType ( const QString & type )
{
return type . endsWith ( QLatin1Char ( ' * ' ) ) | | type . endsWith ( QLatin1String ( " * const " ) ) ;
}
2009-12-07 12:06:01 +01:00
bool isCharPointerType ( const QString & type )
{
return type = = QLatin1String ( " char * " )
| | type = = QLatin1String ( " const char * " )
| | type = = QLatin1String ( " char const * " ) ;
}
2009-03-25 13:42:47 +01:00
bool startsWithDigit ( const QString & str )
{
return ! str . isEmpty ( ) & & str . at ( 0 ) . isDigit ( ) ;
}
QString stripPointerType ( QString type )
{
if ( type . endsWith ( QLatin1Char ( ' * ' ) ) )
type . chop ( 1 ) ;
if ( type . endsWith ( QLatin1String ( " * const " ) ) )
type . chop ( 7 ) ;
if ( type . endsWith ( QLatin1Char ( ' ' ) ) )
type . chop ( 1 ) ;
return type ;
}
2009-10-16 16:26:28 +02:00
/* getUninitializedVariables(): Get variables that are not initialized
* at a certain line of a function from the code model to be able to
* indicate them as not in scope in the locals view .
* Find document + function in the code model , do a double check and
* collect declarative symbols that are in the function past or on
* the current line . blockRecursion ( ) recurses up the scopes
* and collect symbols declared past or on the current line .
* Recursion goes up from the innermost scope , keeping a map
* of occurrences seen , to be able to derive the names of
* shadowed variables as the debugger sees them :
\ code
int x ; // Occurrence (1), should be reported as "x <shadowed 1>"
if ( true ) {
int x = 5 ; ( 2 ) // Occurrence (2), should be reported as "x"
}
\ endcode
*/
typedef QHash < QString , int > SeenHash ;
static void blockRecursion ( const CPlusPlus : : Overview & overview ,
const CPlusPlus : : Scope * scope ,
unsigned line ,
QStringList * uninitializedVariables ,
SeenHash * seenHash ,
int level = 0 )
{
const int size = scope - > symbolCount ( ) ;
for ( int s = 0 ; s < size ; s + + ) {
const CPlusPlus : : Symbol * symbol = scope - > symbolAt ( s ) ;
if ( symbol - > isDeclaration ( ) ) {
// Find out about shadowed symbols by bookkeeping
// the already seen occurrences in a hash.
const QString name = overview . prettyName ( symbol - > name ( ) ) ;
SeenHash : : iterator it = seenHash - > find ( name ) ;
if ( it = = seenHash - > end ( ) ) {
it = seenHash - > insert ( name , 0 ) ;
} else {
+ + ( it . value ( ) ) ;
2010-01-29 21:33:57 +01:00
}
2009-10-16 16:26:28 +02:00
// Is the declaration on or past the current line, that is,
// the variable not initialized.
if ( symbol - > line ( ) > = line )
uninitializedVariables - > push_back ( WatchData : : shadowedName ( name , it . value ( ) ) ) ;
}
}
// Next block scope.
if ( const CPlusPlus : : Scope * enclosingScope = scope - > enclosingBlockScope ( ) )
blockRecursion ( overview , enclosingScope , line , uninitializedVariables , seenHash , level + 1 ) ;
}
// Inline helper with integer error return codes.
static inline
int getUninitializedVariablesI ( const CPlusPlus : : Snapshot & snapshot ,
const QString & functionName ,
const QString & file ,
int line ,
QStringList * uninitializedVariables )
{
uninitializedVariables - > clear ( ) ;
// Find document
2009-12-07 10:54:27 +01:00
if ( snapshot . isEmpty ( ) | | functionName . isEmpty ( ) | | file . isEmpty ( ) | | line < 1 )
2009-10-16 16:26:28 +02:00
return 1 ;
2009-12-07 10:54:27 +01:00
const CPlusPlus : : Snapshot : : const_iterator docIt = snapshot . find ( file ) ;
if ( docIt = = snapshot . end ( ) )
2009-10-16 16:26:28 +02:00
return 2 ;
const CPlusPlus : : Document : : Ptr doc = docIt . value ( ) ;
// Look at symbol at line and find its function. Either it is the
// function itself or some expression/variable.
const CPlusPlus : : Symbol * symbolAtLine = doc - > findSymbolAt ( line , 0 ) ;
if ( ! symbolAtLine )
return 4 ;
2009-10-19 10:59:46 +02:00
// First figure out the function to do a safety name check
// and the innermost scope at cursor position
2009-10-16 16:26:28 +02:00
const CPlusPlus : : Function * function = 0 ;
2009-10-19 10:59:46 +02:00
const CPlusPlus : : Scope * innerMostScope = 0 ;
if ( symbolAtLine - > isFunction ( ) ) {
2009-10-16 16:26:28 +02:00
function = symbolAtLine - > asFunction ( ) ;
2009-10-19 10:59:46 +02:00
if ( function - > memberCount ( ) = = 1 ) // Skip over function block
if ( CPlusPlus : : Block * block = function - > memberAt ( 0 ) - > asBlock ( ) )
innerMostScope = block - > members ( ) ;
2009-10-16 16:26:28 +02:00
} else {
2009-10-19 10:59:46 +02:00
if ( const CPlusPlus : : Scope * functionScope = symbolAtLine - > enclosingFunctionScope ( ) ) {
2009-10-16 16:26:28 +02:00
function = functionScope - > owner ( ) - > asFunction ( ) ;
2009-10-19 10:59:46 +02:00
innerMostScope = symbolAtLine - > isBlock ( ) ?
symbolAtLine - > asBlock ( ) - > members ( ) :
symbolAtLine - > enclosingBlockScope ( ) ;
}
2009-10-16 16:26:28 +02:00
}
2009-10-19 10:59:46 +02:00
if ( ! function | | ! innerMostScope )
2009-10-16 16:26:28 +02:00
return 7 ;
// Compare function names with a bit off fuzz,
// skipping modules from a CDB symbol "lib!foo" or namespaces
// that the code model does not show at this point
CPlusPlus : : Overview overview ;
const QString name = overview . prettyName ( function - > name ( ) ) ;
if ( ! functionName . endsWith ( name ) )
return 11 ;
if ( functionName . size ( ) > name . size ( ) ) {
const char previousChar = functionName . at ( functionName . size ( ) - name . size ( ) - 1 ) . toLatin1 ( ) ;
if ( previousChar ! = ' : ' & & previousChar ! = ' ! ' )
return 11 ;
}
2009-10-19 10:59:46 +02:00
// Starting from the innermost block scope, collect declarations.
2009-10-16 16:26:28 +02:00
SeenHash seenHash ;
blockRecursion ( overview , innerMostScope , line , uninitializedVariables , & seenHash ) ;
return 0 ;
}
bool getUninitializedVariables ( const CPlusPlus : : Snapshot & snapshot ,
const QString & function ,
const QString & file ,
int line ,
QStringList * uninitializedVariables )
{
const int rc = getUninitializedVariablesI ( snapshot , function , file , line , uninitializedVariables ) ;
if ( debug ) {
QString msg ;
QTextStream str ( & msg ) ;
str < < " getUninitializedVariables() " < < function < < ' ' < < file < < ' : ' < < line
< < " returns (int) " < < rc < < " ' "
< < uninitializedVariables - > join ( QString ( QLatin1Char ( ' , ' ) ) ) < < ' \' ' ;
if ( rc )
2009-12-07 10:54:27 +01:00
str < < " of " < < snapshot . size ( ) < < " documents " ;
2009-10-16 16:26:28 +02:00
qDebug ( ) < < msg ;
}
return rc = = 0 ;
}
2009-03-25 13:42:47 +01:00
QString gdbQuoteTypes ( const QString & type )
{
// gdb does not understand sizeof(Core::IFile*).
// "sizeof('Core::IFile*')" is also not acceptable,
// it needs to be "sizeof('Core::IFile'*)"
//
// We never will have a perfect solution here (even if we had a full blown
// C++ parser as we do not have information on what is a type and what is
// a variable name. So "a<b>::c" could either be two comparisons of values
// 'a', 'b' and '::c', or a nested type 'c' in a template 'a<b>'. We
// assume here it is the latter.
//return type;
// (*('myns::QPointer<myns::QObject>*'*)0x684060)" is not acceptable
// (*('myns::QPointer<myns::QObject>'**)0x684060)" is acceptable
if ( isPointerType ( type ) )
return gdbQuoteTypes ( stripPointerType ( type ) ) + QLatin1Char ( ' * ' ) ;
QString accu ;
QString result ;
int templateLevel = 0 ;
const QChar colon = QLatin1Char ( ' : ' ) ;
const QChar singleQuote = QLatin1Char ( ' \' ' ) ;
const QChar lessThan = QLatin1Char ( ' < ' ) ;
const QChar greaterThan = QLatin1Char ( ' > ' ) ;
for ( int i = 0 ; i ! = type . size ( ) ; + + i ) {
const QChar c = type . at ( i ) ;
if ( c . isLetterOrNumber ( ) | | c = = QLatin1Char ( ' _ ' ) | | c = = colon | | c = = QLatin1Char ( ' ' ) ) {
accu + = c ;
} else if ( c = = lessThan ) {
+ + templateLevel ;
accu + = c ;
} else if ( c = = greaterThan ) {
- - templateLevel ;
accu + = c ;
} else if ( templateLevel > 0 ) {
accu + = c ;
} else {
if ( accu . contains ( colon ) | | accu . contains ( lessThan ) )
result + = singleQuote + accu + singleQuote ;
else
result + = accu ;
accu . clear ( ) ;
result + = c ;
}
}
if ( accu . contains ( colon ) | | accu . contains ( lessThan ) )
result + = singleQuote + accu + singleQuote ;
else
result + = accu ;
//qDebug() << "GDB_QUOTING" << type << " TO " << result;
return result ;
}
bool extractTemplate ( const QString & type , QString * tmplate , QString * inner )
{
// Input "Template<Inner1,Inner2,...>::Foo" will return "Template::Foo" in
// 'tmplate' and "Inner1@Inner2@..." etc in 'inner'. Result indicates
// whether parsing was successful
2009-07-03 13:56:27 +02:00
// Gdb inserts a blank after each comma which we would like to avoid
tmplate - > clear ( ) ;
inner - > clear ( ) ;
if ( ! type . contains ( QLatin1Char ( ' < ' ) ) )
return false ;
2009-03-25 13:42:47 +01:00
int level = 0 ;
bool skipSpace = false ;
2009-07-03 13:56:27 +02:00
const int size = type . size ( ) ;
2009-03-25 13:42:47 +01:00
2009-07-03 13:56:27 +02:00
for ( int i = 0 ; i ! = size ; + + i ) {
2009-03-25 13:42:47 +01:00
const QChar c = type . at ( i ) ;
2009-07-03 13:56:27 +02:00
const char asciiChar = c . toAscii ( ) ;
switch ( asciiChar ) {
case ' < ' :
2009-03-25 13:42:47 +01:00
* ( level = = 0 ? tmplate : inner ) + = c ;
+ + level ;
2009-07-03 13:56:27 +02:00
break ;
case ' > ' :
2009-03-25 13:42:47 +01:00
- - level ;
* ( level = = 0 ? tmplate : inner ) + = c ;
2009-07-03 13:56:27 +02:00
break ;
case ' , ' :
2009-03-25 13:42:47 +01:00
* inner + = ( level = = 1 ) ? QLatin1Char ( ' @ ' ) : QLatin1Char ( ' , ' ) ;
skipSpace = true ;
2009-07-03 13:56:27 +02:00
break ;
default :
if ( ! skipSpace | | asciiChar ! = ' ' ) {
* ( level = = 0 ? tmplate : inner ) + = c ;
skipSpace = false ;
}
break ;
2009-03-25 13:42:47 +01:00
}
}
* tmplate = tmplate - > trimmed ( ) ;
* tmplate = tmplate - > remove ( QLatin1String ( " <> " ) ) ;
* inner = inner - > trimmed ( ) ;
2009-07-03 13:56:27 +02:00
// qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner << " FROM " << type;
2009-03-25 13:42:47 +01:00
return ! inner - > isEmpty ( ) ;
}
QString extractTypeFromPTypeOutput ( const QString & str )
{
int pos0 = str . indexOf ( QLatin1Char ( ' = ' ) ) ;
int pos1 = str . indexOf ( QLatin1Char ( ' { ' ) ) ;
int pos2 = str . lastIndexOf ( QLatin1Char ( ' } ' ) ) ;
QString res = str ;
if ( pos0 ! = - 1 & & pos1 ! = - 1 & & pos2 ! = - 1 )
res = str . mid ( pos0 + 2 , pos1 - 1 - pos0 )
+ QLatin1String ( " ... " ) + str . right ( str . size ( ) - pos2 ) ;
return res . simplified ( ) ;
}
2009-07-03 13:25:51 +02:00
bool isIntType ( const QString & type )
2009-03-25 13:42:47 +01:00
{
static const QStringList types = QStringList ( )
< < QLatin1String ( " char " ) < < QLatin1String ( " int " ) < < QLatin1String ( " short " )
2009-07-03 13:25:51 +02:00
< < QLatin1String ( " long " ) < < QLatin1String ( " bool " )
< < QLatin1String ( " signed char " ) < < QLatin1String ( " unsigned " )
2009-09-16 12:20:16 +02:00
< < QLatin1String ( " unsigned char " ) < < QLatin1String ( " unsigned long " )
2009-11-25 16:32:44 +01:00
< < QLatin1String ( " long long " ) < < QLatin1String ( " unsigned long long " )
< < QLatin1String ( " qint16 " ) < < QLatin1String ( " quint16 " )
< < QLatin1String ( " qint32 " ) < < QLatin1String ( " quint32 " )
< < QLatin1String ( " qint64 " ) < < QLatin1String ( " quint64 " ) ;
return type . endsWith ( QLatin1String ( " int " ) )
| | type . endsWith ( QLatin1String ( " int64 " ) )
| | types . contains ( type ) ;
2009-03-25 13:42:47 +01:00
}
2009-09-15 18:21:40 +02:00
bool isSymbianIntType ( const QString & type )
{
static const QStringList types = QStringList ( )
< < QLatin1String ( " TInt " ) < < QLatin1String ( " TBool " ) ;
return types . contains ( type ) ;
}
2009-07-03 13:25:51 +02:00
bool isIntOrFloatType ( const QString & type )
{
static const QStringList types = QStringList ( )
< < QLatin1String ( " float " ) < < QLatin1String ( " double " ) ;
return isIntType ( type ) | | types . contains ( type ) ;
}
2009-07-14 11:21:52 +02:00
GuessChildrenResult guessChildren ( const QString & type )
{
if ( isIntOrFloatType ( type ) )
return HasNoChildren ;
2009-12-07 12:06:01 +01:00
if ( isCharPointerType ( type ) )
return HasNoChildren ;
2009-07-14 11:21:52 +02:00
if ( isPointerType ( type ) )
return HasChildren ;
if ( type . endsWith ( QLatin1String ( " QString " ) ) )
return HasNoChildren ;
return HasPossiblyChildren ;
}
2009-10-09 14:11:05 +02:00
QString sizeofTypeExpression ( const QString & type , QtDumperHelper : : Debugger debugger )
2009-03-25 13:42:47 +01:00
{
if ( type . endsWith ( QLatin1Char ( ' * ' ) ) )
return QLatin1String ( " sizeof(void*) " ) ;
2009-10-09 14:11:05 +02:00
if ( debugger ! = QtDumperHelper : : GdbDebugger | | type . endsWith ( QLatin1Char ( ' > ' ) ) )
2009-03-25 13:42:47 +01:00
return QLatin1String ( " sizeof( " ) + type + QLatin1Char ( ' ) ' ) ;
return QLatin1String ( " sizeof( " ) + gdbQuoteTypes ( type ) + QLatin1Char ( ' ) ' ) ;
}
2009-04-29 14:15:09 +02:00
// Utilities to decode string data returned by the dumper helpers.
2009-05-08 15:37:41 +02:00
QString quoteUnprintableLatin1 ( const QByteArray & ba )
2009-04-29 14:15:09 +02:00
{
QString res ;
char buf [ 10 ] ;
for ( int i = 0 , n = ba . size ( ) ; i ! = n ; + + i ) {
const unsigned char c = ba . at ( i ) ;
if ( isprint ( c ) ) {
res + = c ;
} else {
qsnprintf ( buf , sizeof ( buf ) - 1 , " \\ %x " , int ( c ) ) ;
res + = buf ;
}
}
return res ;
}
2009-04-29 18:03:35 +02:00
QString decodeData ( const QByteArray & ba , int encoding )
2009-04-29 14:15:09 +02:00
{
switch ( encoding ) {
case 0 : // unencoded 8 bit data
2009-04-29 18:03:35 +02:00
return quoteUnprintableLatin1 ( ba ) ;
2009-04-29 14:15:09 +02:00
case 1 : { // base64 encoded 8 bit data, used for QByteArray
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
QString rc = doubleQuote ;
2009-04-29 18:03:35 +02:00
rc + = quoteUnprintableLatin1 ( QByteArray : : fromBase64 ( ba ) ) ;
2009-04-29 14:15:09 +02:00
rc + = doubleQuote ;
return rc ;
}
case 2 : { // base64 encoded 16 bit data, used for QString
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
2009-05-04 12:12:45 +02:00
const QByteArray decodedBa = QByteArray : : fromBase64 ( ba ) ;
2009-04-29 14:15:09 +02:00
QString rc = doubleQuote ;
2009-10-12 09:30:28 +02:00
rc + = QString : : fromUtf16 ( reinterpret_cast < const ushort * >
( decodedBa . data ( ) ) , decodedBa . size ( ) / 2 ) ;
2009-04-29 14:15:09 +02:00
rc + = doubleQuote ;
return rc ;
}
case 3 : { // base64 encoded 32 bit data
2009-05-04 12:12:45 +02:00
const QByteArray decodedBa = QByteArray : : fromBase64 ( ba ) ;
2009-04-29 14:15:09 +02:00
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
QString rc = doubleQuote ;
2009-10-12 09:30:28 +02:00
rc + = QString : : fromUcs4 ( reinterpret_cast < const uint * >
( decodedBa . data ( ) ) , decodedBa . size ( ) / 4 ) ;
2009-04-29 14:15:09 +02:00
rc + = doubleQuote ;
return rc ;
}
case 4 : { // base64 encoded 16 bit data, without quotes (see 2)
2009-05-04 12:12:45 +02:00
const QByteArray decodedBa = QByteArray : : fromBase64 ( ba ) ;
2009-10-12 09:30:28 +02:00
return QString : : fromUtf16 ( reinterpret_cast < const ushort * >
( decodedBa . data ( ) ) , decodedBa . size ( ) / 2 ) ;
2009-04-29 14:15:09 +02:00
}
2009-07-01 14:15:10 +02:00
case 5 : { // base64 encoded 8 bit data, without quotes (see 1)
return quoteUnprintableLatin1 ( QByteArray : : fromBase64 ( ba ) ) ;
}
2010-03-11 18:55:52 +01:00
case 6 : { // %02x encoded 8 bit Latin1 data
2009-10-21 16:41:18 +02:00
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
const QByteArray decodedBa = QByteArray : : fromHex ( ba ) ;
//qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n";
return doubleQuote + QString : : fromLatin1 ( decodedBa ) + doubleQuote ;
}
2010-03-05 11:10:58 +01:00
case 7 : { // %04x encoded 16 bit data, Little Endian
2009-10-15 13:57:51 +02:00
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
2009-10-12 09:30:28 +02:00
const QByteArray decodedBa = QByteArray : : fromHex ( ba ) ;
2009-10-12 15:22:11 +02:00
//qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n";
2009-10-15 13:57:51 +02:00
return doubleQuote + QString : : fromUtf16 ( reinterpret_cast < const ushort * >
( decodedBa . data ( ) ) , decodedBa . size ( ) / 2 ) + doubleQuote ;
2009-10-12 09:30:28 +02:00
}
2010-03-05 11:10:58 +01:00
case 8 : { // %08x encoded 32 bit data, Little Endian
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
const QByteArray decodedBa = QByteArray : : fromHex ( ba ) ;
//qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n";
return doubleQuote + QString : : fromUcs4 ( reinterpret_cast < const uint * >
( decodedBa . data ( ) ) , decodedBa . size ( ) / 4 ) + doubleQuote ;
}
2010-03-11 18:55:52 +01:00
case 9 : { // %02x encoded 8 bit Utf-8 data
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
const QByteArray decodedBa = QByteArray : : fromHex ( ba ) ;
//qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n";
return doubleQuote + QString : : fromUtf8 ( decodedBa ) + doubleQuote ;
}
case 10 : { // %08x encoded 32 bit data, Big Endian
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
QByteArray decodedBa = QByteArray : : fromHex ( ba ) ;
for ( int i = 0 ; i < decodedBa . size ( ) ; i + = 4 ) {
char c = decodedBa . at ( i ) ;
decodedBa [ i ] = decodedBa . at ( i + 3 ) ;
decodedBa [ i + 3 ] = c ;
c = decodedBa . at ( i + 1 ) ;
decodedBa [ i + 1 ] = decodedBa . at ( i + 2 ) ;
decodedBa [ i + 2 ] = c ;
}
//qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n";
return doubleQuote + QString : : fromUcs4 ( reinterpret_cast < const uint * >
( decodedBa . data ( ) ) , decodedBa . size ( ) / 4 ) + doubleQuote ;
}
case 11 : { // %02x encoded 16 bit data, Big Endian
const QChar doubleQuote ( QLatin1Char ( ' " ' ) ) ;
QByteArray decodedBa = QByteArray : : fromHex ( ba ) ;
for ( int i = 0 ; i < decodedBa . size ( ) ; i + = 2 ) {
char c = decodedBa . at ( i ) ;
decodedBa [ i ] = decodedBa . at ( i + 1 ) ;
decodedBa [ i + 1 ] = c ;
}
//qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n";
return doubleQuote + QString : : fromUcs4 ( reinterpret_cast < const uint * >
( decodedBa . data ( ) ) , decodedBa . size ( ) / 4 ) + doubleQuote ;
}
2009-04-29 14:15:09 +02:00
}
2009-10-21 16:41:18 +02:00
qDebug ( ) < < " ENCODING ERROR: " < < encoding ;
2009-04-29 14:15:09 +02:00
return QCoreApplication : : translate ( " Debugger " , " <Encoding error> " ) ;
}
2009-05-14 14:29:37 +02:00
// Editor tooltip support
bool isCppEditor ( Core : : IEditor * editor )
{
static QStringList cppMimeTypes ;
if ( cppMimeTypes . empty ( ) ) {
cppMimeTypes < < QLatin1String ( CppTools : : Constants : : C_SOURCE_MIMETYPE )
< < QLatin1String ( CppTools : : Constants : : CPP_SOURCE_MIMETYPE )
< < QLatin1String ( CppTools : : Constants : : CPP_HEADER_MIMETYPE )
< < QLatin1String ( CppTools : : Constants : : OBJECTIVE_CPP_SOURCE_MIMETYPE ) ;
}
if ( const Core : : IFile * file = editor - > file ( ) )
return cppMimeTypes . contains ( file - > mimeType ( ) ) ;
return false ;
}
// Find the function the cursor is in to use a scope.
2009-07-03 13:56:27 +02:00
2009-05-14 14:29:37 +02:00
// Return the Cpp expression, and, if desired, the function
QString cppExpressionAt ( TextEditor : : ITextEditor * editor , int pos ,
int * line , int * column , QString * function /* = 0 */ )
{
* line = * column = 0 ;
if ( function )
function - > clear ( ) ;
const QPlainTextEdit * plaintext = qobject_cast < QPlainTextEdit * > ( editor - > widget ( ) ) ;
if ( ! plaintext )
return QString ( ) ;
QString expr = plaintext - > textCursor ( ) . selectedText ( ) ;
if ( expr . isEmpty ( ) ) {
QTextCursor tc ( plaintext - > document ( ) ) ;
tc . setPosition ( pos ) ;
const QChar ch = editor - > characterAt ( pos ) ;
if ( ch . isLetterOrNumber ( ) | | ch = = QLatin1Char ( ' _ ' ) )
tc . movePosition ( QTextCursor : : EndOfWord ) ;
// Fetch the expression's code.
CPlusPlus : : ExpressionUnderCursor expressionUnderCursor ;
expr = expressionUnderCursor ( tc ) ;
* column = tc . columnNumber ( ) ;
* line = tc . blockNumber ( ) ;
} else {
const QTextCursor tc = plaintext - > textCursor ( ) ;
* column = tc . columnNumber ( ) ;
* line = tc . blockNumber ( ) ;
2009-07-03 13:56:27 +02:00
}
2009-05-14 14:29:37 +02:00
if ( function & & ! expr . isEmpty ( ) )
if ( const Core : : IFile * file = editor - > file ( ) )
if ( CppTools : : CppModelManagerInterface * modelManager = ExtensionSystem : : PluginManager : : instance ( ) - > getObject < CppTools : : CppModelManagerInterface > ( ) )
* function = CppTools : : AbstractEditorSupport : : functionAt ( modelManager , file - > fileName ( ) , * line , * column ) ;
return expr ;
}
2009-04-29 14:15:09 +02:00
// ----------------- QtDumperHelper::TypeData
QtDumperHelper : : TypeData : : TypeData ( ) :
type ( UnknownType ) ,
isTemplate ( false )
{
}
void QtDumperHelper : : TypeData : : clear ( )
{
isTemplate = false ;
type = UnknownType ;
tmplate . clear ( ) ;
inner . clear ( ) ;
}
// ----------------- QtDumperHelper
QtDumperHelper : : QtDumperHelper ( ) :
2009-07-07 16:00:45 +02:00
m_qtVersion ( 0 ) ,
m_dumperVersion ( 1.0 )
2009-04-29 14:15:09 +02:00
{
2009-07-02 16:38:15 +02:00
qFill ( m_specialSizes , m_specialSizes + SpecialSizeCount , 0 ) ;
2009-07-07 16:00:45 +02:00
setQClassPrefixes ( QString ( ) ) ;
2009-04-29 14:15:09 +02:00
}
void QtDumperHelper : : clear ( )
{
m_nameTypeMap . clear ( ) ;
m_qtVersion = 0 ;
2009-07-07 16:00:45 +02:00
m_dumperVersion = 1.0 ;
2009-04-29 14:15:09 +02:00
m_qtNamespace . clear ( ) ;
2009-04-29 16:52:14 +02:00
m_sizeCache . clear ( ) ;
2009-07-02 16:38:15 +02:00
qFill ( m_specialSizes , m_specialSizes + SpecialSizeCount , 0 ) ;
m_expressionCache . clear ( ) ;
2009-07-07 16:00:45 +02:00
setQClassPrefixes ( QString ( ) ) ;
}
QString QtDumperHelper : : msgDumperOutdated ( double requiredVersion , double currentVersion )
{
return QCoreApplication : : translate ( " QtDumperHelper " ,
2009-10-26 19:59:16 +01:00
" Found an outdated version of the debugging helper library (%1); version %2 is required. " ) .
2009-07-07 16:00:45 +02:00
arg ( currentVersion ) . arg ( requiredVersion ) ;
2009-04-29 14:15:09 +02:00
}
static inline void formatQtVersion ( int v , QTextStream & str )
{
str < < ( ( v > > 16 ) & 0xFF ) < < ' . ' < < ( ( v > > 8 ) & 0xFF ) < < ' . ' < < ( v & 0xFF ) ;
}
QString QtDumperHelper : : toString ( bool debug ) const
{
if ( debug ) {
QString rc ;
QTextStream str ( & rc ) ;
str < < " version= " ;
formatQtVersion ( m_qtVersion , str ) ;
2009-07-06 17:36:50 +02:00
str < < " dumperversion=' " < < m_dumperVersion < < " ' namespace=' " < < m_qtNamespace < < " ', " < < m_nameTypeMap . size ( ) < < " known types <type enum>: " ;
2009-04-29 14:15:09 +02:00
const NameTypeMap : : const_iterator cend = m_nameTypeMap . constEnd ( ) ;
for ( NameTypeMap : : const_iterator it = m_nameTypeMap . constBegin ( ) ; it ! = cend ; + + it ) {
str < < " ,[ " < < it . key ( ) < < ' , ' < < it . value ( ) < < ' ] ' ;
}
2009-07-02 16:38:15 +02:00
str < < " \n Special size: " ;
for ( int i = 0 ; i < SpecialSizeCount ; i + + )
str < < ' ' < < m_specialSizes [ i ] ;
str < < " \n Size cache: " ;
2009-04-29 16:52:14 +02:00
const SizeCache : : const_iterator scend = m_sizeCache . constEnd ( ) ;
for ( SizeCache : : const_iterator it = m_sizeCache . constBegin ( ) ; it ! = scend ; + + it ) {
2009-10-02 15:17:50 +02:00
str < < ' ' < < it . key ( ) < < ' = ' < < it . value ( ) < < ' \n ' ;
2009-04-29 16:52:14 +02:00
}
2009-09-18 16:55:17 +02:00
str < < " \n Expression cache: ( " < < m_expressionCache . size ( ) < < " ) \n " ;
const QMap < QString , QString > : : const_iterator excend = m_expressionCache . constEnd ( ) ;
for ( QMap < QString , QString > : : const_iterator it = m_expressionCache . constBegin ( ) ; it ! = excend ; + + it )
str < < " " < < it . key ( ) < < ' ' < < it . value ( ) < < ' \n ' ;
2009-04-29 14:15:09 +02:00
return rc ;
}
const QString nameSpace = m_qtNamespace . isEmpty ( ) ? QCoreApplication : : translate ( " QtDumperHelper " , " <none> " ) : m_qtNamespace ;
return QCoreApplication : : translate ( " QtDumperHelper " ,
2009-07-06 17:36:50 +02:00
" %n known types, Qt version: %1, Qt namespace: %2 Dumper version: %3 " ,
2009-04-29 14:15:09 +02:00
0 , QCoreApplication : : CodecForTr ,
2009-07-07 16:00:45 +02:00
m_nameTypeMap . size ( ) ) . arg ( qtVersionString ( ) , nameSpace ) . arg ( m_dumperVersion ) ;
2009-04-29 14:15:09 +02:00
}
QtDumperHelper : : Type QtDumperHelper : : simpleType ( const QString & simpleType ) const
{
return m_nameTypeMap . value ( simpleType , UnknownType ) ;
}
int QtDumperHelper : : qtVersion ( ) const
{
return m_qtVersion ;
}
QString QtDumperHelper : : qtNamespace ( ) const
{
return m_qtNamespace ;
}
int QtDumperHelper : : typeCount ( ) const
{
return m_nameTypeMap . size ( ) ;
}
// Look up unnamespaced 'std' types.
static inline QtDumperHelper : : Type stdType ( const QString & s )
{
if ( s = = QLatin1String ( " vector " ) )
return QtDumperHelper : : StdVectorType ;
if ( s = = QLatin1String ( " deque " ) )
return QtDumperHelper : : StdDequeType ;
if ( s = = QLatin1String ( " set " ) )
return QtDumperHelper : : StdSetType ;
if ( s = = QLatin1String ( " stack " ) )
return QtDumperHelper : : StdStackType ;
if ( s = = QLatin1String ( " map " ) )
return QtDumperHelper : : StdMapType ;
if ( s = = QLatin1String ( " basic_string " ) )
return QtDumperHelper : : StdStringType ;
return QtDumperHelper : : UnknownType ;
}
QtDumperHelper : : Type QtDumperHelper : : specialType ( QString s )
{
// Std classes.
if ( s . startsWith ( QLatin1String ( " std:: " ) ) )
return stdType ( s . mid ( 5 ) ) ;
// Strip namespace
2009-06-03 12:46:55 +02:00
// FIXME: that's not a good idea as it makes all namespaces equal.
2009-04-29 14:15:09 +02:00
const int namespaceIndex = s . lastIndexOf ( QLatin1String ( " :: " ) ) ;
if ( namespaceIndex = = - 1 ) {
// None ... check for std..
const Type sType = stdType ( s ) ;
if ( sType ! = UnknownType )
return sType ;
} else {
2009-06-03 12:46:55 +02:00
s = s . mid ( namespaceIndex + 2 ) ;
2009-04-29 14:15:09 +02:00
}
2009-06-03 12:46:55 +02:00
if ( s = = QLatin1String ( " QAbstractItem " ) )
return QAbstractItemType ;
2009-04-29 14:15:09 +02:00
if ( s = = QLatin1String ( " QMap " ) )
return QMapType ;
if ( s = = QLatin1String ( " QMapNode " ) )
return QMapNodeType ;
2009-08-28 09:44:11 +02:00
if ( s = = QLatin1String ( " QMultiMap " ) )
return QMultiMapType ;
if ( s = = QLatin1String ( " QObject " ) )
return QObjectType ;
if ( s = = QLatin1String ( " QObjectSignal " ) )
return QObjectSignalType ;
if ( s = = QLatin1String ( " QObjectSlot " ) )
return QObjectSlotType ;
if ( s = = QLatin1String ( " QStack " ) )
return QStackType ;
if ( s = = QLatin1String ( " QVector " ) )
return QVectorType ;
if ( s = = QLatin1String ( " QWidget " ) )
return QWidgetType ;
2009-04-29 14:15:09 +02:00
return UnknownType ;
}
QString QtDumperHelper : : qtVersionString ( ) const
{
QString rc ;
QTextStream str ( & rc ) ;
formatQtVersion ( m_qtVersion , str ) ;
return rc ;
}
// Parse a list of types.
2009-10-14 14:18:18 +02:00
void QtDumperHelper : : parseQueryTypes ( const QStringList & l , Debugger /* debugger */ )
2009-04-29 14:15:09 +02:00
{
m_nameTypeMap . clear ( ) ;
const int count = l . count ( ) ;
for ( int i = 0 ; i < count ; i + + ) {
const Type t = specialType ( l . at ( i ) ) ;
2009-10-14 14:18:18 +02:00
m_nameTypeMap . insert ( l . at ( i ) , t ! = UnknownType ? t : SupportedType ) ;
2009-04-29 14:15:09 +02:00
}
}
2009-07-07 16:00:45 +02:00
static inline QString qClassName ( const QString & qtNamespace , const char * className )
{
if ( qtNamespace . isEmpty ( ) )
return QString : : fromAscii ( className ) ;
QString rc = qtNamespace ;
rc + = QLatin1String ( " :: " ) ;
rc + = QString : : fromAscii ( className ) ;
return rc ;
}
void QtDumperHelper : : setQClassPrefixes ( const QString & qNamespace )
{
// Prefixes with namespaces
m_qPointerPrefix = qClassName ( qNamespace , " QPointer " ) ;
m_qSharedPointerPrefix = qClassName ( qNamespace , " QSharedPointer " ) ;
m_qSharedDataPointerPrefix = qClassName ( qNamespace , " QSharedDataPointer " ) ;
m_qWeakPointerPrefix = qClassName ( qNamespace , " QWeakPointer " ) ;
2009-09-21 14:55:39 +02:00
m_qListPrefix = qClassName ( qNamespace , " QList " ) ;
m_qLinkedListPrefix = qClassName ( qNamespace , " QLinkedList " ) ;
m_qVectorPrefix = qClassName ( qNamespace , " QVector " ) ;
2009-10-02 15:17:50 +02:00
m_qQueuePrefix = qClassName ( qNamespace , " QQueue " ) ;
2009-07-07 16:00:45 +02:00
}
2009-09-18 16:55:17 +02:00
static inline double getDumperVersion ( const GdbMi & contents )
2009-04-29 14:15:09 +02:00
{
2009-09-18 16:55:17 +02:00
const GdbMi dumperVersionG = contents . findChild ( " dumperversion " ) ;
if ( dumperVersionG . type ( ) ! = GdbMi : : Invalid ) {
2009-07-07 16:00:45 +02:00
bool ok ;
2009-09-18 16:55:17 +02:00
const double v = QString : : fromAscii ( dumperVersionG . data ( ) ) . toDouble ( & ok ) ;
2009-07-07 16:00:45 +02:00
if ( ok )
2009-09-18 16:55:17 +02:00
return v ;
2009-07-07 16:00:45 +02:00
}
2009-09-18 16:55:17 +02:00
return 1.0 ;
}
bool QtDumperHelper : : parseQuery ( const GdbMi & contents , Debugger debugger )
{
clear ( ) ;
if ( debug > 1 )
qDebug ( ) < < " parseQuery " < < contents . toString ( true , 2 ) ;
// Common info, dumper version, etc
m_qtNamespace = QLatin1String ( contents . findChild ( " namespace " ) . data ( ) ) ;
int qtv = 0 ;
const GdbMi qtversion = contents . findChild ( " qtversion " ) ;
if ( qtversion . children ( ) . size ( ) = = 3 ) {
qtv = ( qtversion . childAt ( 0 ) . data ( ) . toInt ( ) < < 16 )
+ ( qtversion . childAt ( 1 ) . data ( ) . toInt ( ) < < 8 )
+ qtversion . childAt ( 2 ) . data ( ) . toInt ( ) ;
}
m_qtVersion = qtv ;
// Get list of helpers
QStringList availableSimpleDebuggingHelpers ;
foreach ( const GdbMi & item , contents . findChild ( " dumpers " ) . children ( ) )
availableSimpleDebuggingHelpers . append ( QLatin1String ( item . data ( ) ) ) ;
parseQueryTypes ( availableSimpleDebuggingHelpers , debugger ) ;
m_dumperVersion = getDumperVersion ( contents ) ;
// Parse sizes
foreach ( const GdbMi & sizesList , contents . findChild ( " sizes " ) . children ( ) ) {
const int childCount = sizesList . childCount ( ) ;
if ( childCount > 1 ) {
const int size = sizesList . childAt ( 0 ) . data ( ) . toInt ( ) ;
for ( int c = 1 ; c < childCount ; c + + )
addSize ( QLatin1String ( sizesList . childAt ( c ) . data ( ) ) , size ) ;
}
}
// Parse expressions
foreach ( const GdbMi & exprList , contents . findChild ( " expressions " ) . children ( ) )
if ( exprList . childCount ( ) = = 2 )
m_expressionCache . insert ( QLatin1String ( exprList . childAt ( 0 ) . data ( ) ) ,
QLatin1String ( exprList . childAt ( 1 ) . data ( ) ) ) ;
2009-04-29 14:15:09 +02:00
return true ;
}
2009-09-18 16:55:17 +02:00
// parse a query
bool QtDumperHelper : : parseQuery ( const char * data , Debugger debugger )
2009-07-07 16:00:45 +02:00
{
2009-11-30 15:17:34 +01:00
GdbMi root ;
root . fromStringMultiple ( QByteArray ( data ) ) ;
2009-09-18 16:55:17 +02:00
if ( ! root . isValid ( ) )
return false ;
return parseQuery ( root , debugger ) ;
2009-07-07 16:00:45 +02:00
}
2009-04-29 16:52:14 +02:00
void QtDumperHelper : : addSize ( const QString & name , int size )
{
// Special interest cases
2009-07-02 16:38:15 +02:00
if ( name = = QLatin1String ( " char* " ) ) {
m_specialSizes [ PointerSize ] = size ;
return ;
}
const SpecialSizeType st = specialSizeType ( name ) ;
if ( st ! = SpecialSizeCount ) {
m_specialSizes [ st ] = size ;
return ;
}
2009-04-29 16:52:14 +02:00
do {
2009-07-03 13:56:27 +02:00
// CDB helpers
2009-04-29 16:52:14 +02:00
if ( name = = QLatin1String ( " std::string " ) ) {
2009-07-03 13:56:27 +02:00
m_sizeCache . insert ( QLatin1String ( " std::basic_string<char,std::char_traits<char>,std::allocator<char> > " ) , size ) ;
m_sizeCache . insert ( QLatin1String ( " basic_string<char,char_traits<char>,allocator<char> > " ) , size ) ;
2009-04-29 16:52:14 +02:00
break ;
}
if ( name = = QLatin1String ( " std::wstring " ) ) {
2009-07-03 13:56:27 +02:00
m_sizeCache . insert ( QLatin1String ( " basic_string<unsigned short,char_traits<unsignedshort>,allocator<unsignedshort> > " ) , size ) ;
m_sizeCache . insert ( QLatin1String ( " std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> > " ) , size ) ;
2009-04-29 16:52:14 +02:00
break ;
}
} while ( false ) ;
m_sizeCache . insert ( name , size ) ;
}
2009-04-29 14:15:09 +02:00
QtDumperHelper : : Type QtDumperHelper : : type ( const QString & typeName ) const
{
const QtDumperHelper : : TypeData td = typeData ( typeName ) ;
return td . type ;
}
QtDumperHelper : : TypeData QtDumperHelper : : typeData ( const QString & typeName ) const
{
TypeData td ;
td . type = UnknownType ;
const Type st = simpleType ( typeName ) ;
if ( st ! = UnknownType ) {
td . isTemplate = false ;
2009-06-03 12:46:55 +02:00
td . type = st ;
2009-04-29 14:15:09 +02:00
return td ;
}
// Try template
td . isTemplate = extractTemplate ( typeName , & td . tmplate , & td . inner ) ;
if ( ! td . isTemplate )
return td ;
// Check the template type QMap<X,Y> -> 'QMap'
td . type = simpleType ( td . tmplate ) ;
return td ;
}
2009-04-29 16:52:14 +02:00
// Format an expression to have the debugger query the
// size. Use size cache if possible
QString QtDumperHelper : : evaluationSizeofTypeExpression ( const QString & typeName ,
2009-10-09 14:11:05 +02:00
Debugger debugger ) const
2009-04-29 16:52:14 +02:00
{
2009-07-02 16:38:15 +02:00
// Look up special size types
const SpecialSizeType st = specialSizeType ( typeName ) ;
if ( st ! = SpecialSizeCount ) {
if ( const int size = m_specialSizes [ st ] )
return QString : : number ( size ) ;
}
// Look up size cache
2009-04-29 16:52:14 +02:00
const SizeCache : : const_iterator sit = m_sizeCache . constFind ( typeName ) ;
if ( sit ! = m_sizeCache . constEnd ( ) )
return QString : : number ( sit . value ( ) ) ;
// Finally have the debugger evaluate
2009-10-09 14:11:05 +02:00
return sizeofTypeExpression ( typeName , debugger ) ;
2009-04-29 16:52:14 +02:00
}
2009-07-07 16:00:45 +02:00
QtDumperHelper : : SpecialSizeType QtDumperHelper : : specialSizeType ( const QString & typeName ) const
2009-07-02 16:38:15 +02:00
{
if ( isPointerType ( typeName ) )
return PointerSize ;
static const QString intType = QLatin1String ( " int " ) ;
static const QString stdAllocatorPrefix = QLatin1String ( " std::allocator " ) ;
if ( typeName = = intType )
return IntSize ;
if ( typeName . startsWith ( stdAllocatorPrefix ) )
return StdAllocatorSize ;
2009-07-07 16:00:45 +02:00
if ( typeName . startsWith ( m_qPointerPrefix ) )
2009-07-02 16:38:15 +02:00
return QPointerSize ;
2009-07-07 16:00:45 +02:00
if ( typeName . startsWith ( m_qSharedPointerPrefix ) )
2009-07-02 16:38:15 +02:00
return QSharedPointerSize ;
2009-07-07 16:00:45 +02:00
if ( typeName . startsWith ( m_qSharedDataPointerPrefix ) )
2009-07-02 16:38:15 +02:00
return QSharedDataPointerSize ;
2009-07-07 16:00:45 +02:00
if ( typeName . startsWith ( m_qWeakPointerPrefix ) )
2009-07-02 16:38:15 +02:00
return QWeakPointerSize ;
2009-09-21 14:55:39 +02:00
if ( typeName . startsWith ( m_qListPrefix ) )
return QListSize ;
if ( typeName . startsWith ( m_qLinkedListPrefix ) )
return QLinkedListSize ;
if ( typeName . startsWith ( m_qVectorPrefix ) )
return QVectorSize ;
if ( typeName . startsWith ( m_qQueuePrefix ) )
return QQueueSize ;
2009-07-02 16:38:15 +02:00
return SpecialSizeCount ;
}
static inline bool isInteger ( const QString & n )
{
const int size = n . size ( ) ;
if ( ! size )
return false ;
for ( int i = 0 ; i < size ; i + + )
if ( ! n . at ( i ) . isDigit ( ) )
return false ;
return true ;
}
2009-04-29 14:15:09 +02:00
void QtDumperHelper : : evaluationParameters ( const WatchData & data ,
const TypeData & td ,
2009-04-29 16:52:14 +02:00
Debugger debugger ,
2009-04-29 14:15:09 +02:00
QByteArray * inBuffer ,
QStringList * extraArgsIn ) const
{
enum { maxExtraArgCount = 4 } ;
QStringList & extraArgs = * extraArgsIn ;
// See extractTemplate for parameters
QStringList inners = td . inner . split ( QLatin1Char ( ' @ ' ) ) ;
if ( inners . at ( 0 ) . isEmpty ( ) )
inners . clear ( ) ;
for ( int i = 0 ; i ! = inners . size ( ) ; + + i )
inners [ i ] = inners [ i ] . simplified ( ) ;
QString outertype = td . isTemplate ? td . tmplate : data . type ;
// adjust the data extract
if ( outertype = = m_qtNamespace + QLatin1String ( " QWidget " ) )
outertype = m_qtNamespace + QLatin1String ( " QObject " ) ;
2009-06-03 12:46:55 +02:00
QString inner = td . inner ;
2009-04-29 14:15:09 +02:00
extraArgs . clear ( ) ;
if ( ! inners . empty ( ) ) {
// "generic" template dumpers: passing sizeof(argument)
// gives already most information the dumpers need
const int count = qMin ( int ( maxExtraArgCount ) , inners . size ( ) ) ;
for ( int i = 0 ; i < count ; i + + )
2009-04-29 16:52:14 +02:00
extraArgs . push_back ( evaluationSizeofTypeExpression ( inners . at ( i ) , debugger ) ) ;
2009-04-29 14:15:09 +02:00
}
int extraArgCount = extraArgs . size ( ) ;
// Pad with zeros
const QString zero = QString ( QLatin1Char ( ' 0 ' ) ) ;
const int extraPad = maxExtraArgCount - extraArgCount ;
for ( int i = 0 ; i < extraPad ; i + + )
extraArgs . push_back ( zero ) ;
// in rare cases we need more or less:
switch ( td . type ) {
2009-06-03 12:46:55 +02:00
case QAbstractItemType :
inner = data . addr . mid ( 1 ) ;
break ;
2009-04-29 14:15:09 +02:00
case QObjectSlotType :
case QObjectSignalType : {
// we need the number out of something like
// iname="local.ob.slots.2" // ".deleteLater()"?
const int pos = data . iname . lastIndexOf ( ' . ' ) ;
const QString slotNumber = data . iname . mid ( pos + 1 ) ;
QTC_ASSERT ( slotNumber . toInt ( ) ! = - 1 , /**/ ) ;
extraArgs [ 0 ] = slotNumber ;
}
break ;
case QMapType :
case QMultiMapType : {
QString nodetype ;
2009-07-14 10:07:15 +02:00
if ( m_qtVersion > = 0x040500 ) {
2009-04-29 14:15:09 +02:00
nodetype = m_qtNamespace + QLatin1String ( " QMapNode " ) ;
nodetype + = data . type . mid ( outertype . size ( ) ) ;
2009-04-22 17:28:26 +02:00
} else {
2009-04-29 14:15:09 +02:00
// FIXME: doesn't work for QMultiMap
nodetype = data . type + QLatin1String ( " ::Node " ) ;
2009-04-22 17:28:26 +02:00
}
2009-04-29 14:15:09 +02:00
//qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype
// << "QT VERSION" << m_qtVersion << ((4 << 16) + (5 << 8) + 0);
2009-04-29 16:52:14 +02:00
extraArgs [ 2 ] = evaluationSizeofTypeExpression ( nodetype , debugger ) ;
2009-10-09 14:11:05 +02:00
extraArgs [ 3 ] = qMapNodeValueOffsetExpression ( nodetype , data . addr , debugger ) ;
2009-04-22 17:28:26 +02:00
}
2009-04-29 14:15:09 +02:00
break ;
2009-07-14 10:07:15 +02:00
case QMapNodeType :
2009-04-29 16:52:14 +02:00
extraArgs [ 2 ] = evaluationSizeofTypeExpression ( data . type , debugger ) ;
2009-10-09 14:11:05 +02:00
extraArgs [ 3 ] = qMapNodeValueOffsetExpression ( data . type , data . addr , debugger ) ;
2009-04-29 14:15:09 +02:00
break ;
case StdVectorType :
//qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
if ( inners . at ( 0 ) = = QLatin1String ( " bool " ) ) {
outertype = QLatin1String ( " std::vector::bool " ) ;
}
break ;
case StdDequeType :
extraArgs [ 1 ] = zero ;
case StdStackType :
// remove 'std::allocator<...>':
extraArgs [ 1 ] = zero ;
break ;
case StdSetType :
// remove 'std::less<...>':
extraArgs [ 1 ] = zero ;
// remove 'std::allocator<...>':
extraArgs [ 2 ] = zero ;
break ;
case StdMapType : {
2009-10-09 14:11:05 +02:00
// We need the offset of the second item in the value pair.
2009-04-29 14:15:09 +02:00
// We read the type of the pair from the allocator argument because
2009-10-09 14:11:05 +02:00
// that gets the constness "right" (in the sense that gdb/cdb can
2009-07-03 13:56:27 +02:00
// read it back: "std::allocator<std::pair<Key,Value> >"
// -> "std::pair<Key,Value>". Different debuggers have varying
// amounts of terminating blanks...
2009-10-09 14:11:05 +02:00
extraArgs [ 2 ] . clear ( ) ;
extraArgs [ 3 ] = zero ;
2009-04-29 14:15:09 +02:00
QString pairType = inners . at ( 3 ) ;
2009-07-03 13:56:27 +02:00
int bracketPos = pairType . indexOf ( QLatin1Char ( ' < ' ) ) ;
if ( bracketPos ! = - 1 )
pairType . remove ( 0 , bracketPos + 1 ) ;
2009-10-09 14:11:05 +02:00
// We don't want the comparator and the allocator confuse gdb.
2009-07-07 16:00:45 +02:00
const QChar closingBracket = QLatin1Char ( ' > ' ) ;
bracketPos = pairType . lastIndexOf ( closingBracket ) ;
if ( bracketPos ! = - 1 )
bracketPos = pairType . lastIndexOf ( closingBracket , bracketPos - pairType . size ( ) - 1 ) ;
2009-07-03 13:56:27 +02:00
if ( bracketPos ! = - 1 )
pairType . truncate ( bracketPos + 1 ) ;
2009-10-09 14:11:05 +02:00
if ( debugger = = GdbDebugger ) {
extraArgs [ 2 ] = QLatin1String ( " (size_t)&((' " ) ;
extraArgs [ 2 ] + = pairType ;
extraArgs [ 2 ] + = QLatin1String ( " '*)0)->second " ) ;
} else {
// Cdb: The std::pair is usually in scope. Still, this expression
// occasionally fails for complex types (std::string).
// We need an address as CDB cannot do the 0-trick.
// Use data address or try at least cache if missing.
const QString address = data . addr . isEmpty ( ) ? QString : : fromLatin1 ( " DUMMY_ADDRESS " ) : data . addr ;
QString offsetExpr ;
QTextStream str ( & offsetExpr ) ;
str < < " (size_t)&((( " < < pairType < < " *) " < < address < < " )->second) " < < ' - ' < < address ;
extraArgs [ 2 ] = lookupCdbDummyAddressExpression ( offsetExpr , address ) ;
}
2009-04-29 14:15:09 +02:00
}
break ;
case StdStringType :
//qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
if ( inners . at ( 0 ) = = QLatin1String ( " char " ) ) {
outertype = QLatin1String ( " std::string " ) ;
} else if ( inners . at ( 0 ) = = QLatin1String ( " wchar_t " ) ) {
outertype = QLatin1String ( " std::wstring " ) ;
}
qFill ( extraArgs , zero ) ;
break ;
case UnknownType :
qWarning ( " Unknown type encountered in %s. \n " , Q_FUNC_INFO ) ;
break ;
case SupportedType :
2009-07-16 12:09:24 +02:00
case QVectorType :
2009-08-28 09:44:11 +02:00
case QStackType :
2009-07-06 17:36:50 +02:00
case QObjectType :
case QWidgetType :
2009-04-29 14:15:09 +02:00
break ;
}
2009-07-02 16:38:15 +02:00
// Look up expressions in the cache
if ( ! m_expressionCache . empty ( ) ) {
const QMap < QString , QString > : : const_iterator excCend = m_expressionCache . constEnd ( ) ;
const QStringList : : iterator eend = extraArgs . end ( ) ;
for ( QStringList : : iterator it = extraArgs . begin ( ) ; it ! = eend ; + + it ) {
QString & e = * it ;
if ( ! e . isEmpty ( ) & & e ! = zero & & ! isInteger ( e ) ) {
const QMap < QString , QString > : : const_iterator eit = m_expressionCache . constFind ( e ) ;
if ( eit ! = excCend )
e = eit . value ( ) ;
}
}
}
2009-04-29 14:15:09 +02:00
inBuffer - > clear ( ) ;
inBuffer - > append ( outertype . toUtf8 ( ) ) ;
inBuffer - > append ( ' \0 ' ) ;
2010-01-05 16:51:55 +01:00
inBuffer - > append ( data . iname ) ;
2009-04-29 14:15:09 +02:00
inBuffer - > append ( ' \0 ' ) ;
2010-01-05 16:51:55 +01:00
inBuffer - > append ( data . exp ) ;
2009-04-29 14:15:09 +02:00
inBuffer - > append ( ' \0 ' ) ;
2009-06-03 12:46:55 +02:00
inBuffer - > append ( inner . toUtf8 ( ) ) ;
2009-04-29 14:15:09 +02:00
inBuffer - > append ( ' \0 ' ) ;
2010-01-05 16:51:55 +01:00
inBuffer - > append ( data . iname ) ;
2009-06-08 11:45:15 +02:00
inBuffer - > append ( ' \0 ' ) ;
2009-04-29 14:15:09 +02:00
if ( debug )
qDebug ( ) < < ' \n ' < < Q_FUNC_INFO < < ' \n ' < < data . toString ( ) < < " \n --> " < < outertype < < td . type < < extraArgs ;
}
2009-10-09 14:11:05 +02:00
// Return debugger expression to get the offset of a map node.
QString QtDumperHelper : : qMapNodeValueOffsetExpression ( const QString & type ,
const QString & addressIn ,
Debugger debugger ) const
{
switch ( debugger ) {
case GdbDebugger :
return QLatin1String ( " (size_t) & ( ( ' " ) + type + QLatin1String( " ' * ) 0 ) - > value " ) ;
case CdbDebugger : {
// Cdb: This will only work if a QMapNode is in scope.
// We need an address as CDB cannot do the 0-trick.
// Use data address or try at least cache if missing.
const QString address = addressIn . isEmpty ( ) ? QString : : fromLatin1 ( " DUMMY_ADDRESS " ) : addressIn ;
QString offsetExpression ;
QTextStream ( & offsetExpression ) < < " (size_t)&((( " < < type
< < " *) " < < address < < " )->value)- " < < address ;
return lookupCdbDummyAddressExpression ( offsetExpression , address ) ;
}
}
return QString ( ) ;
}
/* Cdb cannot do tricks like ( "&(std::pair<int,int>*)(0)->second)",
* that is , use a null pointer to determine the offset of a member .
* It tries to dereference the address at some point and fails with
* " memory access error " . As a trick , use the address of the watch item
* to do this . However , in the expression cache , 0 is still used , so ,
* for cache lookups , use ' 0 ' as address . */
QString QtDumperHelper : : lookupCdbDummyAddressExpression ( const QString & expr ,
const QString & address ) const
{
QString nullExpr = expr ;
nullExpr . replace ( address , QString ( QLatin1Char ( ' 0 ' ) ) ) ;
const QString rc = m_expressionCache . value ( nullExpr , expr ) ;
if ( debug )
qDebug ( ) < < " lookupCdbDummyAddressExpression " < < expr < < rc ;
return rc ;
}
2009-09-21 14:55:39 +02:00
// GdbMi parsing helpers for parsing dumper value results
2009-04-29 14:15:09 +02:00
2009-09-21 14:55:39 +02:00
static bool gdbMiGetIntValue ( int * target ,
const GdbMi & node ,
const char * child )
2009-04-29 14:15:09 +02:00
{
2009-09-21 14:55:39 +02:00
* target = - 1 ;
const GdbMi childNode = node . findChild ( child ) ;
if ( ! childNode . isValid ( ) )
return false ;
bool ok ;
* target = childNode . data ( ) . toInt ( & ok ) ;
return ok ;
2009-04-29 14:15:09 +02:00
}
2009-09-21 14:55:39 +02:00
// Find a string child node and assign value if it exists.
// Optionally decode.
static bool gdbMiGetStringValue ( QString * target ,
const GdbMi & node ,
const char * child ,
const char * encodingChild = 0 )
2009-04-29 14:15:09 +02:00
{
2009-09-21 14:55:39 +02:00
target - > clear ( ) ;
const GdbMi childNode = node . findChild ( child ) ;
if ( ! childNode . isValid ( ) )
return false ;
// Encoded data
if ( encodingChild ) {
int encoding ;
if ( ! gdbMiGetIntValue ( & encoding , node , encodingChild ) )
encoding = 0 ;
* target = decodeData ( childNode . data ( ) , encoding ) ;
return true ;
2009-04-29 14:15:09 +02:00
}
2009-09-21 14:55:39 +02:00
// Plain data
* target = QLatin1String ( childNode . data ( ) ) ;
2009-04-29 14:15:09 +02:00
return true ;
}
2010-01-05 16:51:55 +01:00
static bool gdbMiGetByteArrayValue ( QByteArray * target ,
const GdbMi & node ,
const char * child ,
const char * encodingChild = 0 )
{
QString str ;
const bool success = gdbMiGetStringValue ( & str , node , child , encodingChild ) ;
* target = str . toLatin1 ( ) ;
return success ;
}
2009-09-21 14:55:39 +02:00
static bool gdbMiGetBoolValue ( bool * target ,
const GdbMi & node ,
const char * child )
2009-04-29 14:15:09 +02:00
{
2009-09-21 14:55:39 +02:00
* target = false ;
const GdbMi childNode = node . findChild ( child ) ;
if ( ! childNode . isValid ( ) )
return false ;
* target = childNode . data ( ) = = " true " ;
2009-04-29 14:15:09 +02:00
return true ;
}
2009-09-21 14:55:39 +02:00
/* Context to store parameters that influence the next level children.
* ( next level only , it is not further inherited ) . For example , the root item
* can provide a " childtype " node that specifies the type of the children . */
2010-01-05 16:51:55 +01:00
struct GdbMiRecursionContext
{
2009-09-21 14:55:39 +02:00
GdbMiRecursionContext ( int recursionLevelIn = 0 ) :
recursionLevel ( recursionLevelIn ) , childNumChild ( - 1 ) , childIndex ( 0 ) { }
int recursionLevel ;
int childNumChild ;
int childIndex ;
QString childType ;
2010-01-05 16:51:55 +01:00
QByteArray parentIName ;
2009-09-21 14:55:39 +02:00
} ;
static void gbdMiToWatchData ( const GdbMi & root ,
const GdbMiRecursionContext & ctx ,
QList < WatchData > * wl )
2009-04-29 14:15:09 +02:00
{
2009-09-21 14:55:39 +02:00
if ( debug > 1 )
qDebug ( ) < < Q_FUNC_INFO < < ' \n ' < < root . toString ( false , 0 ) ;
2010-01-29 21:33:57 +01:00
WatchData w ;
2009-09-21 14:55:39 +02:00
QString v ;
2010-01-05 16:51:55 +01:00
QByteArray b ;
2009-09-21 14:55:39 +02:00
// Check for name/iname and use as expression default
if ( ctx . recursionLevel = = 0 ) {
// parents have only iname, from which name is derived
2010-01-05 16:51:55 +01:00
QString iname ;
if ( ! gdbMiGetStringValue ( & iname , root , " iname " ) )
2009-09-21 14:55:39 +02:00
qWarning ( " Internal error: iname missing " ) ;
2010-01-05 16:51:55 +01:00
w . iname = iname . toLatin1 ( ) ;
w . name = iname ;
2009-09-21 14:55:39 +02:00
const int lastDotPos = w . name . lastIndexOf ( QLatin1Char ( ' . ' ) ) ;
if ( lastDotPos ! = - 1 )
w . name . remove ( 0 , lastDotPos + 1 ) ;
2010-01-05 16:51:55 +01:00
w . exp = w . name . toLatin1 ( ) ;
2009-09-21 14:55:39 +02:00
} else {
// Children can have a 'name' attribute. If missing, assume array index
// For display purposes, it can be overridden by "key"
if ( ! gdbMiGetStringValue ( & w . name , root , " name " ) ) {
w . name = QString : : number ( ctx . childIndex ) ;
}
// Set iname
w . iname = ctx . parentIName ;
2010-01-05 16:51:55 +01:00
w . iname + = ' . ' ;
w . iname + = w . name . toLatin1 ( ) ;
2009-09-21 14:55:39 +02:00
// Key?
QString key ;
if ( gdbMiGetStringValue ( & key , root , " key " , " keyencoded " ) ) {
w . name = key . size ( ) > 13 ? key . mid ( 0 , 13 ) + QLatin1String ( " ... " ) : key ;
}
}
if ( w . name . isEmpty ( ) ) {
const QString msg = QString : : fromLatin1 ( " Internal error: Unable to determine name at level %1/%2 for %3 " ) . arg ( ctx . recursionLevel ) . arg ( w . iname , QLatin1String ( root . toString ( true , 2 ) ) ) ;
qWarning ( " %s \n " , qPrintable ( msg ) ) ;
}
gdbMiGetStringValue ( & w . displayedType , root , " displayedtype " ) ;
2010-01-05 16:51:55 +01:00
if ( gdbMiGetByteArrayValue ( & b , root , " editvalue " ) )
w . editvalue = b ;
if ( gdbMiGetByteArrayValue ( & b , root , " exp " ) )
w . exp = b ;
gdbMiGetByteArrayValue ( & w . addr , root , " addr " ) ;
gdbMiGetByteArrayValue ( & w . saddr , root , " saddr " ) ;
2010-01-29 21:33:57 +01:00
gdbMiGetBoolValue ( & w . valueEnabled , root , " valueenabled " ) ;
2009-09-21 14:55:39 +02:00
gdbMiGetBoolValue ( & w . valueEditable , root , " valueeditable " ) ;
if ( gdbMiGetStringValue ( & v , root , " valuetooltip " , " valuetooltipencoded " ) )
w . setValue ( v ) ;
if ( gdbMiGetStringValue ( & v , root , " value " , " valueencoded " ) )
w . setValue ( v ) ;
// Type from context or self
if ( ctx . childType . isEmpty ( ) ) {
if ( gdbMiGetStringValue ( & v , root , " type " ) )
w . setType ( v ) ;
} else {
w . setType ( ctx . childType ) ;
}
// child count?
int numChild = - 1 ;
if ( ctx . childNumChild > = 0 ) {
numChild = ctx . childNumChild ;
} else {
gdbMiGetIntValue ( & numChild , root , " numchild " ) ;
}
if ( numChild > = 0 )
w . setHasChildren ( numChild > 0 ) ;
wl - > push_back ( w ) ;
// Parse children with a new context
if ( numChild = = 0 )
return ;
const GdbMi childrenNode = root . findChild ( " children " ) ;
if ( ! childrenNode . isValid ( ) )
return ;
const QList < GdbMi > children = childrenNode . children ( ) ;
if ( children . empty ( ) )
return ;
wl - > back ( ) . setChildrenUnneeded ( ) ;
GdbMiRecursionContext nextLevelContext ( ctx . recursionLevel + 1 ) ;
nextLevelContext . parentIName = w . iname ;
gdbMiGetStringValue ( & nextLevelContext . childType , root , " childtype " ) ;
if ( ! gdbMiGetIntValue ( & nextLevelContext . childNumChild , root , " childnumchild " ) )
nextLevelContext . childNumChild = - 1 ;
foreach ( const GdbMi & child , children ) {
gbdMiToWatchData ( child , nextLevelContext , wl ) ;
nextLevelContext . childIndex + + ;
2009-04-22 17:28:26 +02:00
}
}
2009-09-21 14:55:39 +02:00
bool QtDumperHelper : : parseValue ( const char * data ,
QList < WatchData > * l )
2009-07-03 13:56:27 +02:00
{
2009-09-21 14:55:39 +02:00
l - > clear ( ) ;
2009-11-30 15:17:34 +01:00
GdbMi root ;
root . fromStringMultiple ( QByteArray ( data ) ) ;
2009-09-21 14:55:39 +02:00
if ( ! root . isValid ( ) )
2009-04-29 14:15:09 +02:00
return false ;
2009-09-21 14:55:39 +02:00
gbdMiToWatchData ( root , GdbMiRecursionContext ( ) , l ) ;
2009-04-29 14:15:09 +02:00
return true ;
}
2009-04-29 16:52:14 +02:00
QDebug operator < < ( QDebug in , const QtDumperHelper : : TypeData & d )
{
QDebug nsp = in . nospace ( ) ;
nsp < < " type= " < < d . type < < " tpl= " < < d . isTemplate ;
if ( d . isTemplate )
nsp < < d . tmplate < < ' < ' < < d . inner < < ' > ' ;
return in ;
}
2009-05-05 10:22:44 +02:00
} // namespace Internal
} // namespace Debugger