Fix file and line number reporting of QML/JS errors

* Replace QUrl with QString in V4 for the source location (we don't need URL parsing)
* Replace line number and file in QV4::Exception with the information we retrieve from
  the stack trace of the exception.

Fixes about five tst_qqmlecmascript tests that relied on correct file/line number information

Change-Id: I2a3daa72be6c5587fd965211ea8f6fb77142e7ee
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Simon Hausmann 2013-05-27 14:19:35 +02:00 committed by Lars Knoll
parent 8a822866b6
commit 6b5c964caa
28 changed files with 53 additions and 55 deletions

View File

@ -111,7 +111,7 @@ public Q_SLOTS:
QVector<QV4::ExecutionEngine::StackFrame> stack = v4->stackTrace(frameIndex + 1);
if (stack.size() > frameIndex)
return QQmlV4Handle(QV4::Value::fromString(v4->newString(stack.at(frameIndex).source.url())));
return QQmlV4Handle(QV4::Value::fromString(v4->newString(stack.at(frameIndex).source)));
return QQmlV4Handle();
}
int callerLine(int frameIndex = 0) const

View File

@ -79,8 +79,13 @@ void QQmlDelayedError::setErrorDescription(const QString &description)
void QQmlDelayedError::setError(const QV4::Exception &e)
{
m_error.setDescription(e.value().toQString());
m_error.setUrl(e.file());
m_error.setLine(e.lineNumber());
QV4::ExecutionEngine::StackTrace trace = e.stackTrace();
if (!trace.isEmpty()) {
QV4::ExecutionEngine::StackFrame frame = trace.first();
m_error.setUrl(QUrl(frame.source));
m_error.setLine(frame.line);
}
m_error.setColumn(-1);
}
@ -181,8 +186,7 @@ QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
*isUndefined = true;
if (!watcher.wasDeleted()) {
if (!e.value().isEmpty()) {
// ### line number
delayedError()->setErrorDescription(e.value().toQString());
delayedError()->setError(e);
} else {
if (hasDelayedError()) delayedError()->clearError();
}
@ -300,9 +304,13 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
void QQmlJavaScriptExpression::exceptionToError(const QV4::Exception &e, QQmlError &error)
{
error.setUrl(e.file());
error.setLine(e.lineNumber());
error.setColumn(-1);
QV4::ExecutionEngine::StackTrace trace = e.stackTrace();
if (!trace.isEmpty()) {
QV4::ExecutionEngine::StackFrame frame = trace.first();
error.setUrl(QUrl(frame.source));
error.setLine(frame.line);
error.setColumn(-1);
}
error.setDescription(e.value().toQString());
}

View File

@ -1445,12 +1445,12 @@ void QQmlXMLHttpRequest::dispatchCallback(const QV4::Value &me)
QV4::Object *o = me.asObject();
if (!o)
__qmljs_throw(ctx, QV4::Value::fromObject(
v4->newErrorObject(QV4::Value::fromString(ctx, QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")))), -1);
v4->newErrorObject(QV4::Value::fromString(ctx, QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")))));
QV4::Object *thisObj = o->get(v4->newString(QStringLiteral("ThisObject"))).asObject();
if (!thisObj)
__qmljs_throw(ctx, QV4::Value::fromObject(
v4->newErrorObject(QV4::Value::fromString(ctx, QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")))), -1);
v4->newErrorObject(QV4::Value::fromString(ctx, QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")))));
QV4::FunctionObject *callback = thisObj->get(v4->newString(QStringLiteral("onreadystatechange"))).asFunctionObject();
if (!callback) {

View File

@ -472,7 +472,7 @@ void __qmljs_llvm_typeof(ExecutionContext *ctx, Value *result, const Value *valu
void __qmljs_llvm_throw(ExecutionContext *context, Value *value)
{
__qmljs_throw(context, *value, -1);
__qmljs_throw(context, *value);
}
void __qmljs_llvm_delete_exception_handler(ExecutionContext *context)

View File

@ -249,7 +249,6 @@ union Instr
struct instr_callBuiltinThrow {
MOTH_INSTR_HEADER
Param arg;
int line;
};
struct instr_callBuiltinFinishTry {
MOTH_INSTR_HEADER

View File

@ -674,11 +674,10 @@ void InstructionSelection::callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR
addInstruction(call);
}
void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg, int line)
void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg)
{
Instruction::CallBuiltinThrow call;
call.arg = getParam(arg);
call.line = line;
addInstruction(call);
}

View File

@ -45,7 +45,7 @@ protected:
virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result);
virtual void callBuiltinThrow(V4IR::Temp *arg, int line);
virtual void callBuiltinThrow(V4IR::Temp *arg);
virtual void callBuiltinFinishTry();
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);

View File

@ -308,7 +308,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
MOTH_END_INSTR(CallActivationProperty)
MOTH_BEGIN_INSTR(CallBuiltinThrow)
__qmljs_throw(context, VALUE(instr.arg), instr.line);
__qmljs_throw(context, VALUE(instr.arg));
MOTH_END_INSTR(CallBuiltinThrow)
MOTH_BEGIN_INSTR(EnterTry)

View File

@ -2588,7 +2588,7 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
enterEnvironment(ast);
V4IR::Function *function = _module->newFunction(name, _function);
function->sourceFile = QUrl::fromLocalFile(_fileName);
function->sourceFile = _fileName;
if (_debugger)
_debugger->addFunction(function);

View File

@ -302,7 +302,7 @@ void ExecutionContext::mark()
}
}
QUrl ExecutionContext::currentFileName() const
QString ExecutionContext::currentFileName() const
{
const ExecutionContext *c = this;
while (c) {
@ -313,7 +313,7 @@ QUrl ExecutionContext::currentFileName() const
}
c = c->outer;
}
return QUrl();
return QString();
}
int ExecutionContext::currentLineNumber() const
@ -564,8 +564,7 @@ void ExecutionContext::inplaceBitOp(String *name, const Value &value, BinOp op)
void ExecutionContext::throwError(const Value &value)
{
// ### line number???
__qmljs_throw(this, value, -1);
__qmljs_throw(this, value);
}
void ExecutionContext::throwError(const QString &message)

View File

@ -144,7 +144,7 @@ struct Q_QML_EXPORT ExecutionContext
void mark();
QUrl currentFileName() const;
QString currentFileName() const;
int currentLineNumber() const;
inline CallContext *asCallContext();

View File

@ -796,11 +796,9 @@ Function *ExecutionEngine::functionForProgramCounter(quintptr pc) const
return 0;
}
Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionValue, int line)
Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionValue)
: exception(exceptionValue)
, m_line(line)
{
m_file = throwingContext->currentFileName();
this->throwingContext = throwingContext->engine->current;
accepted = false;
m_stackTrace = throwingContext->engine->stackTrace();

View File

@ -274,7 +274,7 @@ struct Q_QML_EXPORT ExecutionEngine
Object *qmlContextObject() const;
struct StackFrame {
QUrl source;
QString source;
QString function;
int line;
int column;
@ -314,7 +314,7 @@ inline ExecutionContext *ExecutionEngine::popContext()
}
struct Q_QML_EXPORT Exception {
explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue, int line);
explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue);
~Exception();
void accept(ExecutionContext *catchingContext);
@ -322,8 +322,6 @@ struct Q_QML_EXPORT Exception {
void partiallyUnwindContext(ExecutionContext *catchingContext);
Value value() const { return exception; }
QUrl file() const { return m_file; }
int lineNumber() const { return m_line; }
ExecutionEngine::StackTrace stackTrace() const { return m_stackTrace; }
@ -331,8 +329,6 @@ private:
ExecutionContext *throwingContext;
bool accepted;
PersistentValue exception;
QUrl m_file;
int m_line;
ExecutionEngine::StackTrace m_stackTrace;
};

View File

@ -109,7 +109,7 @@ struct Function {
bool isStrict;
bool isNamedExpression;
QUrl sourceFile;
QString sourceFile;
QVector<LineNumberMapping> lineNumberMappings;
Function(String *name)

View File

@ -755,9 +755,9 @@ void InstructionSelection::callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR
Assembler::PointerToValue(result), Assembler::PointerToValue(value));
}
void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg, int line)
void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg)
{
generateFunctionCall(Assembler::Void, __qmljs_throw, Assembler::ContextRegister, Assembler::Reference(arg), Assembler::TrustedImm32(line));
generateFunctionCall(Assembler::Void, __qmljs_throw, Assembler::ContextRegister, Assembler::Reference(arg));
}
typedef void *(*MiddleOfFunctionEntryPoint(ExecutionContext *, void *localsPtr));

View File

@ -780,7 +780,7 @@ protected:
virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result);
virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result);
virtual void callBuiltinThrow(V4IR::Temp *arg, int line);
virtual void callBuiltinThrow(V4IR::Temp *arg);
virtual void callBuiltinFinishTry();
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);

