void tst_qqmlexpression::scriptString() { qmlRegisterType<TestObject>("Test", 1, 0, "TestObject"); QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("scriptString.qml")); TestObject *testObj = qobject_cast<TestObject*>(c.create()); QVERIFY(testObj != 0); QQmlScriptString script = testObj->scriptString(); QVERIFY(!script.isEmpty()); QQmlExpression expression(script); QVariant value = expression.evaluate(); QCOMPARE(value.toInt(), 15); QQmlScriptString scriptError = testObj->scriptStringError(); QVERIFY(!scriptError.isEmpty()); //verify that the expression has the correct error location information QQmlExpression expressionError(scriptError); QVariant valueError = expressionError.evaluate(); QVERIFY(!valueError.isValid()); QVERIFY(expressionError.hasError()); QQmlError error = expressionError.error(); QCOMPARE(error.url(), c.url()); QCOMPARE(error.line(), 8); }
/*! Reports an error with the given \a description. An error is generated referring to the \a location in the source file. */ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; error.setLine(location.line); error.setColumn(location.column); error.setDescription(description); exceptions << error; }
static QString qmlErrorToString(const QQmlError &error) { return QStringLiteral("%1:%2:%3: %4") .arg(error.url().toString()) .arg(error.line()) .arg(error.column()) .arg(error.description()); }
void QmcTypeCompiler::recordError(const QV4::CompiledData::Location& location, const QString& description) { QQmlError error; error.setLine(location.line); error.setColumn(location.column); error.setUrl(compiledData->url); error.setDescription(description); recordError(error); }
CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors) { using namespace QQmlJS; using namespace QQmlJS::AST; QQmlJS::V4IR::Module module(engine->debugger != 0); QQmlJS::Engine ee; QQmlJS::Lexer lexer(&ee); lexer.setCode(source, /*line*/1, /*qml mode*/true); QQmlJS::Parser parser(&ee); parser.parseProgram(); QList<QQmlError> errors; foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) { if (m.isWarning()) { qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message)); continue; } QQmlError error; error.setUrl(url); error.setDescription(m.message); error.setLine(m.loc.startLine); error.setColumn(m.loc.startColumn); errors << error; } if (!errors.isEmpty()) { if (reportedErrors) *reportedErrors << errors; return 0; } Program *program = AST::cast<Program *>(parser.rootNode()); if (!program) { // if parsing was successful, and we have no program, then // we're done...: return 0; } QQmlJS::Codegen cg(/*strict mode*/false); cg.generateFromProgram(url.toString(), source, program, &module, QQmlJS::Codegen::EvalCode); errors = cg.errors(); if (!errors.isEmpty()) { if (reportedErrors) *reportedErrors << cg.errors(); return 0; } Compiler::JSUnitGenerator jsGenerator(&module); QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, &module, &jsGenerator)); isel->setUseFastLookups(false); return isel->compile(); }
foreach(QQmlError warning, warnings) { QString url; if (warning.url().isLocalFile()) url = warning.url().toLocalFile(); else url = warning.url().toString(); qCWarning(sambaLogQml, "%s:%d: %s", url.toLocal8Bit().constData(), warning.line(), warning.description().toLocal8Bit().constData()); }
QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, QObject *qmlScope, const QString &code, const QString &filename, quint16 line, QV4::PersistentValue *qmlscope) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); QV4::ExecutionContext *ctx = v4->currentContext(); QV4::Scope scope(v4); QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, qmlScope)); QV4::Script script(v4, qmlScopeObject, code, filename, line); QV4::ScopedValue result(scope); script.parse(); if (!v4->hasException) result = script.qmlBinding(); if (v4->hasException) { QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx); if (error.description().isEmpty()) error.setDescription(QLatin1String("Exception occurred during function evaluation")); if (error.line() == -1) error.setLine(line); if (error.url().isEmpty()) error.setUrl(QUrl::fromLocalFile(filename)); error.setObject(qmlScope); ep->warning(error); return QV4::Encode::undefined(); } if (qmlscope) *qmlscope = qmlScopeObject; return result.asReturnedValue(); }
QList<QQmlError> QQmlDirParser::errors(const QString &uri) const { QUrl url(uri); QList<QQmlError> errors; for (int i = 0; i < _errors.size(); ++i) { const QQmlJS::DiagnosticMessage &msg = _errors.at(i); QQmlError e; QString description = msg.message; description.replace(QLatin1String("$$URI$$"), uri); e.setDescription(description); e.setUrl(url); e.setLine(msg.loc.startLine); e.setColumn(msg.loc.startColumn); errors << e; } return errors; }
bool Compiler::compile(const QString &url, const QString &outputFile) { // open output file QFile f(outputFile); if (!f.open(QFile::WriteOnly | QFile::Truncate)) { QQmlError error; error.setDescription("Could not open file for writing"); error.setUrl(QUrl(outputFile)); return false; } QDataStream out(&f); bool ret = compile(url, out); f.close(); return ret; }
void QQuickWindowQmlImpl::setWindowVisibility() { Q_D(QQuickWindowQmlImpl); if (transientParent() && !transientParent()->isVisible()) return; if (sender()) { disconnect(transientParent(), &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::setWindowVisibility); } // We have deferred window creation until we have the full picture of what // the user wanted in terms of window state, geometry, visibility, etc. if ((d->visibility == Hidden && d->visible) || (d->visibility > AutomaticVisibility && !d->visible)) { QQmlData *data = QQmlData::get(this); Q_ASSERT(data && data->context); QQmlError error; error.setObject(this); const QQmlContextData* urlContext = data->context; while (urlContext && urlContext->url().isEmpty()) urlContext = urlContext->parent; error.setUrl(urlContext ? urlContext->url() : QUrl()); QString objectId = data->context->findObjectId(this); if (!objectId.isEmpty()) error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl", "Conflicting properties 'visible' and 'visibility' for Window '%1'").arg(objectId)); else error.setDescription(QCoreApplication::translate("QQuickWindowQmlImpl", "Conflicting properties 'visible' and 'visibility'")); QQmlEnginePrivate::get(data->context->engine)->warning(error); } if (d->visibility == AutomaticVisibility) { setWindowState(QGuiApplicationPrivate::platformIntegration()->defaultWindowState(flags())); setVisible(d->visible); } else { setVisibility(d->visibility); } }
bool Compiler::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { Q_D(Compiler); const QString &importUri = stringAt(import->uriIndex); const QString &importQualifier = stringAt(import->qualifierIndex); if (import->type == QV4::CompiledData::Import::ImportScript) { // TBD: qqmltypeloader.cpp:1320 QmlCompilation::ScriptReference scriptRef; scriptRef.location = import->location; scriptRef.qualifier = importQualifier; scriptRef.compilation = NULL; d->compilation->scripts.append(scriptRef); } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { QString qmldirFilePath; QString qmldirUrl; if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) { //Locked modules are checked first, to save on filesystem checks if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else if (d->compilation->importCache->locateQmldir(d->compilation->importDatabase, importUri, import->majorVersion, import->minorVersion, &qmldirFilePath, &qmldirUrl)) { // This is a local library import if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, qmldirFilePath, qmldirUrl, false, errors)) return false; if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); QQmlTypeLoader* typeLoader = &QQmlEnginePrivate::get(d->compilation->engine)->typeLoader; const QQmlTypeLoader::QmldirContent *qmldir = typeLoader->qmldirContent(qmldirFilePath, qmldirUrl); foreach (const QQmlDirParser::Script &script, qmldir->scripts()) { // TBD: qqmltypeloader.cpp:1343 qDebug() << "Library contains scripts"; QQmlError error; error.setDescription("Libraries with scripts not supported"); appendError(error); return false; } } } else {
bool Compiler::compile(const QString &url) { Q_D(Compiler); clearError(); // set env var so one can test in plugins if needed setenv("QMC_COMPILE", "1", 1); // check that engine is using correct factory if (!qgetenv("QV4_FORCE_INTERPRETER").isEmpty()) { QQmlError error; error.setDescription("Compiler is forced to use interpreter"); appendError(error); return false; } Q_ASSERT(d->compilation == NULL); QmlCompilation* c = new QmlCompilation(url, QUrl(url), d->engine); d->compilation = c; c->importCache = new QQmlImports(&QQmlEnginePrivate::get(d->compilation->engine)->typeLoader); c->importDatabase = new QQmlImportDatabase(d->compilation->engine); c->loadUrl = url; int lastSlash = url.lastIndexOf('/'); if (lastSlash == -1) c->url = url; else if (lastSlash + 1 < url.length()) c->url = url.mid(lastSlash + 1); else c->url = ""; if (!loadData()) { delete takeCompilation(); return false; } if (!compileData()) { delete takeCompilation(); return false; } return true; }
bool Compiler::loadData() { Q_D(Compiler); const QUrl& url = d->compilation->loadUrl; if (!url.isValid() || url.isEmpty()) return false; QQmlFile f; f.load(d->compilation->engine, url); if (!f.isReady()) { if (f.isError()) { QQmlError error; error.setUrl(url); error.setDescription(f.error()); appendError(error); } return false; } d->compilation->code = QString::fromUtf8(f.data()); return true; }
bool Compiler::exportData(QDataStream &output) { Q_D(Compiler); if (!d->compilation->checkData()) { QQmlError error; error.setDescription("Compiled data not valid. Internal error."); appendError(error); return false; } QmcExporter exporter(d->compilation); bool ret = exporter.exportQmc(output); if (!ret) { QQmlError error; error.setDescription("Error saving data"); appendError(error); } return ret; }
void QQmlJavaScriptExpression::exceptionToError(v8::Handle<v8::Message> message, QQmlError &error) { Q_ASSERT(!message.IsEmpty()); v8::Handle<v8::Value> name = message->GetScriptResourceName(); v8::Handle<v8::String> description = message->Get(); int lineNumber = message->GetLineNumber(); v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>(); if (file.IsEmpty() || file->Length() == 0) error.setUrl(QUrl()); else error.setUrl(QUrl(QV8Engine::toStringStatic(file))); error.setLine(lineNumber); error.setColumn(-1); QString qDescription = QV8Engine::toStringStatic(description); if (qDescription.startsWith(QLatin1String("Uncaught "))) qDescription = qDescription.mid(9 /* strlen("Uncaught ") */); error.setDescription(qDescription); }
// Callee owns the persistent handle v8::Persistent<v8::Function> QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope, const char *code, int codeLength, const QString &filename, quint16 line, v8::Persistent<v8::Object> *qmlscope) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); v8::HandleScope handle_scope; v8::Context::Scope ctxtscope(ep->v8engine()->context()); v8::TryCatch tc; v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope); v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line); if (tc.HasCaught()) { QQmlError error; error.setDescription(QLatin1String("Exception occurred during function compilation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); v8::Local<v8::Message> message = tc.Message(); if (!message.IsEmpty()) QQmlExpressionPrivate::exceptionToError(message, error); ep->warning(error); return v8::Persistent<v8::Function>(); } v8::Local<v8::Value> result = script->Run(scopeobject); if (tc.HasCaught()) { QQmlError error; error.setDescription(QLatin1String("Exception occurred during function evaluation")); error.setLine(line); error.setUrl(QUrl::fromLocalFile(filename)); v8::Local<v8::Message> message = tc.Message(); if (!message.IsEmpty()) QQmlExpressionPrivate::exceptionToError(message, error); ep->warning(error); return v8::Persistent<v8::Function>(); } if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject); return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result)); }
QDebug operator<<(QDebug debug, const QQmlError &error) { debug << qPrintable(error.toString()); QUrl url = error.url(); if (error.line() > 0 && url.scheme() == QLatin1String("file")) { QString file = url.toLocalFile(); QFile f(file); if (f.open(QIODevice::ReadOnly)) { QByteArray data = f.readAll(); QTextStream stream(data, QIODevice::ReadOnly); #ifndef QT_NO_TEXTCODEC stream.setCodec("UTF-8"); #endif const QString code = stream.readAll(); const QStringList lines = code.split(QLatin1Char('\n')); if (lines.count() >= error.line()) { const QString &line = lines.at(error.line() - 1); debug << "\n " << qPrintable(line); if(error.column() > 0) { int column = qMax(0, error.column() - 1); column = qMin(column, line.length()); QByteArray ind; ind.reserve(column); for (int i = 0; i < column; ++i) { const QChar ch = line.at(i); if (ch.isSpace()) ind.append(ch.unicode()); else ind.append(' '); } ind.append('^'); debug << "\n " << ind.constData(); } } } } return debug; }
void tst_qqmlerror::line() { QQmlError error; QCOMPARE(error.line(), -1); error.setLine(102); QCOMPARE(error.line(), 102); QQmlError error2 = error; QCOMPARE(error2.line(), 102); error.setLine(4); QCOMPARE(error.line(), 4); QCOMPARE(error2.line(), 102); }
void tst_qqmlerror::column() { QQmlError error; QCOMPARE(error.column(), -1); error.setColumn(16); QCOMPARE(error.column(), 16); QQmlError error2 = error; QCOMPARE(error2.column(), 16); error.setColumn(3); QCOMPARE(error.column(), 3); QCOMPARE(error2.column(), 16); }
void tst_qqmlerror::description() { QQmlError error; QCOMPARE(error.description(), QString()); error.setDescription("An Error"); QCOMPARE(error.description(), QString("An Error")); QQmlError error2 = error; QCOMPARE(error2.description(), QString("An Error")); error.setDescription("Another Error"); QCOMPARE(error.description(), QString("Another Error")); QCOMPARE(error2.description(), QString("An Error")); }
void tst_qqmlerror::url() { QQmlError error; QCOMPARE(error.url(), QUrl()); error.setUrl(QUrl("http://www.qt-project.org/main.qml")); QCOMPARE(error.url(), QUrl("http://www.qt-project.org/main.qml")); QQmlError error2 = error; QCOMPARE(error2.url(), QUrl("http://www.qt-project.org/main.qml")); error.setUrl(QUrl("http://www.qt-project.org/main.qml")); QCOMPARE(error.url(), QUrl("http://www.qt-project.org/main.qml")); QCOMPARE(error2.url(), QUrl("http://www.qt-project.org/main.qml")); }
void QQmlDirParser::setError(const QQmlError &e) { _errors.clear(); reportError(e.line(), e.column(), e.description()); }
QQmlInfo::~QQmlInfo() { if (0 == --d->ref) { QList<QQmlError> errors = d->errors; QQmlEngine *engine = 0; if (!d->buffer.isEmpty()) { QQmlError error; QObject *object = const_cast<QObject *>(d->object); if (object) { engine = qmlEngine(d->object); QString typeName; QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); if (type) { typeName = type->qmlTypeName(); int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash+1); } else { typeName = QString::fromUtf8(object->metaObject()->className()); int marker = typeName.indexOf(QLatin1String("_QMLTYPE_")); if (marker != -1) typeName = typeName.left(marker); marker = typeName.indexOf(QLatin1String("_QML_")); if (marker != -1) { typeName = typeName.left(marker); typeName += QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); if (type) { typeName = type->qmlTypeName(); int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); if (lastSlash != -1) typeName = typeName.mid(lastSlash+1); } } } d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": ")); QQmlData *ddata = QQmlData::get(object, false); if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { error.setUrl(ddata->outerContext->url); error.setLine(ddata->lineNumber); error.setColumn(ddata->columnNumber); } } error.setDescription(d->buffer); errors.prepend(error); } QQmlEnginePrivate::warning(engine, errors); delete d; } }
int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) { int id = _id; if (c == QMetaObject::WriteProperty && interceptors && !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) { for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) { if (vi->m_coreIndex != id) continue; int valueIndex = vi->m_valueTypeCoreIndex; int type = QQmlData::get(object)->propertyCache->property(id)->propType; if (type != QVariant::Invalid) { if (valueIndex != -1) { QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type); Q_ASSERT(valueType); // // Consider the following case: // color c = { 0.1, 0.2, 0.3 } // interceptor exists on c.r // write { 0.2, 0.4, 0.6 } // // The interceptor may choose not to update the r component at this // point (for example, a behavior that creates an animation). But we // need to ensure that the g and b components are updated correctly. // // So we need to perform a full write where the value type is: // r = old value, g = new value, b = new value // // And then call the interceptor which may or may not write the // new value to the r component. // // This will ensure that the other components don't contain stale data // and any relevant signals are emitted. // // To achieve this: // (1) Store the new value type as a whole (needed due to // aliasing between a[0] and static storage in value type). // (2) Read the entire existing value type from object -> valueType temp. // (3) Read the previous value of the component being changed // from the valueType temp. // (4) Write the entire new value type into the temp. // (5) Overwrite the component being changed with the old value. // (6) Perform a full write to the value type (which may emit signals etc). // (7) Issue the interceptor call with the new component value. // QMetaProperty valueProp = valueType->metaObject()->property(valueIndex); QVariant newValue(type, a[0]); valueType->read(object, id); QVariant prevComponentValue = valueProp.read(valueType); valueType->setValue(newValue); QVariant newComponentValue = valueProp.read(valueType); // Don't apply the interceptor if the intercepted value has not changed bool updated = false; if (newComponentValue != prevComponentValue) { valueProp.write(valueType, prevComponentValue); valueType->write(object, id, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); vi->write(newComponentValue); updated = true; } if (updated) return -1; } else { vi->write(QVariant(type, a[0])); return -1; } } } } if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) { if (id >= propOffset()) { id -= propOffset(); if (id < metaData->propertyCount) { int t = (metaData->propertyData() + id)->propertyType; bool needActivate = false; if (id >= firstVarPropertyIndex) { Q_ASSERT(t == QMetaType::QVariant); // the context can be null if accessing var properties from cpp after re-parenting an item. QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine(); if (v8e) { if (c == QMetaObject::ReadProperty) { *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); } else if (c == QMetaObject::WriteProperty) { writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); } } else if (c == QMetaObject::ReadProperty) { // if the context was disposed, we just return an invalid variant from read. *reinterpret_cast<QVariant *>(a[0]) = QVariant(); } } else { if (c == QMetaObject::ReadProperty) { switch(t) { case QVariant::Int: *reinterpret_cast<int *>(a[0]) = data[id].asInt(); break; case QVariant::Bool: *reinterpret_cast<bool *>(a[0]) = data[id].asBool(); break; case QVariant::Double: *reinterpret_cast<double *>(a[0]) = data[id].asDouble(); break; case QVariant::String: *reinterpret_cast<QString *>(a[0]) = data[id].asQString(); break; case QVariant::Url: *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl(); break; case QVariant::Date: *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate(); break; case QVariant::DateTime: *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime(); break; case QVariant::RectF: *reinterpret_cast<QRectF *>(a[0]) = data[id].asQRectF(); break; case QVariant::SizeF: *reinterpret_cast<QSizeF *>(a[0]) = data[id].asQSizeF(); break; case QVariant::PointF: *reinterpret_cast<QPointF *>(a[0]) = data[id].asQPointF(); break; case QMetaType::QObjectStar: *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject(); break; case QMetaType::QVariant: *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); break; default: QQml_valueTypeProvider()->readValueType(data[id].dataType(), data[id].dataPtr(), data->dataSize(), t, a[0]); break; } if (t == qMetaTypeId<QQmlListProperty<QObject> >()) { int listIndex = data[id].asInt(); const List *list = &listProperties.at(listIndex); *reinterpret_cast<QQmlListProperty<QObject> *>(a[0]) = QQmlListProperty<QObject>(object, (void *)list, list_append, list_count, list_at, list_clear); } } else if (c == QMetaObject::WriteProperty) { switch(t) { case QVariant::Int: needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt(); data[id].setValue(*reinterpret_cast<int *>(a[0])); break; case QVariant::Bool: needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool(); data[id].setValue(*reinterpret_cast<bool *>(a[0])); break; case QVariant::Double: needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble(); data[id].setValue(*reinterpret_cast<double *>(a[0])); break; case QVariant::String: needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString(); data[id].setValue(*reinterpret_cast<QString *>(a[0])); break; case QVariant::Url: needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl(); data[id].setValue(*reinterpret_cast<QUrl *>(a[0])); break; case QVariant::Date: needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate(); data[id].setValue(*reinterpret_cast<QDate *>(a[0])); break; case QVariant::DateTime: needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime(); data[id].setValue(*reinterpret_cast<QDateTime *>(a[0])); break; case QVariant::RectF: needActivate = *reinterpret_cast<QRectF *>(a[0]) != data[id].asQRectF(); data[id].setValue(*reinterpret_cast<QRectF *>(a[0])); break; case QVariant::SizeF: needActivate = *reinterpret_cast<QSizeF *>(a[0]) != data[id].asQSizeF(); data[id].setValue(*reinterpret_cast<QSizeF *>(a[0])); break; case QVariant::PointF: needActivate = *reinterpret_cast<QPointF *>(a[0]) != data[id].asQPointF(); data[id].setValue(*reinterpret_cast<QPointF *>(a[0])); break; case QMetaType::QObjectStar: needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject(); data[id].setValue(*reinterpret_cast<QObject **>(a[0]), this, id); break; case QMetaType::QVariant: writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); break; default: data[id].ensureValueType(t); needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr(), data[id].dataSize()); QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize()); break; } } } if (c == QMetaObject::WriteProperty && needActivate) { activate(object, methodOffset() + id, 0); } return -1; } id -= metaData->propertyCount; if (id < metaData->aliasCount) { QQmlVMEMetaData::AliasData *d = metaData->aliasData() + id; if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) *reinterpret_cast<void **>(a[0]) = 0; if (!ctxt) return -1; QQmlContext *context = ctxt->asQQmlContext(); QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context); QObject *target = ctxtPriv->data->idValues[d->contextIdx].data(); if (!target) return -1; connectAlias(id); if (d->isObjectAlias()) { *reinterpret_cast<QObject **>(a[0]) = target; return -1; } // Remove binding (if any) on write if(c == QMetaObject::WriteProperty) { int flags = *reinterpret_cast<int*>(a[3]); if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) { QQmlData *targetData = QQmlData::get(target); if (targetData && targetData->hasBindingBit(d->propertyIndex())) { QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0); if (binding) binding->destroy(); } } } if (d->isValueTypeAlias()) { // Value type property QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->valueType()); Q_ASSERT(valueType); valueType->read(target, d->propertyIndex()); int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a); if (c == QMetaObject::WriteProperty) valueType->write(target, d->propertyIndex(), 0x00); return rv; } else { return QMetaObject::metacall(target, c, d->propertyIndex(), a); } } return -1; } } else if(c == QMetaObject::InvokeMetaMethod) { if (id >= methodOffset()) { id -= methodOffset(); int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; if (id < plainSignals) { activate(object, _id, a); return -1; } id -= plainSignals; if (id < metaData->methodCount) { if (!ctxt->engine) return -1; // We can't run the method QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine); ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. QV4::Scope scope(ep->v4engine()); QV4::Scoped<QV4::FunctionObject> function(scope, method(id)); if (!function) { // The function was not compiled. There are some exceptional cases which the // expression rewriter does not rewrite properly (e.g., \r-terminated lines // are not rewritten correctly but this bug is deemed out-of-scope to fix for // performance reasons; see QTBUG-24064) and thus compilation will have failed. QQmlError e; e.setDescription(QString(QLatin1String("Exception occurred during compilation of function: %1")). arg(QLatin1String(QMetaObject::method(_id).methodSignature().constData()))); ep->warning(e); return -1; // The dynamic method with that id is not available. } QQmlVMEMetaData::MethodData *data = metaData->methodData() + id; QV4::ScopedCallData callData(scope, data->parameterCount); callData->thisObject = ep->v8engine()->global(); for (int ii = 0; ii < data->parameterCount; ++ii) callData->args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]); QV4::ScopedValue result(scope); QV4::ExecutionContext *ctx = function->engine()->currentContext(); result = function->call(callData); if (scope.hasException()) { QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx); if (error.isValid()) ep->warning(error); if (a[0]) *(QVariant *)a[0] = QVariant(); } else { if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. return -1; } return -1; } } if (parent.isT1()) return parent.asT1()->metaCall(object, c, _id, a); else return object->qt_metacall(c, _id, a); }
void tst_qqmlerror::debug() { { QQmlError error; error.setUrl(QUrl("http://www.qt-project.org/main.qml")); error.setDescription("An Error"); error.setLine(92); error.setColumn(13); QTest::ignoreMessage(QtWarningMsg, "http://www.qt-project.org/main.qml:92:13: An Error "); qWarning() << error; } { QUrl url(dataDirectoryUrl().resolved(QUrl("test.txt"))); QQmlError error; error.setUrl(url); error.setDescription("An Error"); error.setLine(2); error.setColumn(5); QString out = url.toString() + ":2:5: An Error \n Line2 Content \n ^ "; QTest::ignoreMessage(QtWarningMsg, qPrintable(out)); qWarning() << error; } { QUrl url(dataDirectoryUrl().resolved(QUrl("foo.txt"))); QQmlError error; error.setUrl(url); error.setDescription("An Error"); error.setLine(2); error.setColumn(5); QString out = url.toString() + ":2:5: An Error "; QTest::ignoreMessage(QtWarningMsg, qPrintable(out)); qWarning() << error; } }
bool QmcTypeCompiler::createTypeMap() { // qqmltypecompiler.cpp:81 const QHash<int, QmlCompilation::TypeReference> &resolvedTypes = compilation->typeReferences; for (QHash<int, QmlCompilation::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { QScopedPointer<QQmlCompiledData::TypeReference> ref(new QQmlCompiledData::TypeReference); QQmlType *qmlType = resolvedType->type; if (resolvedType.value().composite) { // qqmltypecompiler.cpp:87 if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) { QQmlError error; QString reason = tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName()); error.setDescription(reason); error.setColumn(resolvedType->location.column); error.setLine(resolvedType->location.line); recordError(error); return false; } // qqmltypecompiler.cpp:96 Q_ASSERT(resolvedType->component); Q_ASSERT(resolvedType->component->compiledData); ref->component = resolvedType->component->compiledData; ref->component->addref(); } else if (qmlType) { ref->type = qmlType; Q_ASSERT(ref->type); if (resolvedType->needsCreation && !ref->type->isCreatable()) { QQmlError error; QString reason = ref->type->noCreationReason(); if (reason.isEmpty()) reason = tr("Element is not creatable."); error.setDescription(reason); error.setColumn(resolvedType->location.column); error.setLine(resolvedType->location.line); error.setUrl(compilation->url); recordError(error); return false; } if (ref->type->containsRevisionedAttributes()) { QQmlError cacheError; ref->typePropertyCache = QQmlEnginePrivate::get(compilation->engine)->cache( ref->type, resolvedType->minorVersion, cacheError); if (!ref->typePropertyCache) { cacheError.setColumn(resolvedType->location.column); cacheError.setLine(resolvedType->location.line); recordError(cacheError); return false; } ref->typePropertyCache->addref(); } } ref->majorVersion = resolvedType->majorVersion; ref->minorVersion = resolvedType->minorVersion; ref->doDynamicTypeCheck(); compiledData->resolvedTypes.insert(resolvedType.key(), ref.take()); } return true; }
void tst_qqmlerror::toString() { { QQmlError error; error.setUrl(QUrl("http://www.qt-project.org/main.qml")); error.setDescription("An Error"); error.setLine(92); error.setColumn(13); QCOMPARE(error.toString(), QString("http://www.qt-project.org/main.qml:92:13: An Error")); } { QQmlError error; error.setUrl(QUrl("http://www.qt-project.org/main.qml")); error.setDescription("An Error"); error.setLine(92); QCOMPARE(error.toString(), QString("http://www.qt-project.org/main.qml:92: An Error")); } }
bool Compiler::addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { Q_D(Compiler); const QString &importUri = stringAt(import->uriIndex); const QString &importQualifier = stringAt(import->qualifierIndex); if (import->type == QV4::CompiledData::Import::ImportScript) { // TBD: qqmltypeloader.cpp:1320 QmlCompilation::ScriptReference scriptRef; scriptRef.location = import->location; scriptRef.qualifier = importQualifier; scriptRef.compilation = NULL; d->compilation->scripts.append(scriptRef); } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { QString qmldirFilePath; QString qmldirUrl; if (QQmlMetaType::isLockedModule(importUri, import->majorVersion)) { //Locked modules are checked first, to save on filesystem checks if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else if (d->compilation->importCache->locateQmldir(d->compilation->importDatabase, importUri, import->majorVersion, import->minorVersion, &qmldirFilePath, &qmldirUrl)) { // This is a local library import if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, qmldirFilePath, qmldirUrl, false, errors)) return false; if (!importQualifier.isEmpty()) { // Does this library contain any qualified scripts? QUrl libraryUrl(qmldirUrl); QQmlTypeLoader* typeLoader = &QQmlEnginePrivate::get(d->compilation->engine)->typeLoader; const QQmlTypeLoader::QmldirContent *qmldir = typeLoader->qmldirContent(qmldirFilePath, qmldirUrl); // File loading will import the dependency and takes care of // everything there. Adding a script reference here just seems // to add an unnecessary reference that might actually be a bug. // In case something is needed, see: qqmltypeloader.cpp:1343 } } else { // Is this a module? qDebug() << "Importing local module" << importUri; if (QQmlMetaType::isAnyModule(importUri)) { if (!d->compilation->importCache->addLibraryImport(d->compilation->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, QString(), QString(), false, errors)) return false; } else { QQmlError error; error.setDescription("Unresolved import " + importUri); error.setLine(import->location.line); error.setColumn(import->location.column); error.setUrl(d->compilation->url); appendError(error); return false; // TBD: else add to unresolved imports qqmltypeloader.cpp:1356 } } } else { // qqmltypeloader.cpp:1383 Q_ASSERT(import->type == QV4::CompiledData::Import::ImportFile); QUrl qmldirUrl; if (importQualifier.isEmpty()) { qmldirUrl = compilation()->loadUrl.resolved(QUrl(importUri + QLatin1String("/qmldir"))); if (!QQmlImports::isLocal(qmldirUrl)) { qDebug() << "File import from network not supported"; QQmlError error; error.setDescription("File import from network not supported"); errors->append(error); return false; } } if (!compilation()->importCache->addFileImport(compilation()->importDatabase, importUri, importQualifier, import->majorVersion, import->minorVersion, /*incomplete*/ false, errors)) return false; } return true; }
void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) { if (!compiledData) return; QML_MEMORY_SCOPE_URL(compiledData->url()); QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this); QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this); QQmlEngine *engine = compiledData->engine; QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine); if (!vmeGuard.isOK()) { QQmlError error; error.setUrl(compiledData->url()); error.setDescription(QQmlComponent::tr("Object destroyed during incubation")); errors << error; progress = QQmlIncubatorPrivate::Completed; goto finishIncubate; } vmeGuard.clear(); if (progress == QQmlIncubatorPrivate::Execute) { enginePriv->referenceScarceResources(); QObject *tresult = 0; tresult = creator->create(subComponentToCreate, /*parent*/0, &i); if (!tresult) errors = creator->errors; enginePriv->dereferenceScarceResources(); if (watcher.hasRecursed()) return; result = tresult; if (errors.isEmpty() && result == 0) goto finishIncubate; if (result) { QQmlData *ddata = QQmlData::get(result); Q_ASSERT(ddata); //see QQmlComponent::beginCreate for explanation of indestructible ddata->indestructible = true; ddata->explicitIndestructibleSet = true; ddata->rootObjectInCreation = false; if (q) q->setInitialState(result); } if (watcher.hasRecursed()) return; if (errors.isEmpty()) progress = QQmlIncubatorPrivate::Completing; else progress = QQmlIncubatorPrivate::Completed; changeStatus(calculateStatus()); if (watcher.hasRecursed()) return; if (i.shouldInterrupt()) goto finishIncubate; } if (progress == QQmlIncubatorPrivate::Completing) { do { if (watcher.hasRecursed()) return; QQmlContextData *ctxt = 0; ctxt = creator->finalize(i); if (ctxt) { rootContext = ctxt; progress = QQmlIncubatorPrivate::Completed; goto finishIncubate; } } while (!i.shouldInterrupt()); } finishIncubate: if (progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty()) { QExplicitlySharedDataPointer<QQmlIncubatorPrivate> isWaiting = waitingOnMe; clear(); if (isWaiting) { QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(isWaiting.data()); changeStatus(calculateStatus()); if (!watcher.hasRecursed()) isWaiting->incubate(i); } else { changeStatus(calculateStatus()); } enginePriv->inProgressCreations--; if (0 == enginePriv->inProgressCreations) { while (enginePriv->erroredBindings) { enginePriv->warning(enginePriv->erroredBindings); enginePriv->erroredBindings->removeError(); } } } else if (!creator.isNull()) { vmeGuard.guard(creator.data()); } }
void tst_qqmlerror::copy() { QQmlError error; error.setUrl(QUrl("http://www.qt-project.org/main.qml")); error.setDescription("An Error"); error.setLine(92); error.setColumn(13); QQmlError error2(error); QQmlError error3; error3 = error; error.setUrl(QUrl("http://www.qt-project.org/main.qml")); error.setDescription("Another Error"); error.setLine(2); error.setColumn(33); QCOMPARE(error.url(), QUrl("http://www.qt-project.org/main.qml")); QCOMPARE(error.description(), QString("Another Error")); QCOMPARE(error.line(), 2); QCOMPARE(error.column(), 33); QCOMPARE(error2.url(), QUrl("http://www.qt-project.org/main.qml")); QCOMPARE(error2.description(), QString("An Error")); QCOMPARE(error2.line(), 92); QCOMPARE(error2.column(), 13); QCOMPARE(error3.url(), QUrl("http://www.qt-project.org/main.qml")); QCOMPARE(error3.description(), QString("An Error")); QCOMPARE(error3.line(), 92); QCOMPARE(error3.column(), 13); }