forked from qt-creator/qt-creator
QmlV8DebuggerClient: Relocate breakpoints
Walk the AST to find probable "breakable" code positions and relocate breakpoints. Change-Id: I3033bb85b21436face8265661aa8779c63dcf960 Reviewed-by: Kai Koehne <kai.koehne@nokia.com> Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
@@ -69,7 +69,8 @@ public:
|
|||||||
virtual void activateFrame(int index) = 0;
|
virtual void activateFrame(int index) = 0;
|
||||||
|
|
||||||
virtual bool acceptsBreakpoint(const BreakpointModelId &id);
|
virtual bool acceptsBreakpoint(const BreakpointModelId &id);
|
||||||
virtual void insertBreakpoint(const BreakpointModelId &id) = 0;
|
virtual void insertBreakpoint(const BreakpointModelId &id, int adjustedLine,
|
||||||
|
int adjustedColumn = -1) = 0;
|
||||||
virtual void removeBreakpoint(const BreakpointModelId &id) = 0;
|
virtual void removeBreakpoint(const BreakpointModelId &id) = 0;
|
||||||
virtual void changeBreakpoint(const BreakpointModelId &id) = 0;
|
virtual void changeBreakpoint(const BreakpointModelId &id) = 0;
|
||||||
virtual void synchronizeBreakpoints() = 0;
|
virtual void synchronizeBreakpoints() = 0;
|
||||||
|
|||||||
@@ -58,6 +58,8 @@
|
|||||||
#include <projectexplorer/applicationlauncher.h>
|
#include <projectexplorer/applicationlauncher.h>
|
||||||
#include <qmljsdebugclient/qdeclarativeoutputparser.h>
|
#include <qmljsdebugclient/qdeclarativeoutputparser.h>
|
||||||
#include <qmljseditor/qmljseditorconstants.h>
|
#include <qmljseditor/qmljseditorconstants.h>
|
||||||
|
#include <qmljs/parser/qmljsast_p.h>
|
||||||
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||||
|
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -95,6 +97,8 @@
|
|||||||
# define XSDEBUG(s) qDebug() << s
|
# define XSDEBUG(s) qDebug() << s
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
|
using namespace QmlJS;
|
||||||
|
using namespace AST;
|
||||||
|
|
||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -114,6 +118,7 @@ private:
|
|||||||
QHash<QString, QWeakPointer<TextEditor::ITextEditor> > m_sourceEditors;
|
QHash<QString, QWeakPointer<TextEditor::ITextEditor> > m_sourceEditors;
|
||||||
InteractiveInterpreter m_interpreter;
|
InteractiveInterpreter m_interpreter;
|
||||||
bool m_validContext;
|
bool m_validContext;
|
||||||
|
QHash<QString,BreakpointModelId> pendingBreakpoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
|
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
|
||||||
@@ -121,6 +126,163 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
|
|||||||
m_validContext(false)
|
m_validContext(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
class ASTWalker: public Visitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator()(Node *ast, quint32 *l, quint32 *c)
|
||||||
|
{
|
||||||
|
done = false;
|
||||||
|
line = l;
|
||||||
|
column = c;
|
||||||
|
Node::accept(ast, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool preVisit(Node *ast)
|
||||||
|
{
|
||||||
|
return ast->lastSourceLocation().startLine >= *line && !done;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Case 1: Breakpoint is between sourceStart(exclusive) and
|
||||||
|
// sourceEnd(inclusive) --> End tree walk.
|
||||||
|
//Case 2: Breakpoint is on sourceStart --> Check for the start
|
||||||
|
// of the first executable code. Set the line number and
|
||||||
|
// column number. End tree walk.
|
||||||
|
//Case 3: Breakpoint is on "unbreakable" code --> Find the next "breakable"
|
||||||
|
// code and check for Case 2. End tree walk.
|
||||||
|
|
||||||
|
//Add more types when suitable.
|
||||||
|
|
||||||
|
bool visit(UiScriptBinding *ast)
|
||||||
|
{
|
||||||
|
quint32 sourceStartLine = ast->firstSourceLocation().startLine;
|
||||||
|
quint32 statementStartLine;
|
||||||
|
quint32 statementColumn;
|
||||||
|
|
||||||
|
if (ast->statement->kind == Node::Kind_ExpressionStatement) {
|
||||||
|
statementStartLine = ast->statement->firstSourceLocation().
|
||||||
|
startLine;
|
||||||
|
statementColumn = ast->statement->firstSourceLocation().startColumn;
|
||||||
|
|
||||||
|
} else if (ast->statement->kind == Node::Kind_Block) {
|
||||||
|
Block *block = static_cast<Block *>(ast->statement);
|
||||||
|
statementStartLine = block->statements->firstSourceLocation().
|
||||||
|
startLine;
|
||||||
|
statementColumn = block->statements->firstSourceLocation().
|
||||||
|
startColumn;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Case 1
|
||||||
|
//Check for possible relocation within the binding statement
|
||||||
|
|
||||||
|
//Rewritten to (function <token>() { { }})
|
||||||
|
//The offset 16 is position of inner lbrace without token length.
|
||||||
|
const int offset = 16;
|
||||||
|
|
||||||
|
//Case 2
|
||||||
|
if (statementStartLine == *line) {
|
||||||
|
if (sourceStartLine == *line)
|
||||||
|
*column = offset + ast->qualifiedId->identifierToken.length;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Case 3
|
||||||
|
if (statementStartLine > *line) {
|
||||||
|
*line = statementStartLine;
|
||||||
|
if (sourceStartLine == *line)
|
||||||
|
*column = offset + ast->qualifiedId->identifierToken.length;
|
||||||
|
else
|
||||||
|
*column = statementColumn;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool visit(FunctionDeclaration *ast) {
|
||||||
|
quint32 sourceStartLine = ast->firstSourceLocation().startLine;
|
||||||
|
quint32 sourceStartColumn = ast->firstSourceLocation().startColumn;
|
||||||
|
quint32 statementStartLine = ast->body->firstSourceLocation().startLine;
|
||||||
|
quint32 statementColumn = ast->body->firstSourceLocation().startColumn;
|
||||||
|
|
||||||
|
//Case 1
|
||||||
|
//Check for possible relocation within the function declaration
|
||||||
|
|
||||||
|
//Case 2
|
||||||
|
if (statementStartLine == *line) {
|
||||||
|
if (sourceStartLine == *line)
|
||||||
|
*column = statementColumn - sourceStartColumn + 1;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Case 3
|
||||||
|
if (statementStartLine > *line) {
|
||||||
|
*line = statementStartLine;
|
||||||
|
if (sourceStartLine == *line)
|
||||||
|
*column = statementColumn - sourceStartColumn + 1;
|
||||||
|
else
|
||||||
|
*column = statementColumn;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool visit(EmptyStatement *ast)
|
||||||
|
{
|
||||||
|
*line = ast->lastSourceLocation().startLine + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool visit(VariableStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(VariableDeclarationList *ast) { test(ast); return true; }
|
||||||
|
bool visit(VariableDeclaration *ast) { test(ast); return true; }
|
||||||
|
bool visit(ExpressionStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(IfStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(DoWhileStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(WhileStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(ForStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(LocalForStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(ForEachStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(LocalForEachStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(ContinueStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(BreakStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(ReturnStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(WithStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(SwitchStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(CaseBlock *ast) { test(ast); return true; }
|
||||||
|
bool visit(CaseClauses *ast) { test(ast); return true; }
|
||||||
|
bool visit(CaseClause *ast) { test(ast); return true; }
|
||||||
|
bool visit(DefaultClause *ast) { test(ast); return true; }
|
||||||
|
bool visit(LabelledStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(ThrowStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(TryStatement *ast) { test(ast); return true; }
|
||||||
|
bool visit(Catch *ast) { test(ast); return true; }
|
||||||
|
bool visit(Finally *ast) { test(ast); return true; }
|
||||||
|
bool visit(FunctionExpression *ast) { test(ast); return true; }
|
||||||
|
bool visit(DebuggerStatement *ast) { test(ast); return true; }
|
||||||
|
|
||||||
|
void test(Node *ast)
|
||||||
|
{
|
||||||
|
quint32 statementStartLine = ast->firstSourceLocation().startLine;
|
||||||
|
//Case 1/2
|
||||||
|
if (statementStartLine <= *line &&
|
||||||
|
*line <= ast->lastSourceLocation().startLine)
|
||||||
|
done = true;
|
||||||
|
|
||||||
|
//Case 3
|
||||||
|
if (statementStartLine > *line) {
|
||||||
|
*line = statementStartLine;
|
||||||
|
*column = ast->firstSourceLocation().startColumn;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool done;
|
||||||
|
quint32 *line;
|
||||||
|
quint32 *column;
|
||||||
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -188,6 +350,11 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters,
|
|||||||
connect(&d->m_noDebugOutputTimer, SIGNAL(timeout()), this, SLOT(beginConnection()));
|
connect(&d->m_noDebugOutputTimer, SIGNAL(timeout()), this, SLOT(beginConnection()));
|
||||||
|
|
||||||
qtMessageLogHandler()->setHasEditableRow(true);
|
qtMessageLogHandler()->setHasEditableRow(true);
|
||||||
|
|
||||||
|
connect(ModelManagerInterface::instance(),
|
||||||
|
SIGNAL(documentUpdated(QmlJS::Document::Ptr)),
|
||||||
|
this,
|
||||||
|
SLOT(documentUpdated(QmlJS::Document::Ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlEngine::~QmlEngine()
|
QmlEngine::~QmlEngine()
|
||||||
@@ -560,8 +727,14 @@ void QmlEngine::executeRunToLine(const ContextData &data)
|
|||||||
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
|
||||||
showStatusMessage(tr("Run to line %1 (%2) requested...").arg(data.lineNumber).arg(data.fileName), 5000);
|
showStatusMessage(tr("Run to line %1 (%2) requested...").arg(data.lineNumber).arg(data.fileName), 5000);
|
||||||
resetLocation();
|
resetLocation();
|
||||||
|
ContextData modifiedData = data;
|
||||||
|
quint32 line = data.lineNumber;
|
||||||
|
quint32 column;
|
||||||
|
bool valid;
|
||||||
|
if (adjustBreakpointLineAndColumn(data.fileName, &line, &column, &valid))
|
||||||
|
modifiedData.lineNumber = line;
|
||||||
if (d->m_adapter.activeDebuggerClient())
|
if (d->m_adapter.activeDebuggerClient())
|
||||||
d->m_adapter.activeDebuggerClient()->executeRunToLine(data);
|
d->m_adapter.activeDebuggerClient()->executeRunToLine(modifiedData);
|
||||||
notifyInferiorRunRequested();
|
notifyInferiorRunRequested();
|
||||||
notifyInferiorRunOk();
|
notifyInferiorRunOk();
|
||||||
}
|
}
|
||||||
@@ -601,11 +774,25 @@ void QmlEngine::insertBreakpoint(BreakpointModelId id)
|
|||||||
QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << id << this << state);
|
QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << id << this << state);
|
||||||
handler->notifyBreakpointInsertProceeding(id);
|
handler->notifyBreakpointInsertProceeding(id);
|
||||||
|
|
||||||
|
const BreakpointParameters ¶ms = handler->breakpointData(id);
|
||||||
|
quint32 line = params.lineNumber;
|
||||||
|
quint32 column = 0;
|
||||||
|
if (params.type == BreakpointByFileAndLine) {
|
||||||
|
bool valid = false;
|
||||||
|
if (!adjustBreakpointLineAndColumn(params.fileName, &line, &column,
|
||||||
|
&valid)) {
|
||||||
|
d->pendingBreakpoints.insertMulti(params.fileName, id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (d->m_adapter.activeDebuggerClient()) {
|
if (d->m_adapter.activeDebuggerClient()) {
|
||||||
d->m_adapter.activeDebuggerClient()->insertBreakpoint(id);
|
d->m_adapter.activeDebuggerClient()->insertBreakpoint(id, line, column);
|
||||||
} else {
|
} else {
|
||||||
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients()) {
|
foreach (QmlDebuggerClient *client, d->m_adapter.debuggerClients()) {
|
||||||
client->insertBreakpoint(id);
|
client->insertBreakpoint(id, line, column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -613,6 +800,21 @@ void QmlEngine::insertBreakpoint(BreakpointModelId id)
|
|||||||
void QmlEngine::removeBreakpoint(BreakpointModelId id)
|
void QmlEngine::removeBreakpoint(BreakpointModelId id)
|
||||||
{
|
{
|
||||||
BreakHandler *handler = breakHandler();
|
BreakHandler *handler = breakHandler();
|
||||||
|
|
||||||
|
const BreakpointParameters ¶ms = handler->breakpointData(id);
|
||||||
|
if (params.type == BreakpointByFileAndLine &&
|
||||||
|
d->pendingBreakpoints.contains(params.fileName)) {
|
||||||
|
QHash<QString, BreakpointModelId>::iterator i =
|
||||||
|
d->pendingBreakpoints.find(params.fileName);
|
||||||
|
while (i != d->pendingBreakpoints.end() && i.key() == params.fileName) {
|
||||||
|
if (i.value() == id) {
|
||||||
|
d->pendingBreakpoints.erase(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BreakpointState state = handler->state(id);
|
BreakpointState state = handler->state(id);
|
||||||
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << id << this << state);
|
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << id << this << state);
|
||||||
handler->notifyBreakpointRemoveProceeding(id);
|
handler->notifyBreakpointRemoveProceeding(id);
|
||||||
@@ -852,6 +1054,17 @@ void QmlEngine::disconnected()
|
|||||||
notifyInferiorExited();
|
notifyInferiorExited();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlEngine::documentUpdated(QmlJS::Document::Ptr doc)
|
||||||
|
{
|
||||||
|
QString fileName = doc->fileName();
|
||||||
|
if (d->pendingBreakpoints.contains(fileName)) {
|
||||||
|
QList<BreakpointModelId> ids = d->pendingBreakpoints.values(fileName);
|
||||||
|
d->pendingBreakpoints.remove(fileName);
|
||||||
|
foreach (const BreakpointModelId &id, ids)
|
||||||
|
insertBreakpoint(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QmlEngine::updateCurrentContext()
|
void QmlEngine::updateCurrentContext()
|
||||||
{
|
{
|
||||||
const QString context = state() == InferiorStopOk ?
|
const QString context = state() == InferiorStopOk ?
|
||||||
@@ -1085,6 +1298,27 @@ QtMessageLogItem *QmlEngine::constructLogItemTree(
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QmlEngine::adjustBreakpointLineAndColumn(
|
||||||
|
const QString &filePath, quint32 *line, quint32 *column, bool *valid)
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
//check if file is in the latest snapshot
|
||||||
|
//ignoring documentChangedOnDisk
|
||||||
|
//TODO:: update breakpoints if document is changed.
|
||||||
|
Document::Ptr doc = ModelManagerInterface::instance()->newestSnapshot().
|
||||||
|
document(filePath);
|
||||||
|
if (doc.isNull()) {
|
||||||
|
ModelManagerInterface::instance()->updateSourceFiles(
|
||||||
|
QStringList() << filePath, false);
|
||||||
|
success = false;
|
||||||
|
} else {
|
||||||
|
ASTWalker walker;
|
||||||
|
walker(doc->ast(), line, column);
|
||||||
|
*valid = walker.done;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
QmlAdapter *QmlEngine::adapter() const
|
QmlAdapter *QmlEngine::adapter() const
|
||||||
{
|
{
|
||||||
return &d->m_adapter;
|
return &d->m_adapter;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <qmljsdebugclient/qdeclarativeenginedebug.h>
|
#include <qmljsdebugclient/qdeclarativeenginedebug.h>
|
||||||
#include <qmljsdebugclient/qdebugmessageclient.h>
|
#include <qmljsdebugclient/qdebugmessageclient.h>
|
||||||
#include <utils/outputformat.h>
|
#include <utils/outputformat.h>
|
||||||
|
#include <qmljs/qmljsdocument.h>
|
||||||
|
|
||||||
#include <QAbstractSocket>
|
#include <QAbstractSocket>
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void disconnected();
|
void disconnected();
|
||||||
|
void documentUpdated(QmlJS::Document::Ptr doc);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void errorMessageBoxFinished(int result);
|
void errorMessageBoxFinished(int result);
|
||||||
@@ -184,6 +186,8 @@ private:
|
|||||||
bool canEvaluateScript(const QString &script);
|
bool canEvaluateScript(const QString &script);
|
||||||
QtMessageLogItem *constructLogItemTree(const QVariant &result,
|
QtMessageLogItem *constructLogItemTree(const QVariant &result,
|
||||||
const QString &key = QString());
|
const QString &key = QString());
|
||||||
|
bool adjustBreakpointLineAndColumn(const QString &filePath, quint32 *line,
|
||||||
|
quint32 *column, bool *valid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class QmlCppEngine;
|
friend class QmlCppEngine;
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ public:
|
|||||||
bool includeSource = false, const QVariant filter = QVariant());
|
bool includeSource = false, const QVariant filter = QVariant());
|
||||||
void source(int frame = -1, int fromLine = -1, int toLine = -1);
|
void source(int frame = -1, int fromLine = -1, int toLine = -1);
|
||||||
|
|
||||||
void setBreakpoint(const QString type, const QString target, int line = -1,
|
void setBreakpoint(const QString type, const QString target,
|
||||||
int column = -1, bool enabled = true,
|
bool enabled = true,int line = 0, int column = 0,
|
||||||
const QString condition = QString(), int ignoreCount = -1);
|
const QString condition = QString(), int ignoreCount = -1);
|
||||||
void changeBreakpoint(int breakpoint, bool enabled = true,
|
void changeBreakpoint(int breakpoint, bool enabled = true,
|
||||||
const QString condition = QString(), int ignoreCount = -1);
|
const QString condition = QString(), int ignoreCount = -1);
|
||||||
@@ -513,7 +513,7 @@ void QmlV8DebuggerClientPrivate::source(int frame, int fromLine, int toLine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void QmlV8DebuggerClientPrivate::setBreakpoint(const QString type, const QString target,
|
void QmlV8DebuggerClientPrivate::setBreakpoint(const QString type, const QString target,
|
||||||
int line, int column, bool enabled,
|
bool enabled, int line, int column,
|
||||||
const QString condition, int ignoreCount)
|
const QString condition, int ignoreCount)
|
||||||
{
|
{
|
||||||
// { "seq" : <number>,
|
// { "seq" : <number>,
|
||||||
@@ -542,13 +542,17 @@ void QmlV8DebuggerClientPrivate::setBreakpoint(const QString type, const QString
|
|||||||
QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT)));
|
QScriptValue args = parser.call(QScriptValue(), QScriptValueList() << QScriptValue(_(OBJECT)));
|
||||||
|
|
||||||
args.setProperty(_(TYPE), QScriptValue(type));
|
args.setProperty(_(TYPE), QScriptValue(type));
|
||||||
|
if (type == _(SCRIPTREGEXP))
|
||||||
|
args.setProperty(_(TARGET),
|
||||||
|
QScriptValue(QFileInfo(target).fileName()));
|
||||||
|
else
|
||||||
args.setProperty(_(TARGET), QScriptValue(target));
|
args.setProperty(_(TARGET), QScriptValue(target));
|
||||||
|
|
||||||
if (line != -1)
|
if (line)
|
||||||
args.setProperty(_(LINE), QScriptValue(line));
|
args.setProperty(_(LINE), QScriptValue(line - 1));
|
||||||
|
|
||||||
if (column != -1)
|
if (column)
|
||||||
args.setProperty(_(COLUMN), QScriptValue(column));
|
args.setProperty(_(COLUMN), QScriptValue(column - 1));
|
||||||
|
|
||||||
args.setProperty(_(ENABLED), QScriptValue(enabled));
|
args.setProperty(_(ENABLED), QScriptValue(enabled));
|
||||||
|
|
||||||
@@ -959,7 +963,7 @@ void QmlV8DebuggerClientPrivate::reformatRequest(QByteArray &request)
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
rs >> signalHandler >> enabled;
|
rs >> signalHandler >> enabled;
|
||||||
|
|
||||||
setBreakpoint(_(EVENT), QString::fromUtf8(signalHandler), -1, -1, enabled);
|
setBreakpoint(_(EVENT), QString::fromUtf8(signalHandler), enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1050,8 +1054,8 @@ void QmlV8DebuggerClient::executeStepI()
|
|||||||
|
|
||||||
void QmlV8DebuggerClient::executeRunToLine(const ContextData &data)
|
void QmlV8DebuggerClient::executeRunToLine(const ContextData &data)
|
||||||
{
|
{
|
||||||
d->setBreakpoint(QString(_(SCRIPTREGEXP)), QFileInfo(data.fileName).fileName(),
|
d->setBreakpoint(QString(_(SCRIPTREGEXP)), data.fileName,
|
||||||
data.lineNumber - 1);
|
data.lineNumber);
|
||||||
clearExceptionSelection();
|
clearExceptionSelection();
|
||||||
d->continueDebugging(Continue);
|
d->continueDebugging(Continue);
|
||||||
}
|
}
|
||||||
@@ -1082,7 +1086,9 @@ bool QmlV8DebuggerClient::acceptsBreakpoint(const BreakpointModelId &id)
|
|||||||
|| type == BreakpointAtJavaScriptThrow);
|
|| type == BreakpointAtJavaScriptThrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &id)
|
void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &id,
|
||||||
|
int adjustedLine,
|
||||||
|
int adjustedColumn)
|
||||||
{
|
{
|
||||||
BreakHandler *handler = d->engine->breakHandler();
|
BreakHandler *handler = d->engine->breakHandler();
|
||||||
const BreakpointParameters ¶ms = handler->breakpointData(id);
|
const BreakpointParameters ¶ms = handler->breakpointData(id);
|
||||||
@@ -1092,14 +1098,12 @@ void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &id)
|
|||||||
d->setExceptionBreak(AllExceptions, params.enabled);
|
d->setExceptionBreak(AllExceptions, params.enabled);
|
||||||
|
|
||||||
} else if (params.type == BreakpointByFileAndLine) {
|
} else if (params.type == BreakpointByFileAndLine) {
|
||||||
d->setBreakpoint(QString(_(SCRIPTREGEXP)),
|
d->setBreakpoint(QString(_(SCRIPTREGEXP)), params.fileName,
|
||||||
QFileInfo(params.fileName).fileName(),
|
params.enabled, adjustedLine, adjustedColumn,
|
||||||
params.lineNumber - 1, -1, params.enabled,
|
|
||||||
QLatin1String(params.condition), params.ignoreCount);
|
QLatin1String(params.condition), params.ignoreCount);
|
||||||
|
|
||||||
} else if (params.type == BreakpointOnQmlSignalHandler) {
|
} else if (params.type == BreakpointOnQmlSignalHandler) {
|
||||||
d->setBreakpoint(QString(_(EVENT)), params.functionName,
|
d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled);
|
||||||
-1, -1, params.enabled);
|
|
||||||
d->engine->breakHandler()->notifyBreakpointInsertOk(id);
|
d->engine->breakHandler()->notifyBreakpointInsertOk(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1109,21 +1113,18 @@ void QmlV8DebuggerClient::insertBreakpoint(const BreakpointModelId &id)
|
|||||||
void QmlV8DebuggerClient::removeBreakpoint(const BreakpointModelId &id)
|
void QmlV8DebuggerClient::removeBreakpoint(const BreakpointModelId &id)
|
||||||
{
|
{
|
||||||
BreakHandler *handler = d->engine->breakHandler();
|
BreakHandler *handler = d->engine->breakHandler();
|
||||||
|
const BreakpointParameters ¶ms = handler->breakpointData(id);
|
||||||
|
|
||||||
int breakpoint = d->breakpoints.value(id);
|
int breakpoint = d->breakpoints.value(id);
|
||||||
d->breakpoints.remove(id);
|
d->breakpoints.remove(id);
|
||||||
|
|
||||||
if (handler->breakpointData(id).type == BreakpointAtJavaScriptThrow) {
|
if (params.type == BreakpointAtJavaScriptThrow)
|
||||||
d->setExceptionBreak(AllExceptions);
|
d->setExceptionBreak(AllExceptions);
|
||||||
|
else if (params.type == BreakpointOnQmlSignalHandler)
|
||||||
} else if (handler->breakpointData(id).type == BreakpointOnQmlSignalHandler) {
|
d->setBreakpoint(QString(_(EVENT)), params.functionName, false);
|
||||||
d->setBreakpoint(QString(_(EVENT)), handler->breakpointData(id).functionName,
|
else
|
||||||
-1, -1, false);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
d->clearBreakpoint(breakpoint);
|
d->clearBreakpoint(breakpoint);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void QmlV8DebuggerClient::changeBreakpoint(const BreakpointModelId &id)
|
void QmlV8DebuggerClient::changeBreakpoint(const BreakpointModelId &id)
|
||||||
{
|
{
|
||||||
@@ -1133,9 +1134,8 @@ void QmlV8DebuggerClient::changeBreakpoint(const BreakpointModelId &id)
|
|||||||
if (params.type == BreakpointAtJavaScriptThrow) {
|
if (params.type == BreakpointAtJavaScriptThrow) {
|
||||||
d->setExceptionBreak(AllExceptions, params.enabled);
|
d->setExceptionBreak(AllExceptions, params.enabled);
|
||||||
|
|
||||||
} else if (handler->breakpointData(id).type == BreakpointOnQmlSignalHandler) {
|
} else if (params.type == BreakpointOnQmlSignalHandler) {
|
||||||
d->setBreakpoint(QString(_(EVENT)), params.functionName,
|
d->setBreakpoint(QString(_(EVENT)), params.functionName, params.enabled);
|
||||||
-1, -1, params.enabled);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int breakpoint = d->breakpoints.value(id);
|
int breakpoint = d->breakpoints.value(id);
|
||||||
@@ -1311,8 +1311,15 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data)
|
|||||||
BreakpointModelId id = d->breakpointsSync.take(seq);
|
BreakpointModelId id = d->breakpointsSync.take(seq);
|
||||||
d->breakpoints.insert(id, index);
|
d->breakpoints.insert(id, index);
|
||||||
|
|
||||||
if (d->engine->breakHandler()->state(id) != BreakpointInserted)
|
BreakHandler *handler = d->engine->breakHandler();
|
||||||
d->engine->breakHandler()->notifyBreakpointInsertOk(id);
|
if (handler->state(id) != BreakpointInserted) {
|
||||||
|
BreakpointResponse br = handler->response(id);
|
||||||
|
br.lineNumber = breakpointData.value(_("line")
|
||||||
|
).toInt() + 1;
|
||||||
|
handler->setResponse(id, br);
|
||||||
|
handler->notifyBreakpointInsertOk(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
d->breakpointsTemp.append(index);
|
d->breakpointsTemp.append(index);
|
||||||
@@ -1450,12 +1457,11 @@ void QmlV8DebuggerClient::messageReceived(const QByteArray &data)
|
|||||||
const BreakpointParameters ¶ms = handler->breakpointData(internalId);
|
const BreakpointParameters ¶ms = handler->breakpointData(internalId);
|
||||||
|
|
||||||
d->clearBreakpoint(v8Id);
|
d->clearBreakpoint(v8Id);
|
||||||
d->setBreakpoint(
|
d->setBreakpoint(QString(_(SCRIPTREGEXP)),
|
||||||
QString(_(SCRIPTREGEXP)),
|
params.fileName,
|
||||||
QFileInfo(params.fileName).fileName(),
|
|
||||||
params.lineNumber - 1,
|
|
||||||
newColumn,
|
|
||||||
params.enabled,
|
params.enabled,
|
||||||
|
params.lineNumber,
|
||||||
|
newColumn,
|
||||||
QString(params.condition),
|
QString(params.condition),
|
||||||
params.ignoreCount);
|
params.ignoreCount);
|
||||||
d->breakpointsSync.insert(d->sequence, internalId);
|
d->breakpointsSync.insert(d->sequence, internalId);
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ public:
|
|||||||
void activateFrame(int index);
|
void activateFrame(int index);
|
||||||
|
|
||||||
bool acceptsBreakpoint(const BreakpointModelId &id);
|
bool acceptsBreakpoint(const BreakpointModelId &id);
|
||||||
void insertBreakpoint(const BreakpointModelId &id);
|
void insertBreakpoint(const BreakpointModelId &id, int adjustedLine,
|
||||||
|
int adjustedColumn = -1);
|
||||||
void removeBreakpoint(const BreakpointModelId &id);
|
void removeBreakpoint(const BreakpointModelId &id);
|
||||||
void changeBreakpoint(const BreakpointModelId &id);
|
void changeBreakpoint(const BreakpointModelId &id);
|
||||||
void synchronizeBreakpoints();
|
void synchronizeBreakpoints();
|
||||||
|
|||||||
@@ -119,12 +119,13 @@ class QScriptDebuggerClientPrivate
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit QScriptDebuggerClientPrivate(QScriptDebuggerClient *) :
|
explicit QScriptDebuggerClientPrivate(QScriptDebuggerClient *) :
|
||||||
ping(0), engine(0)
|
ping(0), sessionStarted(false), engine(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ping;
|
int ping;
|
||||||
|
bool sessionStarted;
|
||||||
QmlEngine *engine;
|
QmlEngine *engine;
|
||||||
JSAgentBreakpoints breakpoints;
|
JSAgentBreakpoints breakpoints;
|
||||||
|
|
||||||
@@ -225,10 +226,12 @@ void QScriptDebuggerClient::startSession()
|
|||||||
QTC_CHECK(handler->state(id) == BreakpointInsertProceeding);
|
QTC_CHECK(handler->state(id) == BreakpointInsertProceeding);
|
||||||
handler->notifyBreakpointInsertOk(id);
|
handler->notifyBreakpointInsertOk(id);
|
||||||
}
|
}
|
||||||
|
d->sessionStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QScriptDebuggerClient::endSession()
|
void QScriptDebuggerClient::endSession()
|
||||||
{
|
{
|
||||||
|
d->sessionStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QScriptDebuggerClient::activateFrame(int index)
|
void QScriptDebuggerClient::activateFrame(int index)
|
||||||
@@ -242,14 +245,22 @@ void QScriptDebuggerClient::activateFrame(int index)
|
|||||||
sendMessage(reply);
|
sendMessage(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QScriptDebuggerClient::insertBreakpoint(const BreakpointModelId &id)
|
void QScriptDebuggerClient::insertBreakpoint(const BreakpointModelId &id,
|
||||||
|
int adjustedLine,
|
||||||
|
int /*adjustedColumn*/)
|
||||||
{
|
{
|
||||||
BreakHandler *handler = d->engine->breakHandler();
|
BreakHandler *handler = d->engine->breakHandler();
|
||||||
JSAgentBreakpointData bp;
|
JSAgentBreakpointData bp;
|
||||||
bp.fileUrl = QUrl::fromLocalFile(handler->fileName(id)).toString().toUtf8();
|
bp.fileUrl = QUrl::fromLocalFile(handler->fileName(id)).toString().toUtf8();
|
||||||
bp.lineNumber = handler->lineNumber(id);
|
bp.lineNumber = adjustedLine;
|
||||||
bp.functionName = handler->functionName(id).toUtf8();
|
bp.functionName = handler->functionName(id).toUtf8();
|
||||||
d->breakpoints.insert(bp);
|
d->breakpoints.insert(bp);
|
||||||
|
|
||||||
|
BreakpointResponse br = handler->response(id);
|
||||||
|
br.lineNumber = adjustedLine;
|
||||||
|
handler->setResponse(id, br);
|
||||||
|
if (d->sessionStarted && handler->state(id) == BreakpointInsertProceeding)
|
||||||
|
handler->notifyBreakpointInsertOk(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QScriptDebuggerClient::removeBreakpoint(const BreakpointModelId &id)
|
void QScriptDebuggerClient::removeBreakpoint(const BreakpointModelId &id)
|
||||||
@@ -266,7 +277,8 @@ void QScriptDebuggerClient::changeBreakpoint(const BreakpointModelId &id)
|
|||||||
{
|
{
|
||||||
BreakHandler *handler = d->engine->breakHandler();
|
BreakHandler *handler = d->engine->breakHandler();
|
||||||
if (handler->isEnabled(id)) {
|
if (handler->isEnabled(id)) {
|
||||||
insertBreakpoint(id);
|
BreakpointResponse br = handler->response(id);
|
||||||
|
insertBreakpoint(id, br.lineNumber);
|
||||||
} else {
|
} else {
|
||||||
removeBreakpoint(id);
|
removeBreakpoint(id);
|
||||||
}
|
}
|
||||||
@@ -461,33 +473,12 @@ void QScriptDebuggerClient::messageReceived(const QByteArray &data)
|
|||||||
.arg(QLatin1String(stackFrames.value(0).fileUrl), Qt::escape(error));
|
.arg(QLatin1String(stackFrames.value(0).fileUrl), Qt::escape(error));
|
||||||
showMessageBox(QMessageBox::Information, tr("Uncaught Exception"), msg);
|
showMessageBox(QMessageBox::Information, tr("Uncaught Exception"), msg);
|
||||||
} else {
|
} else {
|
||||||
//
|
|
||||||
// Make breakpoint non-pending
|
|
||||||
//
|
|
||||||
QString file;
|
QString file;
|
||||||
QString function;
|
|
||||||
int line = -1;
|
int line = -1;
|
||||||
|
|
||||||
if (!ideStackFrames.isEmpty()) {
|
if (!ideStackFrames.isEmpty()) {
|
||||||
file = ideStackFrames.at(0).file;
|
file = ideStackFrames.at(0).file;
|
||||||
line = ideStackFrames.at(0).line;
|
line = ideStackFrames.at(0).line;
|
||||||
function = ideStackFrames.at(0).function;
|
|
||||||
}
|
|
||||||
|
|
||||||
BreakHandler *handler = d->engine->breakHandler();
|
|
||||||
foreach (BreakpointModelId id, handler->engineBreakpointIds(d->engine)) {
|
|
||||||
QString processedFilename = handler->fileName(id);
|
|
||||||
|
|
||||||
if (processedFilename == file && handler->lineNumber(id) == line) {
|
|
||||||
if (handler->state(id) == BreakpointInsertProceeding)
|
|
||||||
handler->notifyBreakpointInsertOk(id);
|
|
||||||
QTC_CHECK(handler->state(id) == BreakpointInserted);
|
|
||||||
BreakpointResponse br = handler->response(id);
|
|
||||||
br.fileName = file;
|
|
||||||
br.lineNumber = line;
|
|
||||||
br.functionName = function;
|
|
||||||
handler->setResponse(id, br);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<JSAgentBreakpointData> breakpoints(d->breakpoints.toList());
|
QList<JSAgentBreakpointData> breakpoints(d->breakpoints.toList());
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ public:
|
|||||||
|
|
||||||
void activateFrame(int index);
|
void activateFrame(int index);
|
||||||
|
|
||||||
void insertBreakpoint(const BreakpointModelId &id);
|
void insertBreakpoint(const BreakpointModelId &id, int adjustedLine,
|
||||||
|
int adjustedColumn = -1);
|
||||||
void removeBreakpoint(const BreakpointModelId &id);
|
void removeBreakpoint(const BreakpointModelId &id);
|
||||||
void changeBreakpoint(const BreakpointModelId &id);
|
void changeBreakpoint(const BreakpointModelId &id);
|
||||||
void synchronizeBreakpoints();
|
void synchronizeBreakpoints();
|
||||||
|
|||||||
Reference in New Issue
Block a user