forked from qt-creator/qt-creator
Merge commit 'origin/1.3'
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -1613,31 +1613,28 @@ static void qDumpQList(QDumper &d)
|
||||
// This uses the knowledge that QList<T> has only a single member
|
||||
// of type union { QListData p; QListData::Data *d; };
|
||||
|
||||
const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
|
||||
const QListData::Data *pdata =
|
||||
*reinterpret_cast<const QListData::Data* const*>(d.data);
|
||||
const int nn = ldata.size();
|
||||
const QListData &pdata = *reinterpret_cast<const QListData*>(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);
|
||||
|
||||
@@ -874,7 +874,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) &&
|
||||
@@ -913,7 +913,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;
|
||||
}
|
||||
@@ -927,7 +927,7 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
||||
|
||||
bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpression::Result> &results,
|
||||
const LookupContext &context,
|
||||
int endOfExpression)
|
||||
int endOfExpression, bool toolTipOnly)
|
||||
{
|
||||
QList<Function *> functions;
|
||||
|
||||
@@ -1016,15 +1016,17 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi
|
||||
}
|
||||
}
|
||||
|
||||
if (! functions.isEmpty()) {
|
||||
// There are two options:
|
||||
// 1. If this is a function call, we want to pop up a tooltip that shows the user
|
||||
// the possible overloads with their argument types and names.
|
||||
// 2. If this is a function definition, we want to offer autocompletion of
|
||||
// the function signature.
|
||||
// There are two different kinds of completion we want to provide:
|
||||
// 1. If this is a function call, we want to pop up a tooltip that shows the user
|
||||
// the possible overloads with their argument types and names.
|
||||
// 2. If this is a function definition, we want to offer autocompletion of
|
||||
// the function signature.
|
||||
|
||||
// Here we evaluate a first criterion: function definitions will only
|
||||
// happen in class or namespace scope.
|
||||
// check if function signature autocompletion is appropriate
|
||||
if (! functions.isEmpty() && ! toolTipOnly) {
|
||||
|
||||
// function definitions will only happen in class or namespace scope,
|
||||
// so get the current location's enclosing scope.
|
||||
|
||||
// get current line and column
|
||||
TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(m_editor->widget());
|
||||
@@ -1046,16 +1048,16 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi
|
||||
unsigned endLine, endColumn;
|
||||
context.thisDocument()->translationUnit()->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;
|
||||
@@ -1094,7 +1096,9 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! functions.empty()) {
|
||||
// set up function call tooltip
|
||||
|
||||
// Recreate if necessary
|
||||
|
||||
@@ -118,7 +118,7 @@ private:
|
||||
|
||||
bool completeConstructorOrFunction(const QList<CPlusPlus::TypeOfExpression::Result> &,
|
||||
const CPlusPlus::LookupContext &,
|
||||
int endOfExpression);
|
||||
int endOfExpression, bool toolTipOnly);
|
||||
|
||||
bool completeMember(const QList<CPlusPlus::TypeOfExpression::Result> &,
|
||||
const CPlusPlus::LookupContext &context);
|
||||
|
||||
@@ -1270,6 +1270,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."));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<int *> 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='<null>',numchild='0'}]",
|
||||
&ilist, NS"QList", true, "int*");
|
||||
}
|
||||
|
||||
void tst_Debugger::dumpQList_char()
|
||||
{
|
||||
QList<char> clist;
|
||||
|
||||
Reference in New Issue
Block a user