From 085f6b2c267e43c11b814f7dffd7fceaa4634a4f Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 5 Nov 2009 08:25:25 +0100 Subject: [PATCH 1/6] debugger: add autotest for QList dumper --- tests/auto/debugger/tst_dumpers.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 2cb677968c5..dafec2ef83b 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -145,6 +145,7 @@ private slots: void dumpQImageData(); void dumpQLinkedList(); void dumpQList_int(); + void dumpQList_int_star(); void dumpQList_char(); void dumpQList_QString(); void dumpQList_QString3(); @@ -1392,6 +1393,22 @@ void tst_Debugger::dumpQList_int() &ilist, NS"QList", true, "int"); } +void tst_Debugger::dumpQList_int_star() +{ + QList ilist; + testDumper("value='<0 items>',valueeditable='false',numchild='0'," + "internal='1',children=[]", + &ilist, NS"QList", true, "int*"); + ilist.append(new int(1)); + ilist.append(0); + testDumper("value='<2 items>',valueeditable='false',numchild='2'," + "internal='1',childtype='int*',childnumchild='1',children=[" + "{saddr='" + str(&ilist.at(0)) + "',addr='" + str(deref(&ilist.at(0))) + + "',type='int',value='1'}," + "{saddr='" + str(&ilist.at(1)) + "',value='',numchild='0'}]", + &ilist, NS"QList", true, "int*"); +} + void tst_Debugger::dumpQList_char() { QList clist; From 5eadf2bef7707091c187cb29b41631c79058ae02 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 5 Nov 2009 14:46:38 +0100 Subject: [PATCH 2/6] debugger: simplify QList dumper --- share/qtcreator/gdbmacros/gdbmacros.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 2d14e7df067..dd51f806bd7 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -1613,31 +1613,28 @@ static void qDumpQList(QDumper &d) // This uses the knowledge that QList has only a single member // of type union { QListData p; QListData::Data *d; }; - const QListData &ldata = *reinterpret_cast(d.data); - const QListData::Data *pdata = - *reinterpret_cast(d.data); - const int nn = ldata.size(); + const QListData &pdata = *reinterpret_cast(d.data); + const int nn = pdata.size(); if (nn < 0) return; const bool innerTypeIsPointer = isPointerType(d.innerType); const int n = qMin(nn, 1000); if (nn > 0) { - if (ldata.d->begin < 0) + if (pdata.d->begin < 0) return; - if (ldata.d->begin > ldata.d->end) + if (pdata.d->begin > pdata.d->end) return; #if QT_VERSION >= 0x040400 - if (ldata.d->ref._q_value <= 0) + if (pdata.d->ref._q_value <= 0) return; #endif - qCheckAccess(ldata.d->array); + qCheckAccess(pdata.d->array); // Additional checks on pointer arrays if (innerTypeIsPointer) for (int i = 0; i != n; ++i) - if (const void *p = ldata.d->array + i + pdata->begin) + if (const void *p = pdata.d->array + i + pdata.d->begin) qCheckPointer(deref(p)); } - qCheckAccess(pdata); d.putItemCount("value", nn); d.putItem("valueeditable", "false"); @@ -1658,7 +1655,7 @@ static void qDumpQList(QDumper &d) for (int i = 0; i != n; ++i) { d.beginHash(); if (innerTypeIsPointer) { - void *p = ldata.d->array + i + pdata->begin; + void *p = pdata.d->array + i + pdata.d->begin; d.putItem("saddr", p); if (*(void**)p) { //d.putItem("value","@").put(p); @@ -1668,7 +1665,7 @@ static void qDumpQList(QDumper &d) d.putItem("numchild", "0"); } } else { - void *p = ldata.d->array + i + pdata->begin; + void *p = pdata.d->array + i + pdata.d->begin; if (isInternal) { //qDumpInnerValue(d, d.innerType, p); d.putItem("addr", p); From 06570d8d7c782b046c6ec2d27d5157a5afe3d00a Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Nov 2009 10:14:28 +0100 Subject: [PATCH 3/6] debugger: fix display of breakpoint markers in plugins --- src/plugins/debugger/gdb/gdbengine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 20ce97c9477..4a7f5e9fac7 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1258,6 +1258,11 @@ void GdbEngine::handleStop1(const GdbMi &data) if (m_sourcesListOutdated) reloadSourceFilesInternal(); // This needs to be done before fullName() may need it + // Older gdb versions do not produce "library loaded" messages + // so the breakpoint update is not triggered. + if (m_gdbVersion < 70000 && !m_isMacGdb) + postCommand(_("-break-list"), CB(handleBreakList)); + QByteArray reason = data.findChild("reason").data(); if (reason == "breakpoint-hit") { showStatusMessage(tr("Stopped at breakpoint.")); From 72db7df3a260c0f83812b254e70fa06f20bd874c Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 6 Nov 2009 10:46:24 +0100 Subject: [PATCH 4/6] fix some documentation glitches --- doc/qtcreator.qdoc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/qtcreator.qdoc b/doc/qtcreator.qdoc index 624a9e5d339..eea59c58061 100644 --- a/doc/qtcreator.qdoc +++ b/doc/qtcreator.qdoc @@ -1095,8 +1095,9 @@ watchers, registers, etc, Qt Creator comes with additional features to make debugging Qt-based applications easy. The debugger frontend knows about the internal layout of several Qt classes such as QString, the QTL containers, - and most importantly QObject (and classes derived from it). Therefore, it - is able to present Qt's data clearly. + and most importantly QObject (and classes derived from it), as well as + most containers of the C++ Standard Library, and is therefore able to + present their contents in a useful way. \section1 Debugger Engine Installation Notes @@ -1262,7 +1263,7 @@ parameters of the function in that frame as well as the local variables. Compound variables of struct or class type will be displayed as - "expandable" in the view. C lick on the "+" to expand the entry and show + "expandable" in the view. Click on the "+" to expand the entry and show all members. Together with the display of value and type, the user can examine and traverse the low-level layout of an object's data. @@ -1291,8 +1292,8 @@ The \gui{Locals and Watchers} view also provides access to the most powerful feature of the debugger: comprehensive display of data belonging - to Qt's basic objects. To enable this feature, select \gui{Use Custom - Display for Qt Objects} from the \gui Debug menu.The + to Qt's basic objects. To enable this feature, select \gui{Use + debugging helper} from the \gui Debug menu.The \gui{Locals and Watchers} view will be re-organized to provide a high-level view of the objects. For example, in case of QObject, instead of displaying a pointer to some private data structure, you will see a list of children, From 5e0e97587356f938298899c26f54f7d733417be4 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 9 Nov 2009 09:00:59 +0100 Subject: [PATCH 5/6] Debugger/Windows: Register debugger properly if there is no default. Some systems do not have a default debugger registered. Do not fail on reading the missing key and disable "Default Debugger" in that case. Initial-patch-by: Robert Loehning Reviewed-by: Robert Loehning --- src/tools/qtcdebugger/main.cpp | 50 ++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/src/tools/qtcdebugger/main.cpp b/src/tools/qtcdebugger/main.cpp index 36a276a7002..8be595a0ce1 100644 --- a/src/tools/qtcdebugger/main.cpp +++ b/src/tools/qtcdebugger/main.cpp @@ -363,19 +363,25 @@ bool startCreatorAsDebugger(QString *errorMessage) return true; } +bool readDefaultDebugger(QString *defaultDebugger, + QString *errorMessage) +{ + bool success = false; + HKEY handle; + if (openRegistryKey(HKEY_LOCAL_MACHINE, optIsWow ? debuggerWow32RegistryKeyC : debuggerRegistryKeyC, + false, &handle, errorMessage)) { + success = registryReadStringKey(handle, debuggerRegistryDefaultValueNameC, + defaultDebugger, errorMessage); + RegCloseKey(handle); + } + return success; +} + bool startDefaultDebugger(QString *errorMessage) { - // Read out default value - HKEY handle; - if (!openRegistryKey(HKEY_LOCAL_MACHINE, optIsWow ? debuggerWow32RegistryKeyC : debuggerRegistryKeyC, - false, &handle, errorMessage)) - return false; QString defaultDebugger; - if (!registryReadStringKey(handle, debuggerRegistryDefaultValueNameC, &defaultDebugger, errorMessage)) { - RegCloseKey(handle); + if (!readDefaultDebugger(&defaultDebugger, errorMessage)) return false; - } - RegCloseKey(handle); // binary, replace placeholders by pid/event id if (debug) qDebug() << "Default" << defaultDebugger; @@ -401,10 +407,13 @@ bool startDefaultDebugger(QString *errorMessage) bool chooseDebugger(QString *errorMessage) { + QString defaultDebugger; const QString msg = QString::fromLatin1("The application \"%1\" (process id %2) crashed. Would you like to debug it?").arg(getProcessBaseName(argProcessId)).arg(argProcessId); QMessageBox msgBox(QMessageBox::Information, QLatin1String(titleC), msg, QMessageBox::Cancel); QPushButton *creatorButton = msgBox.addButton(QLatin1String("Debug with Qt Creator"), QMessageBox::AcceptRole); QPushButton *defaultButton = msgBox.addButton(QLatin1String("Debug with default debugger"), QMessageBox::AcceptRole); + defaultButton->setEnabled(readDefaultDebugger(&defaultDebugger, errorMessage) + && !defaultDebugger.isEmpty()); msgBox.exec(); if (msgBox.clickedButton() == creatorButton) { // Just in case, default to standard @@ -444,12 +453,12 @@ static bool registerDebuggerKey(const WCHAR *key, do { if (!openRegistryKey(HKEY_LOCAL_MACHINE, key, true, &handle, errorMessage)) break; + // Save old key, which might be missing QString oldDebugger; - if (!registryReadStringKey(handle, debuggerRegistryValueNameC, &oldDebugger, errorMessage)) - break; + registryReadStringKey(handle, debuggerRegistryValueNameC, &oldDebugger, errorMessage); if (oldDebugger.contains(QLatin1String(applicationFileC), Qt::CaseInsensitive)) { *errorMessage = QLatin1String("The program is already registered as post mortem debugger."); - return false; + break; } if (!registryWriteStringKey(handle, debuggerRegistryDefaultValueNameC, oldDebugger, errorMessage)) break; @@ -483,11 +492,24 @@ static bool unregisterDebuggerKey(const WCHAR *key, QString *errorMessage) do { if (!openRegistryKey(HKEY_LOCAL_MACHINE, key, true, &handle, errorMessage)) break; + QString debugger; + registryReadStringKey(handle, debuggerRegistryValueNameC, &debugger, errorMessage); + if (!(debugger.isEmpty() + || debugger.contains(QLatin1String(applicationFileC), Qt::CaseInsensitive))) { + *errorMessage = QLatin1String("The program is not registered as post mortem debugger."); + break; + } QString oldDebugger; if (!registryReadStringKey(handle, debuggerRegistryDefaultValueNameC, &oldDebugger, errorMessage)) break; - if (!registryWriteStringKey(handle, debuggerRegistryValueNameC, oldDebugger, errorMessage)) - break; + // Re-register old debugger or delete key if it was empty. + if (oldDebugger.isEmpty()) { + if (!registryDeleteValue(handle, debuggerRegistryValueNameC, errorMessage)) + break; + } else { + if (!registryWriteStringKey(handle, debuggerRegistryValueNameC, oldDebugger, errorMessage)) + break; + } if (!registryDeleteValue(handle, debuggerRegistryDefaultValueNameC, errorMessage)) break; success = true; From a253a6998055b33fedb72943101f94342cfb55a7 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 9 Nov 2009 10:10:31 +0100 Subject: [PATCH 6/6] Do never offer signature autocompletion for constructor calls. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They should always use the function parameter tooltip. This fixes a bug where you were offered completion for C foo( -> C foo(int x) if C had a constructor taking int x. Reviewed-by: Thorbjørn Lindeijer --- src/plugins/cpptools/cppcodecompletion.cpp | 32 ++++++++++++---------- src/plugins/cpptools/cppcodecompletion.h | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 909ae011fe7..b27bfcf7af2 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -871,7 +871,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) if (! resolvedTypes.isEmpty()) { if (m_completionOperator == T_LPAREN && - completeConstructorOrFunction(resolvedTypes, context, endOfExpression)) { + completeConstructorOrFunction(resolvedTypes, context, endOfExpression, false)) { return m_startPosition; } else if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) && @@ -910,7 +910,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) // If it's a class, add completions for the constructors foreach (const TypeOfExpression::Result &result, results) { if (result.first->isClassType()) { - if (completeConstructorOrFunction(results, context, endOfExpression)) + if (completeConstructorOrFunction(results, context, endOfExpression, true)) return m_startPosition; break; } @@ -924,7 +924,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) bool CppCodeCompletion::completeConstructorOrFunction(const QList &results, const LookupContext &context, - int endOfExpression) + int endOfExpression, bool toolTipOnly) { QList functions; @@ -1013,15 +1013,17 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList(m_editor->widget()); @@ -1043,16 +1045,16 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QListtranslationUnit()->getPosition(sc->owner()->endOffset(), &endLine, &endColumn); - if (startLine <= line && line <= endLine) + if (startLine <= line && line <= endLine) { if ((startLine != line || startColumn <= column) && (endLine != line || column <= endColumn)) break; + } sc = sc->enclosingScope(); } - if (sc && (sc->isClassScope() || sc->isNamespaceScope())) - { + if (sc && (sc->isClassScope() || sc->isNamespaceScope())) { // It may still be a function call. If the whole line parses as a function // declaration, we should be certain that it isn't. bool autocompleteSignature = false; @@ -1091,7 +1093,9 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList &, const CPlusPlus::LookupContext &, - int endOfExpression); + int endOfExpression, bool toolTipOnly); bool completeMember(const QList &, const CPlusPlus::LookupContext &context);