Commit b8b50a21 authored by hjk's avatar hjk
Browse files

Debugger: Remove QScriptDebugClient



This officially removes support for QtQuick1 debugging.

Change-Id: Id3b6e64bb8e250ba57589b4e747f4ad33d3e03a6
Reviewed-by: default avatarKai Koehne <kai.koehne@theqtcompany.com>
Reviewed-by: default avatarEike Ziller <eike.ziller@theqtcompany.com>
Reviewed-by: default avatarAlessandro Portale <alessandro.portale@theqtcompany.com>
parent eb5afed1
......@@ -153,8 +153,7 @@ QtcPlugin {
"qmlinspectoradapter.cpp", "qmlinspectoradapter.h",
"qmlinspectoragent.cpp", "qmlinspectoragent.h",
"qmlv8debuggerclient.cpp", "qmlv8debuggerclient.h",
"qmlv8debuggerclientconstants.h",
"qscriptdebuggerclient.cpp", "qscriptdebuggerclient.h"
"qmlv8debuggerclientconstants.h"
]
}
......
......@@ -3,7 +3,6 @@ HEADERS += \
$$PWD/qmladapter.h \
$$PWD/baseqmldebuggerclient.h \
$$PWD/qmlcppengine.h \
$$PWD/qscriptdebuggerclient.h \
$$PWD/qmlv8debuggerclient.h \
$$PWD/interactiveinterpreter.h \
$$PWD/qmlv8debuggerclientconstants.h \
......@@ -15,7 +14,6 @@ SOURCES += \
$$PWD/qmladapter.cpp \
$$PWD/baseqmldebuggerclient.cpp \
$$PWD/qmlcppengine.cpp \
$$PWD/qscriptdebuggerclient.cpp \
$$PWD/qmlv8debuggerclient.cpp \
$$PWD/interactiveinterpreter.cpp \
$$PWD/qmlinspectoragent.cpp \
......
......@@ -33,7 +33,6 @@
#include <debugger/debuggerstringutils.h>
#include "qmlengine.h"
#include "qmlv8debuggerclient.h"
#include "qscriptdebuggerclient.h"
#include <utils/qtcassert.h>
......@@ -153,22 +152,14 @@ bool QmlAdapter::isConnected() const
void QmlAdapter::createDebuggerClients()
{
QScriptDebuggerClient *debugClient1 = new QScriptDebuggerClient(m_conn);
connect(debugClient1, &QScriptDebuggerClient::newState,
this, &QmlAdapter::clientStateChanged);
connect(debugClient1, &QScriptDebuggerClient::newState,
this, &QmlAdapter::debugClientStateChanged);
QmlV8DebuggerClient *debugClient2 = new QmlV8DebuggerClient(m_conn);
connect(debugClient2, &QmlV8DebuggerClient::newState,
this, &QmlAdapter::clientStateChanged);
connect(debugClient2, &QmlV8DebuggerClient::newState,
this, &QmlAdapter::debugClientStateChanged);
m_debugClients.insert(debugClient1->name(),debugClient1);
m_debugClients.insert(debugClient2->name(),debugClient2);
debugClient1->setEngine((QmlEngine*)(m_engine.data()));
debugClient2->setEngine((QmlEngine*)(m_engine.data()));
}
......
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "qscriptdebuggerclient.h"
#include "qmlengine.h"
#include <debugger/watchhandler.h>
#include <debugger/breakhandler.h>
#include <debugger/stackhandler.h>
#include <debugger/debuggercore.h>
#include <debugger/debuggerstringutils.h>
#include <qmldebug/qmldebugclient.h>
#include <coreplugin/messagebox.h>
#include <QFileInfo>
#include <utils/qtcassert.h>
using QmlDebug::QmlDebugStream;
namespace Debugger {
namespace Internal {
struct JSAgentBreakpointData
{
QByteArray functionName;
QByteArray fileUrl;
qint32 lineNumber;
};
struct JSAgentStackData
{
QByteArray functionName;
QByteArray fileUrl;
qint32 lineNumber;
};
uint qHash(const JSAgentBreakpointData &b)
{
return b.lineNumber ^ qHash(b.fileUrl);
}
QDataStream &operator<<(QDataStream &s, const JSAgentBreakpointData &data)
{
return s << data.functionName << data.fileUrl << data.lineNumber;
}
QDataStream &operator<<(QDataStream &s, const JSAgentStackData &data)
{
return s << data.functionName << data.fileUrl << data.lineNumber;
}
QDataStream &operator>>(QDataStream &s, JSAgentBreakpointData &data)
{
return s >> data.functionName >> data.fileUrl >> data.lineNumber;
}
QDataStream &operator>>(QDataStream &s, JSAgentStackData &data)
{
return s >> data.functionName >> data.fileUrl >> data.lineNumber;
}
bool operator==(const JSAgentBreakpointData &b1, const JSAgentBreakpointData &b2)
{
return b1.lineNumber == b2.lineNumber && b1.fileUrl == b2.fileUrl;
}
typedef QSet<JSAgentBreakpointData> JSAgentBreakpoints;
typedef QList<JSAgentStackData> JSAgentStackFrames;
static QDataStream &operator>>(QDataStream &s, WatchData &data)
{
data = WatchData();
QByteArray name;
QByteArray value;
QByteArray type;
bool hasChildren = false;
s >> data.exp >> name >> value >> type >> hasChildren >> data.id;
data.name = QString::fromUtf8(name);
data.setType(type, false);
data.setValue(QString::fromUtf8(value));
data.setHasChildren(hasChildren);
data.setAllUnneeded();
return s;
}
class QScriptDebuggerClientPrivate
{
public:
explicit QScriptDebuggerClientPrivate(QScriptDebuggerClient *) :
ping(0), sessionStarted(false), engine(0)
{
}
int ping;
bool sessionStarted;
QmlEngine *engine;
JSAgentBreakpoints breakpoints;
void logSendMessage(const QString &msg) const;
void logReceiveMessage(const QString &msg) const;
};
QScriptDebuggerClient::QScriptDebuggerClient(QmlDebug::QmlDebugConnection* client)
: BaseQmlDebuggerClient(client, QLatin1String("JSDebugger")),
d(new QScriptDebuggerClientPrivate(this))
{
}
QScriptDebuggerClient::~QScriptDebuggerClient()
{
delete d;
}
void QScriptDebuggerClient::executeStep()
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "STEPINTO";
rs << cmd;
d->logSendMessage(QLatin1String(cmd));
sendMessage(reply);
}
void QScriptDebuggerClient::executeStepOut()
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "STEPOUT";
rs << cmd;
d->logSendMessage(QLatin1String(cmd));
sendMessage(reply);
}
void QScriptDebuggerClient::executeNext()
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "STEPOVER";
rs << cmd;
d->logSendMessage(QLatin1String(cmd));
sendMessage(reply);
}
void QScriptDebuggerClient::executeStepI()
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "STEPINTO";
rs << cmd;
d->logSendMessage(QLatin1String(cmd));
sendMessage(reply);
}
void QScriptDebuggerClient::executeRunToLine(const ContextData &data)
{
JSAgentBreakpointData bp;
bp.fileUrl = QUrl::fromLocalFile(data.fileName).toString().toUtf8();
bp.lineNumber = data.lineNumber;
bp.functionName = "TEMPORARY";
d->breakpoints.insert(bp);
synchronizeBreakpoints();
continueInferior();
}
void QScriptDebuggerClient::continueInferior()
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "CONTINUE";
rs << cmd;
d->logSendMessage(QLatin1String(cmd));
sendMessage(reply);
}
void QScriptDebuggerClient::interruptInferior()
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "INTERRUPT";
rs << cmd;
d->logSendMessage(QLatin1String(cmd));
sendMessage(reply);
}
void QScriptDebuggerClient::startSession()
{
//Flush buffered data
flushSendBuffer();
//Set all breakpoints
BreakHandler *handler = d->engine->breakHandler();
DebuggerEngine * engine = d->engine->isSlaveEngine() ?
d->engine->masterEngine() : d->engine;
foreach (Breakpoint bp, handler->engineBreakpoints(engine)) {
QTC_CHECK(bp.state() == BreakpointInsertProceeding);
bp.notifyBreakpointInsertOk();
}
d->sessionStarted = true;
}
void QScriptDebuggerClient::endSession()
{
}
void QScriptDebuggerClient::resetSession()
{
d->sessionStarted = false;
}
void QScriptDebuggerClient::activateFrame(int index)
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "ACTIVATE_FRAME";
rs << cmd
<< index;
d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QString::number(index));
sendMessage(reply);
}
void QScriptDebuggerClient::insertBreakpoint(Breakpoint bp,
int adjustedLine,
int /*adjustedColumn*/)
{
JSAgentBreakpointData jsbp;
jsbp.fileUrl = QUrl::fromLocalFile(bp.fileName()).toString().toUtf8();
jsbp.lineNumber = adjustedLine;
jsbp.functionName = bp.functionName().toUtf8();
d->breakpoints.insert(jsbp);
BreakpointResponse br = bp.response();
br.lineNumber = adjustedLine;
bp.setResponse(br);
if (d->sessionStarted && bp.state() == BreakpointInsertProceeding)
bp.notifyBreakpointInsertOk();
}
void QScriptDebuggerClient::removeBreakpoint(Breakpoint bp)
{
JSAgentBreakpointData jsbp;
jsbp.fileUrl = QUrl::fromLocalFile(bp.fileName()).toString().toUtf8();
jsbp.lineNumber = bp.lineNumber();
jsbp.functionName = bp.functionName().toUtf8();
d->breakpoints.remove(jsbp);
}
void QScriptDebuggerClient::changeBreakpoint(Breakpoint bp)
{
if (bp.isEnabled())
insertBreakpoint(bp, bp.response().lineNumber);
else
removeBreakpoint(bp);
BreakpointResponse br = bp.response();
br.enabled = bp.isEnabled();
bp.setResponse(br);
}
void QScriptDebuggerClient::synchronizeBreakpoints()
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "BREAKPOINTS";
rs << cmd
<< d->breakpoints;
QString logBreakpoints;
QTextStream str(&logBreakpoints);
str << cmd << " (";
bool first = true;
foreach (const JSAgentBreakpointData &bp, d->breakpoints) {
if (first)
first = false;
else
str << ", ";
str << '[' << bp.functionName << ", " << bp.fileUrl << ", " << bp.lineNumber << ']';
}
str << ')';
d->logSendMessage(logBreakpoints);
sendMessage(reply);
}
void QScriptDebuggerClient::assignValueInDebugger(const WatchData *data,
const QString &expr,
const QVariant &valueV)
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "EXEC";
rs << cmd;
QString expression = QString(_("%1 = %2;")).arg(expr).arg(valueV.toString());
rs << data->iname << expression;
d->logSendMessage(QString::fromLatin1("%1 %2 %3 %4").
arg(QLatin1String(cmd), QLatin1String(data->iname), expr,
valueV.toString()));
sendMessage(reply);
}
void QScriptDebuggerClient::updateWatchData(const WatchData &data)
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "EXEC";
rs << cmd;
rs << data.iname << data.name;
d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QLatin1String(data.iname)
+ QLatin1Char(' ') + data.name);
sendMessage(reply);
}
void QScriptDebuggerClient::executeDebuggerCommand(const QString &command)
{
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "EXEC";
QByteArray console = "console";
rs << cmd << console << command;
d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QLatin1String(console)
+ QLatin1Char(' ') + command);
sendMessage(reply);
}
void QScriptDebuggerClient::synchronizeWatchers(const QStringList &watchers)
{
// send watchers list
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "WATCH_EXPRESSIONS";
rs << cmd;
d->logSendMessage(QString::fromLatin1("%1 (%2)").arg(QLatin1String(cmd),
watchers.join(QLatin1String(", "))));
sendMessage(reply);
}
void QScriptDebuggerClient::expandObject(const QByteArray &iname, quint64 objectId)
{
//Check if id is valid
if (qint64(objectId) == -1)
return;
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "EXPAND";
rs << cmd;
rs << iname << objectId;
d->logSendMessage(QLatin1String(cmd) + QLatin1Char(' ') + QLatin1String(iname)
+ QString::number(objectId));
sendMessage(reply);
}
void QScriptDebuggerClient::sendPing()
{
d->ping++;
QByteArray reply;
QmlDebugStream rs(&reply, QIODevice::WriteOnly);
QByteArray cmd = "PING";
rs << cmd;
rs << d->ping;
d->logSendMessage(QLatin1String(cmd));
sendMessage(reply);
}
void QScriptDebuggerClient::messageReceived(const QByteArray &data)
{
QByteArray rwData = data;
QmlDebugStream stream(&rwData, QIODevice::ReadOnly);
QByteArray command;
stream >> command;
WatchHandler *watchHandler = d->engine->watchHandler();
StackHandler *stackHandler = d->engine->stackHandler();
if (command == "STOPPED") {
d->engine->inferiorSpontaneousStop();
QString logString = QString::fromLatin1(command);
JSAgentStackFrames stackFrames;
QList<WatchData> watches;
QList<WatchData> locals;
stream >> stackFrames >> watches >> locals;
logString += QString::fromLatin1(" (%1 stack frames) (%2 watches) (%3 locals)").
arg(stackFrames.size()).arg(watches.size()).arg(locals.size());
StackFrames ideStackFrames;
for (int i = 0; i != stackFrames.size(); ++i) {
StackFrame frame;
frame.line = stackFrames.at(i).lineNumber;
frame.function = QLatin1String(stackFrames.at(i).functionName);
frame.file = d->engine->toFileInProject(QUrl(QLatin1String(stackFrames.at(i).fileUrl)));
frame.usable = QFileInfo(frame.file).isReadable();
frame.level = i + 1;
ideStackFrames << frame;
}
stackHandler->setFrames(ideStackFrames);
bool becauseOfException;
stream >> becauseOfException;
logString += becauseOfException ? QLatin1String(" exception") : QLatin1String(" no_exception");
if (becauseOfException) {
QString error;
stream >> error;
logString += QLatin1Char(' ');
logString += error;
d->logReceiveMessage(logString);
QString msg = stackFrames.isEmpty()
? tr("<p>An uncaught exception occurred:</p><p>%1</p>")
.arg(error.toHtmlEscaped())
: tr("<p>An uncaught exception occurred in \"%1\":</p><p>%2</p>")
.arg(QLatin1String(stackFrames.value(0).fileUrl), error.toHtmlEscaped());
Core::AsynchronousMessageBox::information(tr("Uncaught Exception"), msg);
} else {
QString file;
int line = -1;
if (!ideStackFrames.isEmpty()) {
file = ideStackFrames.at(0).file;
line = ideStackFrames.at(0).line;
}
QList<JSAgentBreakpointData> breakpoints(d->breakpoints.toList());
foreach (const JSAgentBreakpointData &data, breakpoints) {
if (data.fileUrl == QUrl::fromLocalFile(file).toString().toUtf8() &&
data.lineNumber == line &&
data.functionName == "TEMPORARY") {
breakpoints.removeOne(data);
d->breakpoints = JSAgentBreakpoints::fromList(breakpoints);
synchronizeBreakpoints();
break;
}
}
d->logReceiveMessage(logString);
}
if (!ideStackFrames.isEmpty())
d->engine->gotoLocation(ideStackFrames.value(0));
insertLocalsAndWatches(locals, watches, stackHandler->currentIndex());
} else if (command == "RESULT") {
WatchData data;
QByteArray iname;
stream >> iname >> data;
d->logReceiveMessage(QLatin1String(command) + QLatin1Char(' ')
+ QLatin1String(iname) + QLatin1Char(' ') + data.value);
auto item = new WatchItem(data);
item->iname = iname;
if (iname.startsWith("watch.")) {
watchHandler->insertItem(item);
} else if (iname == "console") {
d->engine->showMessage(item->value, ConsoleOutput);
} else if (iname.startsWith("local.")) {
item->name = item->name.left(item->name.indexOf(QLatin1Char(' ')));
watchHandler->insertItem(item);
} else {
qWarning() << "QmlEngine: Unexcpected result: " << iname << item->value;
}
} else if (command == "EXPANDED") {
QList<WatchData> result;
QByteArray iname;
stream >> iname >> result;
d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x watchdata)").
arg(QLatin1String(command), QLatin1String(iname),
QString::number(result.size())));
bool needPing = false;
foreach (WatchData data, result) {
data.iname = iname + '.' + data.exp;
watchHandler->insertItem(new WatchItem(data));
if (watchHandler->isExpandedIName(data.iname) && qint64(data.id) != -1) {
needPing = true;
expandObject(data.iname, data.id);
}
}
if (needPing)
sendPing();
} else if (command == "LOCALS") {
QList<WatchData> locals;
QList<WatchData> watches;
int frameId;
stream >> frameId >> locals;
if (!stream.atEnd()) { // compatibility with jsdebuggeragent from 2.1, 2.2
stream >> watches;
}
d->logReceiveMessage(QString::fromLatin1("%1 %2 (%3 x locals) (%4 x watchdata)").arg(
QLatin1String(command), QString::number(frameId),
QString::number(locals.size()), QString::number(watches.size())));
insertLocalsAndWatches(locals, watches, frameId);
} else if (command == "PONG") {
int ping;
stream >> ping;
d->logReceiveMessage(QLatin1String(command) + QLatin1Ch