aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qv4codegen.cpp37
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp68
2 files changed, 77 insertions, 28 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index a10c0730bf..fcfbdfa74b 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -92,6 +92,27 @@ static bool cjumpCanHandle(IR::AluOp op)
}
}
+static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body,
+ const SourceLocation &fallback)
+{
+ switch (body->kind) {
+ // Statements where we might never execute the last line.
+ // Use the fallback.
+ case Statement::Kind_ConditionalExpression:
+ case Statement::Kind_ForEachStatement:
+ case Statement::Kind_ForStatement:
+ case Statement::Kind_IfStatement:
+ case Statement::Kind_LocalForEachStatement:
+ case Statement::Kind_LocalForStatement:
+ case Statement::Kind_WhileStatement:
+ setLocation(s, fallback);
+ break;
+ default:
+ setLocation(s, body->lastSourceLocation());
+ break;
+ }
+}
+
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
@@ -2256,7 +2277,7 @@ bool Codegen::visit(DoWhileStatement *ast)
_block = loopbody;
statement(ast->statement);
- setLocation(_block->JUMP(loopcond), ast->statement->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(loopcond), ast->statement, ast->semicolonToken);
_block = loopcond;
condition(ast->expression, loopbody, loopend);
@@ -2321,7 +2342,7 @@ bool Codegen::visit(ForEachStatement *ast)
return false;
move(*init, _block->TEMP(temp));
statement(ast->statement);
- setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken);
_block = foreachin;
@@ -2360,7 +2381,7 @@ bool Codegen::visit(ForStatement *ast)
_block = forbody;
statement(ast->statement);
- setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken);
_block = forstep;
statement(ast->expression);
@@ -2386,12 +2407,12 @@ bool Codegen::visit(IfStatement *ast)
_block = iftrue;
statement(ast->ok);
- _block->JUMP(endif);
+ setJumpOutLocation(_block->JUMP(endif), ast->ok, ast->ifToken);
if (ast->ko) {
_block = iffalse;
statement(ast->ko);
- _block->JUMP(endif);
+ setJumpOutLocation(_block->JUMP(endif), ast->ko, ast->elseToken);
}
_block = endif;
@@ -2460,7 +2481,7 @@ bool Codegen::visit(LocalForEachStatement *ast)
int temp = _block->newTemp();
move(identifier(ast->declaration->name.toString()), _block->TEMP(temp));
statement(ast->statement);
- setLocation(_block->JUMP(foreachin), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken);
_block = foreachin;
@@ -2499,7 +2520,7 @@ bool Codegen::visit(LocalForStatement *ast)
_block = forbody;
statement(ast->statement);
- setLocation(_block->JUMP(forstep), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken);
_block = forstep;
statement(ast->expression);
@@ -2800,7 +2821,7 @@ bool Codegen::visit(WhileStatement *ast)
_block = whilebody;
statement(ast->statement);
- setLocation(_block->JUMP(whilecond), ast->lastSourceLocation());
+ setJumpOutLocation(_block->JUMP(whilecond), ast->statement, ast->whileToken);
_block = whileend;
leaveLoop();
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index 6d0d884ed7..584bd10151 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -315,8 +315,8 @@ private slots:
void stepToEndOfScript_data() { redundancy_data(); }
void stepToEndOfScript();
- void lastLineOfLoop_data();
- void lastLineOfLoop();
+ void lastLineOfConditional_data();
+ void lastLineOfConditional();
private:
QV4Debugger *debugger() const
{
@@ -801,32 +801,60 @@ void tst_qv4debugger::stepToEndOfScript()
QCOMPARE(state.lineNumber, -4); // A return instruction without proper line number.
}
-void tst_qv4debugger::lastLineOfLoop_data()
+void tst_qv4debugger::lastLineOfConditional_data()
{
- QTest::addColumn<QString>("loopHead");
- QTest::addColumn<QString>("loopTail");
-
- QTest::newRow("for") << "for (var i = 0; i < 10; ++i) {\n" << "}\n";
- QTest::newRow("for..in") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}\n";
- QTest::newRow("while") << "while (ret < 10) {\n" << "}\n";
- QTest::newRow("do..while") << "do {\n" << "} while (ret < 10);\n";
+ QTest::addColumn<QString>("head");
+ QTest::addColumn<QString>("tail");
+ QTest::addColumn<int>("breakPoint");
+ QTest::addColumn<int>("lastLine");
+
+ QTest::newRow("for {block}") << "for (var i = 0; i < 10; ++i) {\n" << "}" << 4 << 7;
+ QTest::newRow("for..in {block}") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}" << 4 << 7;
+ QTest::newRow("while {block}") << "while (ret < 10) {\n" << "}" << 4 << 7;
+ QTest::newRow("do..while {block}") << "do {\n" << "} while (ret < 10);" << 4 << 7;
+
+ QTest::newRow("if true {block}") << "if (true) {\n" << "}"
+ << 4 << 7;
+ QTest::newRow("if false {block}") << "if (false) {\n" << "}"
+ << 2 << 8;
+ QTest::newRow("if true else {block}") << "if (true) {\n" << "} else {\n ret += 8;\n}"
+ << 4 << 7;
+ QTest::newRow("if false else {block}") << "if (false) {\n" << "} else {\n ret += 8;\n}"
+ << 8 << 9;
+
+ QTest::newRow("for statement") << "for (var i = 0; i < 10; ++i)\n" << "" << 4 << 2;
+ QTest::newRow("for..in statement") << "for (var i in [0, 1, 2, 3, 4])\n" << "" << 4 << 2;
+ QTest::newRow("while statement") << "while (ret < 10)\n" << "" << 4 << 2;
+ QTest::newRow("do..while statement") << "do\n" << "while (ret < 10);" << 4 << 7;
+
+ // For two nested if statements without blocks, we need to map the jump from the inner to the
+ // outer one on the outer "if". There is just no better place.
+ QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 2;
+ QTest::newRow("if false statement") << "if (false)\n" << "" << 2 << 8;
+
+ // Also two nested ifs without blocks.
+ QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 2;
+ QTest::newRow("if false else statement") << "if (false)\n" << "else\n ret += 8;" << 8 << 9;
}
-void tst_qv4debugger::lastLineOfLoop()
+void tst_qv4debugger::lastLineOfConditional()
{
- QFETCH(QString, loopHead);
- QFETCH(QString, loopTail);
+ QFETCH(QString, head);
+ QFETCH(QString, tail);
+ QFETCH(int, breakPoint);
+ QFETCH(int, lastLine);
QString script =
- "var ret = 0;\n"
- + loopHead +
+ "var ret = 2;\n"
+ + head +
" if (ret == 2)\n"
" ret += 4;\n" // breakpoint, then step over
- " else \n"
+ " else\n"
" ret += 1;\n"
- + loopTail;
+ + tail + "\n" +
+ "ret -= 5;";
- debugger()->addBreakPoint("trueBranch", 4);
+ debugger()->addBreakPoint("trueBranch", breakPoint);
m_debuggerAgent->m_resumeSpeed = QV4Debugger::StepOver;
evaluateJavaScript(script, "trueBranch");
QVERIFY(m_debuggerAgent->m_wasPaused);
@@ -834,10 +862,10 @@ void tst_qv4debugger::lastLineOfLoop()
QVERIFY(m_debuggerAgent->m_statesWhenPaused.count() > 1);
QV4Debugger::ExecutionState firstState = m_debuggerAgent->m_statesWhenPaused.first();
QCOMPARE(firstState.fileName, QString("trueBranch"));
- QCOMPARE(firstState.lineNumber, 4);
+ QCOMPARE(firstState.lineNumber, breakPoint);
QV4Debugger::ExecutionState secondState = m_debuggerAgent->m_statesWhenPaused.at(1);
QCOMPARE(secondState.fileName, QString("trueBranch"));
- QCOMPARE(secondState.lineNumber, 7);
+ QCOMPARE(secondState.lineNumber, lastLine);
}
void tst_qv4debugger::redundancy_data()