View File

@ -310,7 +310,7 @@ void InstructionSelection::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
case V4IR::Name::builtin_throw: {
V4IR::Temp *arg = call->args->expr->asTemp();
assert(arg != 0);
callBuiltinThrow(arg, baseName->line);
callBuiltinThrow(arg);
} return;
case V4IR::Name::builtin_finish_try:

View File

@ -115,7 +115,7 @@ public: // to implement by subclasses:
virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result) = 0;
virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result) = 0;
virtual void callBuiltinThrow(V4IR::Temp *arg, int line) = 0;
virtual void callBuiltinThrow(V4IR::Temp *arg) = 0;
virtual void callBuiltinFinishTry() = 0;
virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result) = 0;
virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result) = 0;

View File

@ -671,7 +671,7 @@ struct Function {
QVector<Function *> nestedFunctions;
Function *outer;
QUrl sourceFile;
QString sourceFile;
int insideWithOrCatch;

View File

@ -917,7 +917,7 @@ void __qmljs_construct_property(ExecutionContext *context, Value *result, const
context->throwTypeError();
}
void __qmljs_throw(ExecutionContext *context, const Value &value, int line)
void __qmljs_throw(ExecutionContext *context, const Value &value)
{
if (context->engine->debugger)
context->engine->debugger->aboutToThrow(value);
@ -944,7 +944,7 @@ void __qmljs_throw(ExecutionContext *context, const Value &value, int line)
printf("stack walked. throwing exception now...\n");
#endif
throw Exception(context, value, line);
throw Exception(context, value);
}
void __qmljs_builtin_typeof(ExecutionContext *ctx, Value *result, const Value &value)

View File

@ -189,7 +189,7 @@ void __qmljs_delete_subscript(QV4::ExecutionContext *ctx, QV4::Value *result, co
void __qmljs_delete_member(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &base, QV4::String *name);
void __qmljs_delete_name(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::String *name);
void Q_NORETURN __qmljs_throw(QV4::ExecutionContext*, const QV4::Value &value, int line);
void Q_NORETURN __qmljs_throw(QV4::ExecutionContext*, const QV4::Value &value);
// binary operators
typedef void (*BinOp)(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);

View File

@ -162,7 +162,7 @@ void Script::parse()
if (!vmFunction)
// ### FIX file/line number
__qmljs_throw(v4->current, QV4::Value::fromObject(v4->newSyntaxErrorObject(v4->current, 0)), -1);
__qmljs_throw(v4->current, QV4::Value::fromObject(v4->newSyntaxErrorObject(v4->current, 0)));
}
Value Script::run()

View File

@ -60,7 +60,7 @@ static void generateWarning(QV4::ExecutionContext *ctx, const QString& descripti
QQmlError retn;
retn.setDescription(description);
retn.setLine(ctx->currentLineNumber());
retn.setUrl(ctx->currentFileName());
retn.setUrl(QUrl(ctx->currentFileName()));
QQmlEnginePrivate::warning(engine, retn);
}

View File

@ -1392,7 +1392,7 @@ ObjectTemplate::ObjectTemplate()
Handle<Value> ThrowException(Handle<Value> exception)
{
__qmljs_throw(currentEngine()->current, exception->v4Value(), -1);
__qmljs_throw(currentEngine()->current, exception->v4Value());
return Handle<Value>();
}

View File

@ -81,7 +81,6 @@ struct StaticQtMetaObject : public QObject
{ return &staticQtMetaObject; }
};
QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
: Object(v4)
, m_platform(0)
@ -1307,7 +1306,7 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
QString stackFrame =
QString::fromLatin1("%1 (%2:%3:%4)\n").arg(frame.function,
frame.source.url(),
frame.source,
QString::number(frame.line),
QString::number(frame.column));
stack += stackFrame;
@ -1335,7 +1334,7 @@ static QV4::Value writeToConsole(ConsoleLogTypes logType, SimpleCallContext *ctx
}
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
switch (logType) {
case Log:
logger.debug("%s", qPrintable(result));
@ -1376,7 +1375,7 @@ QV4::Value ConsoleObject::method_profile(SimpleCallContext *ctx)
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
if (QQmlProfilerService::startProfiling()) {
QV8ProfilerService::instance()->startProfiling(title);
@ -1398,7 +1397,7 @@ QV4::Value ConsoleObject::method_profileEnd(SimpleCallContext *ctx)
QV4::ExecutionEngine *v4 = ctx->engine;
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
if (QQmlProfilerService::stopProfiling()) {
QV8ProfilerService *profiler = QV8ProfilerService::instance();
@ -1454,7 +1453,7 @@ QV4::Value ConsoleObject::method_count(SimpleCallContext *ctx)
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
QString scriptName = frame.source.url();
QString scriptName = frame.source;
int value = v8engine->consoleCountHelper(scriptName, frame.line, frame.column);
QString message = name + QLatin1String(": ") + QString::number(value);
@ -1475,7 +1474,7 @@ QV4::Value ConsoleObject::method_trace(SimpleCallContext *ctx)
QString stack = jsStack(v4);
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
logger.debug("%s", qPrintable(stack));
return QV4::Value::undefinedValue();
@ -1505,7 +1504,7 @@ QV4::Value ConsoleObject::method_assert(SimpleCallContext *ctx)
QString stack = jsStack(v4);
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
logger.critical("%s\n%s", qPrintable(message), qPrintable(stack));
}

View File

@ -696,7 +696,7 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
newBinding = new QQmlBinding(function->v4Value(), object, context, frame.source.url(),
newBinding = new QQmlBinding(function->v4Value(), object, context, frame.source,
qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
newBinding->setTarget(object, *property, context);
newBinding->setEvaluateFlags(newBinding->evaluateFlags() |

View File

@ -397,7 +397,7 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Handle<v8::String> propert
QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
newBinding = new QQmlBinding(function->v4Value(), reference->object, context,
frame.source.url(), qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
frame.source, qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
newBinding->setTarget(reference->object, cacheData, context);
newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
QQmlBinding::RequiresThisObject);

View File

@ -142,7 +142,7 @@ static void showException(QV4::ExecutionContext *ctx, const QV4::Exception &exce
}
foreach (const QV4::ExecutionEngine::StackFrame &frame, exception.stackTrace()) {
std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source.toLocalFile());
std::cerr << " at " << qPrintable(frame.function) << " (" << qPrintable(frame.source);
if (frame.line >= 0)
std::cerr << ":" << frame.line;
std::cerr << ")" << std::endl;