/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtSCriptTools module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** 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. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qscriptdebuggeragent_p.h" | |
#include "qscriptdebuggeragent_p_p.h" | |
#include "qscriptdebuggerbackend_p_p.h" | |
#include <QtCore/qcoreapplication.h> | |
#include <QtCore/qset.h> | |
#include <QtScript/qscriptengine.h> | |
QT_BEGIN_NAMESPACE | |
/*! | |
\since 4.5 | |
\class QScriptDebuggerAgent | |
\internal | |
This class implements a state machine that uses the low-level events | |
reported by the QScriptEngineAgent interface to implement debugging- | |
specific functionality such as stepping and breakpoints. It is used | |
internally by the QScriptDebuggerBackend class. | |
*/ | |
QScriptDebuggerAgentPrivate::QScriptDebuggerAgentPrivate() | |
: state(NoState), stepDepth(0), stepCount(0), | |
targetScriptId(-1), targetLineNumber(-1), returnCounter(0), | |
nextBreakpointId(1), hitBreakpointId(0), | |
nextContextId(0), statementCounter(0) | |
{ | |
} | |
QScriptDebuggerAgentPrivate::~QScriptDebuggerAgentPrivate() | |
{ | |
} | |
QScriptDebuggerAgentPrivate *QScriptDebuggerAgentPrivate::get( | |
QScriptDebuggerAgent *q) | |
{ | |
if (!q) | |
return 0; | |
return q->d_func(); | |
} | |
/*! | |
Constructs a new agent for the given \a engine. The agent will | |
report debugging-related events (e.g. step completion) to the given | |
\a backend. | |
*/ | |
QScriptDebuggerAgent::QScriptDebuggerAgent( | |
QScriptDebuggerBackendPrivate *backend, QScriptEngine *engine) | |
: QScriptEngineAgent(engine), d_ptr(new QScriptDebuggerAgentPrivate()) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->backend = backend; | |
QScriptContext *ctx = engine->currentContext(); | |
while (ctx) { | |
d->scriptIdStack.append(QList<qint64>()); | |
d->contextIdStack.append(d->nextContextId); | |
++d->nextContextId; | |
ctx = ctx->parentContext(); | |
} | |
} | |
/*! | |
Destroys this QScriptDebuggerAgent. | |
*/ | |
QScriptDebuggerAgent::~QScriptDebuggerAgent() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
if (d->backend) | |
d->backend->agentDestroyed(this); | |
delete d; | |
} | |
/*! | |
Instructs the agent to perform a "step into" operation. This | |
function returns immediately. The agent will report step completion | |
at a later time, i.e. when script statements are evaluated. | |
*/ | |
void QScriptDebuggerAgent::enterStepIntoMode(int count) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->state = QScriptDebuggerAgentPrivate::SteppingIntoState; | |
d->stepCount = count; | |
d->stepResult = QScriptValue(); | |
} | |
/*! | |
Instructs the agent to perform a "step over" operation. This | |
function returns immediately. The agent will report step completion | |
at a later time, i.e. when script statements are evaluated. | |
*/ | |
void QScriptDebuggerAgent::enterStepOverMode(int count) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->state = QScriptDebuggerAgentPrivate::SteppingOverState; | |
if (engine()->isEvaluating()) | |
d->stepDepth = 0; | |
else | |
d->stepDepth = -1; | |
d->stepCount = count; | |
d->stepResult = QScriptValue(); | |
} | |
/*! | |
Instructs the agent to perform a "step out" operation. This | |
function returns immediately. The agent will report step completion | |
at a later time, i.e. when script statements are evaluated. | |
*/ | |
void QScriptDebuggerAgent::enterStepOutMode() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->state = QScriptDebuggerAgentPrivate::SteppingOutState; | |
if (engine()->isEvaluating()) | |
d->stepDepth = 0; | |
else | |
d->stepDepth = -1; | |
} | |
/*! | |
Instructs the agent to continue evaluation. | |
This function returns immediately. | |
*/ | |
void QScriptDebuggerAgent::enterContinueMode() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
} | |
/*! | |
Instructs the agent to interrupt evaluation. | |
This function returns immediately. | |
*/ | |
void QScriptDebuggerAgent::enterInterruptMode() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->state = QScriptDebuggerAgentPrivate::InterruptingState; | |
} | |
/*! | |
Instructs the agent to continue evaluation until the location | |
described by \a fileName and \a lineNumber is reached. This | |
function returns immediately. | |
*/ | |
void QScriptDebuggerAgent::enterRunToLocationMode(const QString &fileName, int lineNumber) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->targetFileName = fileName; | |
d->targetLineNumber = lineNumber; | |
d->targetScriptId = resolveScript(fileName); | |
d->state = QScriptDebuggerAgentPrivate::RunningToLocationState; | |
} | |
/*! | |
Instructs the agent to continue evaluation until the location | |
described by \a scriptId and \a lineNumber is reached. This | |
function returns immediately. | |
*/ | |
void QScriptDebuggerAgent::enterRunToLocationMode(qint64 scriptId, int lineNumber) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->targetScriptId = scriptId; | |
d->targetFileName = QString(); | |
d->targetLineNumber = lineNumber; | |
d->state = QScriptDebuggerAgentPrivate::RunningToLocationState; | |
} | |
void QScriptDebuggerAgent::enterReturnByForceMode(int contextIndex, const QScriptValue &value) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->returnCounter = contextIndex + 1; | |
d->returnValue = QScriptValue(); | |
d->state = QScriptDebuggerAgentPrivate::ReturningByForceState; | |
// throw an exception; we will catch it when the proper frame is popped | |
engine()->currentContext()->throwValue(value); | |
} | |
/*! | |
Sets a breakpoint defined by the given \a data. | |
Returns an integer that uniquely identifies the new breakpoint, | |
or -1 if setting the breakpoint failed. | |
*/ | |
int QScriptDebuggerAgent::setBreakpoint(const QScriptBreakpointData &data) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
qint64 scriptId = data.scriptId(); | |
if (scriptId != -1) { | |
if (!d->scripts.contains(scriptId)) { | |
// that script has been unloaded, so invalidate the ID | |
scriptId = -1; | |
const_cast<QScriptBreakpointData&>(data).setScriptId(-1); | |
} else if (data.fileName().isEmpty()) { | |
QString fileName = d->scripts[scriptId].fileName(); | |
const_cast<QScriptBreakpointData&>(data).setFileName(fileName); | |
} | |
} | |
int id = d->nextBreakpointId; | |
++d->nextBreakpointId; | |
if (scriptId != -1) { | |
d->resolvedBreakpoints[scriptId].append(id); | |
} else { | |
QString fileName = data.fileName(); | |
bool resolved = false; | |
QScriptScriptMap::const_iterator it; | |
for (it = d->scripts.constBegin(); it != d->scripts.constEnd(); ++it) { | |
if (it.value().fileName() == fileName) { | |
d->resolvedBreakpoints[it.key()].append(id); | |
resolved = true; | |
break; | |
} | |
} | |
if (!resolved) | |
d->unresolvedBreakpoints[fileName].append(id); | |
} | |
d->breakpoints.insert(id, data); | |
return id; | |
} | |
/*! | |
Deletes the breakpoint with the given \a id. | |
Returns true if the breakpoint was deleted, false if | |
no such breakpoint exists. | |
*/ | |
bool QScriptDebuggerAgent::deleteBreakpoint(int id) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
if (!d->breakpoints.contains(id)) | |
return false; | |
d->breakpoints.remove(id); | |
bool found = false; | |
{ | |
QHash<qint64, QList<int> >::iterator it; | |
it = d->resolvedBreakpoints.begin(); | |
for ( ; !found && (it != d->resolvedBreakpoints.end()); ) { | |
QList<int> &lst = it.value(); | |
Q_ASSERT(!lst.isEmpty()); | |
for (int i = 0; i < lst.size(); ++i) { | |
if (lst.at(i) == id) { | |
lst.removeAt(i); | |
found = true; | |
break; | |
} | |
} | |
if (lst.isEmpty()) | |
it = d->resolvedBreakpoints.erase(it); | |
else | |
++it; | |
} | |
} | |
if (!found) { | |
QHash<QString, QList<int> >::iterator it; | |
it = d->unresolvedBreakpoints.begin(); | |
for ( ; !found && (it != d->unresolvedBreakpoints.end()); ) { | |
QList<int> &lst = it.value(); | |
Q_ASSERT(!lst.isEmpty()); | |
for (int i = 0; i < lst.size(); ++i) { | |
if (lst.at(i) == id) { | |
lst.removeAt(i); | |
found = true; | |
break; | |
} | |
} | |
if (lst.isEmpty()) | |
it = d->unresolvedBreakpoints.erase(it); | |
else | |
++it; | |
} | |
} | |
return found; | |
} | |
/*! | |
Deletes all breakpoints. | |
*/ | |
void QScriptDebuggerAgent::deleteAllBreakpoints() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->breakpoints.clear(); | |
d->resolvedBreakpoints.clear(); | |
d->unresolvedBreakpoints.clear(); | |
} | |
/*! | |
Returns the data associated with the breakpoint with the given \a | |
id. | |
*/ | |
QScriptBreakpointData QScriptDebuggerAgent::breakpointData(int id) const | |
{ | |
Q_D(const QScriptDebuggerAgent); | |
return d->breakpoints.value(id); | |
} | |
/*! | |
Sets the data associated with the breakpoint with the given \a | |
id. | |
*/ | |
bool QScriptDebuggerAgent::setBreakpointData(int id, | |
const QScriptBreakpointData &data) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
if (!d->breakpoints.contains(id)) | |
return false; | |
d->breakpoints[id] = data; | |
return true; | |
} | |
/*! | |
Returns all breakpoints. | |
*/ | |
QScriptBreakpointMap QScriptDebuggerAgent::breakpoints() const | |
{ | |
Q_D(const QScriptDebuggerAgent); | |
return d->breakpoints; | |
} | |
/*! | |
Returns all scripts. | |
*/ | |
QScriptScriptMap QScriptDebuggerAgent::scripts() const | |
{ | |
Q_D(const QScriptDebuggerAgent); | |
return d->scripts; | |
} | |
/*! | |
Returns the data associated with the script with the given \a id. | |
*/ | |
QScriptScriptData QScriptDebuggerAgent::scriptData(qint64 id) const | |
{ | |
Q_D(const QScriptDebuggerAgent); | |
return d->scripts.value(id); | |
} | |
/*! | |
Checkpoints the current scripts. | |
*/ | |
void QScriptDebuggerAgent::scriptsCheckpoint() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->previousCheckpointScripts = d->checkpointScripts; | |
d->checkpointScripts = d->scripts; | |
} | |
/*! | |
Returns the difference between the current checkpoint and the | |
previous checkpoint. The first item in the pair is a list containing | |
the identifiers of the scripts that were added. The second item in | |
the pair is a list containing the identifiers of the scripts that | |
were removed. | |
*/ | |
QPair<QList<qint64>, QList<qint64> > QScriptDebuggerAgent::scriptsDelta() const | |
{ | |
Q_D(const QScriptDebuggerAgent); | |
QSet<qint64> prevSet = d->previousCheckpointScripts.keys().toSet(); | |
QSet<qint64> currSet = d->checkpointScripts.keys().toSet(); | |
QSet<qint64> addedScriptIds = currSet - prevSet; | |
QSet<qint64> removedScriptIds = prevSet - currSet; | |
return qMakePair(addedScriptIds.toList(), removedScriptIds.toList()); | |
} | |
/*! | |
Returns the identifier of the script that has the given \a fileName, | |
or -1 if there is no such script. | |
*/ | |
qint64 QScriptDebuggerAgent::resolveScript(const QString &fileName) const | |
{ | |
Q_D(const QScriptDebuggerAgent); | |
QScriptScriptMap::const_iterator it; | |
for (it = d->scripts.constBegin(); it != d->scripts.constEnd(); ++it) { | |
if (it.value().fileName() == fileName) | |
return it.key(); | |
} | |
return -1; | |
} | |
QList<qint64> QScriptDebuggerAgent::contextIds() const | |
{ | |
Q_D(const QScriptDebuggerAgent); | |
return d->contextIdStack; | |
} | |
QPair<QList<qint64>, QList<qint64> > QScriptDebuggerAgent::contextsCheckpoint() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
int i = d->checkpointContextIdStack.size() - 1; | |
int j = d->contextIdStack.size() - 1; | |
for ( ; (i >= 0) && (j >= 0); --i, --j) { | |
if (d->checkpointContextIdStack.at(i) != d->contextIdStack.at(j)) | |
break; | |
} | |
QList<qint64> removed = d->checkpointContextIdStack.mid(0, i+1); | |
QList<qint64> added = d->contextIdStack.mid(0, j+1); | |
d->checkpointContextIdStack = d->contextIdStack; | |
return qMakePair(removed, added); | |
} | |
void QScriptDebuggerAgent::nullifyBackendPointer() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->backend = 0; | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::scriptLoad(qint64 id, const QString &program, | |
const QString &fileName, int baseLineNumber) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
QScriptScriptData data = QScriptScriptData(program, fileName, baseLineNumber); | |
d->scripts.insert(id, data); | |
if ((d->state == QScriptDebuggerAgentPrivate::RunningToLocationState) | |
&& (d->targetScriptId == -1) | |
&& ((d->targetFileName == fileName) || d->targetFileName.isEmpty())) { | |
d->targetScriptId = id; | |
} | |
if (!fileName.isEmpty()) { | |
QList<int> lst = d->unresolvedBreakpoints.take(fileName); | |
if (!lst.isEmpty()) | |
d->resolvedBreakpoints.insert(id, lst); | |
} | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::scriptUnload(qint64 id) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
QScriptScriptData data = d->scripts.take(id); | |
QString fileName = data.fileName(); | |
if ((d->state == QScriptDebuggerAgentPrivate::RunningToLocationState) | |
&& (d->targetScriptId == id)) { | |
d->targetScriptId = -1; | |
d->targetFileName = fileName; | |
} | |
if (!fileName.isEmpty()) { | |
QList<int> lst = d->resolvedBreakpoints.take(id); | |
if (!lst.isEmpty()) | |
d->unresolvedBreakpoints.insert(fileName, lst); | |
} | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::contextPush() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->scriptIdStack.append(QList<qint64>()); | |
d->contextIdStack.prepend(d->nextContextId); | |
++d->nextContextId; | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::contextPop() | |
{ | |
Q_D(QScriptDebuggerAgent); | |
d->scriptIdStack.removeLast(); | |
d->contextIdStack.removeFirst(); | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::functionEntry(qint64 scriptId) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
QList<qint64> &ids = d->scriptIdStack.last(); | |
ids.append(scriptId); | |
if ((d->state == QScriptDebuggerAgentPrivate::SteppingOverState) | |
|| (d->state == QScriptDebuggerAgentPrivate::SteppingOutState)) { | |
++d->stepDepth; | |
} | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::functionExit(qint64 scriptId, | |
const QScriptValue &returnValue) | |
{ | |
Q_UNUSED(scriptId); | |
Q_D(QScriptDebuggerAgent); | |
QList<qint64> &ids = d->scriptIdStack.last(); | |
ids.removeLast(); | |
if (d->state == QScriptDebuggerAgentPrivate::SteppingOverState) { | |
--d->stepDepth; | |
} else if (d->state == QScriptDebuggerAgentPrivate::SteppingOutState) { | |
if (--d->stepDepth < 0) { | |
d->stepResult = returnValue; | |
d->state = QScriptDebuggerAgentPrivate::SteppedOutState; | |
} | |
} else if (d->state == QScriptDebuggerAgentPrivate::ReturningByForceState) { | |
if (--d->returnCounter == 0) { | |
d->returnValue = returnValue; | |
d->state = QScriptDebuggerAgentPrivate::ReturnedByForceState; | |
engine()->clearExceptions(); | |
} | |
} | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::positionChange(qint64 scriptId, | |
int lineNumber, int columnNumber) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
if (engine()->processEventsInterval() == -1) { | |
// see if it's time to call processEvents() | |
if ((++d->statementCounter % 25000) == 0) { | |
if (!d->processEventsTimer.isNull()) { | |
if (d->processEventsTimer.elapsed() > 30) { | |
QCoreApplication::processEvents(); | |
d->processEventsTimer.restart(); | |
} | |
} else { | |
d->processEventsTimer.start(); | |
} | |
} | |
} | |
// check breakpoints | |
{ | |
QList<int> lst = d->resolvedBreakpoints.value(scriptId); | |
for (int i = 0; i < lst.size(); ++i) { | |
int id = lst.at(i); | |
QScriptBreakpointData &data = d->breakpoints[id]; | |
if (!data.isEnabled()) | |
continue; | |
if (data.lineNumber() != lineNumber) | |
continue; | |
if (!data.condition().isEmpty()) { | |
// ### careful, evaluate() can cause an exception | |
// ### disable callbacks in nested evaluate? | |
QScriptDebuggerAgentPrivate::State was = d->state; | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
QScriptValue ret = engine()->evaluate( | |
data.condition(), | |
QString::fromLatin1("Breakpoint %0 condition checker").arg(id)); | |
if (!ret.isError()) | |
d->state = was; | |
if (!ret.toBoolean()) | |
continue; | |
} | |
if (!data.hit()) | |
continue; | |
d->hitBreakpointId = id; | |
d->state = QScriptDebuggerAgentPrivate::BreakpointState; | |
} | |
} | |
switch (d->state) { | |
case QScriptDebuggerAgentPrivate::NoState: | |
case QScriptDebuggerAgentPrivate::SteppingOutState: | |
case QScriptDebuggerAgentPrivate::ReturningByForceState: | |
// Do nothing | |
break; | |
case QScriptDebuggerAgentPrivate::SteppingIntoState: | |
if (--d->stepCount == 0) { | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) | |
d->backend->stepped(scriptId, lineNumber, columnNumber, QScriptValue()); | |
} | |
break; | |
case QScriptDebuggerAgentPrivate::SteppingOverState: | |
if ((d->stepDepth > 0) || (--d->stepCount != 0)) | |
break; | |
// fallthrough | |
case QScriptDebuggerAgentPrivate::SteppedOverState: | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) | |
d->backend->stepped(scriptId, lineNumber, columnNumber, d->stepResult); | |
break; | |
case QScriptDebuggerAgentPrivate::SteppedOutState: | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) | |
d->backend->stepped(scriptId, lineNumber, columnNumber, d->stepResult); | |
break; | |
case QScriptDebuggerAgentPrivate::RunningToLocationState: | |
if (((lineNumber == d->targetLineNumber) || (d->targetLineNumber == -1)) | |
&& (scriptId == d->targetScriptId)) { | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) | |
d->backend->locationReached(scriptId, lineNumber, columnNumber); | |
} | |
break; | |
case QScriptDebuggerAgentPrivate::InterruptingState: | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) | |
d->backend->interrupted(scriptId, lineNumber, columnNumber); | |
break; | |
case QScriptDebuggerAgentPrivate::BreakpointState: | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) | |
d->backend->breakpoint(scriptId, lineNumber, columnNumber, d->hitBreakpointId); | |
if (d->breakpoints.value(d->hitBreakpointId).isSingleShot()) | |
deleteBreakpoint(d->hitBreakpointId); | |
break; | |
case QScriptDebuggerAgentPrivate::ReturnedByForceState: | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) | |
d->backend->forcedReturn(scriptId, lineNumber, columnNumber, d->returnValue); | |
break; | |
case QScriptDebuggerAgentPrivate::SteppedIntoState: | |
case QScriptDebuggerAgentPrivate::ReachedLocationState: | |
case QScriptDebuggerAgentPrivate::InterruptedState: | |
// ### deal with the case when code is evaluated while we're already paused | |
// Q_ASSERT(false); | |
break; | |
} | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::exceptionThrow(qint64 scriptId, | |
const QScriptValue &exception, | |
bool hasHandler) | |
{ | |
Q_D(QScriptDebuggerAgent); | |
if (d->state == QScriptDebuggerAgentPrivate::ReturningByForceState) { | |
// we threw this exception ourselves, so ignore it for now | |
// (see functionExit()). | |
return; | |
} | |
if (d->backend) | |
d->backend->exception(scriptId, exception, hasHandler); | |
} | |
/*! | |
\reimp | |
*/ | |
void QScriptDebuggerAgent::exceptionCatch(qint64 scriptId, | |
const QScriptValue &exception) | |
{ | |
Q_UNUSED(scriptId); | |
Q_UNUSED(exception); | |
} | |
/*! | |
\reimp | |
*/ | |
bool QScriptDebuggerAgent::supportsExtension(Extension extension) const | |
{ | |
return (extension == DebuggerInvocationRequest); | |
} | |
/*! | |
\reimp | |
*/ | |
QVariant QScriptDebuggerAgent::extension(Extension extension, | |
const QVariant &argument) | |
{ | |
Q_UNUSED(extension); | |
Q_D(QScriptDebuggerAgent); | |
Q_ASSERT(extension == DebuggerInvocationRequest); | |
QVariantList lst = argument.toList(); | |
qint64 scriptId = lst.at(0).toLongLong(); | |
int lineNumber = lst.at(1).toInt(); | |
int columnNumber = lst.at(2).toInt(); | |
d->state = QScriptDebuggerAgentPrivate::NoState; | |
if (d->backend) { | |
d->backend->debuggerInvocationRequest( | |
scriptId, lineNumber, columnNumber); | |
} | |
return QVariant(); | |
} | |
QT_END_NAMESPACE |