diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2017-12-11 12:44:47 +0100 |
---|---|---|
committer | Michael Brasser <michael.brasser@live.com> | 2017-12-21 16:02:50 +0000 |
commit | 52bc4fbfbae6aa1569dc134dd103e966f04bc2e6 (patch) | |
tree | 91c5f84c6623f14338b95b5acbb40c66cb7d1aaf /src | |
parent | cbdbbe79ec141e66f3160a1332e49518f9682517 (diff) |
Use potentially intercepted URL as ID for compilation units
We generally have to pass a URL and a file name everywhere because the
logical URL might be something else than the actual file being loaded.
For example a QQmlFileSelector might modify the URL to be loaded for a
specific file. This resulting URL, however, should not be used to
resolve further URLs defined in the file loaded that way.
As we need to access QQmlTypeLoader::m_url as string more often now,
cache it and avoid frequent translations between QUrl and QString.
Furthermore, QQmlDataBlob's URLs are changed to follow the same
semantics. The finalUrl is the one that should be used to resolve
further URLs, the url is the one used to load the content, and subject
to any redirects or interceptions.
This changes the semantics of URL redirects. Previously a redirected URL
was used as the base URL for furher URL resolution. This doesn't work
because redirection occurs after interception and interception should
not influence the resolution of further URLs. We now use the original
URL as base URL for resolution of further URLs and rely on the server to
redirect those, too.
Task-number: QTBUG-61209
Change-Id: I93822f820bed2515995de3cb118099218b510ca4
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 7 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder_p.h | 6 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 22 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script_p.h | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlcontext.cpp | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlincubator.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 80 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 2 |
21 files changed, 124 insertions, 60 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 092c0020fa..3974f9ae4e 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1552,8 +1552,10 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding return bindingPtr; } -JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, - QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool) +JSCodeGen::JSCodeGen(const QString &fileName, const QString &finalUrl, const QString &sourceCode, + QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, + QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, + const QV4::Compiler::StringTableGenerator *stringPool) : QQmlJS::Codegen(/*strict mode*/false) , sourceCode(sourceCode) , jsEngine(jsEngine) @@ -1568,6 +1570,7 @@ JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR { _module = jsModule; _module->setFileName(fileName); + _module->setFinalUrl(finalUrl); _fileNameIsUrl = true; } diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index a6ff18927d..8f8a6d090e 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -582,9 +582,9 @@ struct Q_QML_EXPORT PropertyResolver struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QQmlJS::Codegen { - JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule, - QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, - const QV4::Compiler::StringTableGenerator *stringPool); + JSCodeGen(const QString &fileName, const QString &finalUrl, const QString &sourceCode, + QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, + QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool); struct IdMapping { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index fab865081a..568ad4af89 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -140,7 +140,10 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() sss.scan(); } - QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable); + QmlIR::JSCodeGen v4CodeGenerator(typeData->urlString(), typeData->finalUrlString(), + document->code, &document->jsModule, + &document->jsParserEngine, document->program, + typeNameCache, &document->jsGenerator.stringTable); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) return nullptr; diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 1e98d1167b..b07e9f55f5 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -489,6 +489,7 @@ Codegen::Codegen(bool strict) } void Codegen::generateFromProgram(const QString &fileName, + const QString &finalUrl, const QString &sourceCode, Program *node, QV4::IR::Module *module, @@ -501,6 +502,7 @@ void Codegen::generateFromProgram(const QString &fileName, _env = 0; _module->setFileName(fileName); + _module->setFinalUrl(finalUrl); ScanFunctions scan(this, sourceCode, mode); scan(node); @@ -511,12 +513,14 @@ void Codegen::generateFromProgram(const QString &fileName, } void Codegen::generateFromFunctionExpression(const QString &fileName, + const QString &finalUrl, const QString &sourceCode, AST::FunctionExpression *ast, QV4::IR::Module *module) { _module = module; _module->setFileName(fileName); + _module->setFinalUrl(finalUrl); _env = 0; ScanFunctions scan(this, sourceCode, GlobalCode); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 1cbe6949a1..a08b9c1d68 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -86,15 +86,17 @@ public: }; void generateFromProgram(const QString &fileName, + const QString &finalUrl, const QString &sourceCode, AST::Program *ast, QV4::IR::Module *module, CompilationMode mode = GlobalCode, const QStringList &inheritedLocals = QStringList()); void generateFromFunctionExpression(const QString &fileName, - const QString &sourceCode, - AST::FunctionExpression *ast, - QV4::IR::Module *module); + const QString &finalUrl, + const QString &sourceCode, + AST::FunctionExpression *ast, + QV4::IR::Module *module); protected: enum Format { ex, cx, nx }; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 294eaa25f5..f54a1b0c41 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -502,6 +502,7 @@ Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument) if (jsUnit->sourceFileIndex == quint32(0) || jsUnit->stringAt(jsUnit->sourceFileIndex) != irDocument->jsModule.fileName) { ensureWritableUnit(); jsUnit->sourceFileIndex = stringTable.registerString(irDocument->jsModule.fileName); + jsUnit->finalUrlIndex = stringTable.registerString(irDocument->jsModule.finalUrl); } // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example) diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 440dc3e013..188a571394 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x13 +#define QV4_DATA_STRUCTURE_VERSION 0x14 class QIODevice; class QQmlPropertyCache; @@ -661,6 +661,7 @@ struct Unit LEUInt32 offsetToJSClassTable; LEInt32 indexOfRootFunction; LEUInt32 sourceFileIndex; + LEUInt32 finalUrlIndex; /* QML specific fields */ LEUInt32 nImports; @@ -668,6 +669,8 @@ struct Unit LEUInt32 nObjects; LEUInt32 offsetToObjects; + LEUInt32 padding; + const Import *importAt(int idx) const { return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import)); } @@ -732,7 +735,7 @@ struct Unit } }; -static_assert(sizeof(Unit) == 144, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); +static_assert(sizeof(Unit) == 152, "Unit structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target"); struct TypeReference { @@ -842,14 +845,29 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public ExecutionEngine *engine; QQmlEnginePrivate *qmlEngine; // only used in QML environment for composite types, not in plain QJSEngine case. + // url() and fileName() shall be used to load the actual QML/JS code or to show errors or + // warnings about that code. They include any potential URL interceptions and thus represent the + // "physical" location of the code. + // + // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code + // They are _not_ intercepted and thus represent the "logical" name for the code. + QString fileName() const { return data->stringAt(data->sourceFileIndex); } + QString finalUrlString() const { return data->stringAt(data->finalUrlIndex); } QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; } + QUrl finalUrl() const + { + if (m_finalUrl.isNull) + m_finalUrl = QUrl(finalUrlString()); + return m_finalUrl; + } QV4::Lookup *runtimeLookups; QV4::Value *runtimeRegularExpressions; QV4::InternalClass **runtimeClasses; QVector<QV4::Function *> runtimeFunctions; mutable QQmlNullableValue<QUrl> m_url; + mutable QQmlNullableValue<QUrl> m_finalUrl; // QML specific fields QQmlPropertyCacheVector propertyCaches; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 3abdd0370f..0dc40d9698 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -212,6 +212,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option) { registerString(irModule->fileName); + registerString(irModule->finalUrl); for (QV4::IR::Function *f : qAsConst(irModule->functions)) { registerString(*f->name); for (int i = 0; i < f->formals.size(); ++i) @@ -427,6 +428,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp } unit.indexOfRootFunction = -1; unit.sourceFileIndex = getStringId(irModule->fileName); + unit.finalUrlIndex = getStringId(irModule->finalUrl); unit.sourceTimeStamp = irModule->sourceTimeStamp.isValid() ? irModule->sourceTimeStamp.toMSecsSinceEpoch() : 0; unit.nImports = 0; unit.offsetToImports = 0; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 0b0ed391fb..a8e18784c7 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -351,6 +351,11 @@ void Module::setFileName(const QString &name) fileName = name; } +void Module::setFinalUrl(const QString &url) +{ + finalUrl = url; +} + Function::Function(Module *module, Function *outer, const QString &name) : module(module) , pool(&module->pool) diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 5c8e79f404..9980a21912 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -952,6 +952,7 @@ struct Q_QML_PRIVATE_EXPORT Module { QVector<Function *> functions; Function *rootFunction; QString fileName; + QString finalUrl; QDateTime sourceTimeStamp; bool isQmlModule; // implies rootFunction is always 0 uint unitFlags; // flags merged into CompiledData::Unit::flags @@ -977,6 +978,7 @@ struct Q_QML_PRIVATE_EXPORT Module { ~Module(); void setFileName(const QString &name); + void setFinalUrl(const QString &url); }; struct BasicBlock { diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 917f6bffc5..a584c2731f 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -884,14 +884,14 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) while (c) { CallContext *callCtx = c->asCallContext(); if (callCtx && callCtx->d()->v4Function) { - base.setUrl(callCtx->d()->v4Function->sourceFile()); + base = callCtx->d()->v4Function->finalUrl(); break; } c = parentContext(c); } if (base.isEmpty() && globalCode) - base.setUrl(globalCode->sourceFile()); + base = globalCode->finalUrl(); if (base.isEmpty()) return src; diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 54d0528c42..b212b3d027 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -84,6 +84,7 @@ struct Q_QML_EXPORT Function { return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; } inline QString sourceFile() const { return compilationUnit->fileName(); } + inline QUrl finalUrl() const { return compilationUnit->finalUrl(); } inline bool usesArgumentsObject() const { return compiledFunction->flags & CompiledData::Function::UsesArgumentsObject; } inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 9eb9d2ad36..63396998fa 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -229,7 +229,7 @@ void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callDa IR::Module module(scope.engine->debugger() != 0); QQmlJS::RuntimeCodegen cg(scope.engine, f->strictMode()); - cg.generateFromFunctionExpression(QString(), function, fe, &module); + cg.generateFromFunctionExpression(QString(), QString(), function, fe, &module); Compiler::JSUnitGenerator jsGenerator(&module); QScopedPointer<EvalInstructionSelection> isel(scope.engine->iselFactory->create(QQmlEnginePrivate::get(scope.engine), scope.engine->executableAllocator, &module, &jsGenerator)); diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 62145f36cc..9d1d5e2589 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -127,7 +127,8 @@ void Script::parse() } RuntimeCodegen cg(v4, strictMode); - cg.generateFromProgram(sourceFile, sourceCode, program, &module, QQmlJS::Codegen::EvalCode, inheritedLocals); + cg.generateFromProgram(sourceFile, sourceFile, sourceCode, program, &module, + QQmlJS::Codegen::EvalCode, inheritedLocals); if (v4->hasException) return; @@ -186,7 +187,10 @@ Function *Script::function() return vmFunction; } -QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors, QQmlJS::Directives *directivesCollector) +QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile( + IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, + const QString &fileName, const QString &finalUrl, const QString &source, + QList<QQmlError> *reportedErrors, QQmlJS::Directives *directivesCollector) { using namespace QQmlJS; using namespace QQmlJS::AST; @@ -205,12 +209,12 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module const auto diagnosticMessages = parser.diagnosticMessages(); for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) { if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(url.toString()), m.loc.startLine, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); continue; } QQmlError error; - error.setUrl(url); + error.setUrl(QUrl(fileName)); error.setDescription(m.message); error.setLine(m.loc.startLine); error.setColumn(m.loc.startColumn); @@ -231,7 +235,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(IR::Module } QQmlJS::Codegen cg(/*strict mode*/false); - cg.generateFromProgram(url.toString(), source, program, module, QQmlJS::Codegen::EvalCode); + cg.generateFromProgram(fileName, finalUrl, source, program, module, QQmlJS::Codegen::EvalCode); errors = cg.qmlErrors(); if (!errors.isEmpty()) { if (reportedErrors) diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 4ebe2dd609..55a349b5fc 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -139,8 +139,10 @@ struct Q_QML_EXPORT Script { Function *function(); - static QQmlRefPointer<CompiledData::CompilationUnit> precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, - QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0); + static QQmlRefPointer<CompiledData::CompilationUnit> precompile( + IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, + const QString &fileName, const QString &finalUrl, const QString &source, + QList<QQmlError> *reportedErrors = 0, QQmlJS::Directives *directivesCollector = 0); static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, QmlContext *qmlContext); }; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 7f1121c1e1..e872b1d92e 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -561,7 +561,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationU Q_D(QQmlComponent); d->compilationUnit = compilationUnit; d->start = start; - d->url = compilationUnit->url(); + d->url = compilationUnit->finalUrl(); d->progress = 1.0; } diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 37cb328b36..59e2c83a63 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -845,14 +845,14 @@ QV4::IdentifierHash<int> &QQmlContextData::detachedPropertyNames() QUrl QQmlContextData::url() const { if (typeCompilationUnit) - return typeCompilationUnit->url(); + return typeCompilationUnit->finalUrl(); return baseUrl; } QString QQmlContextData::urlString() const { if (typeCompilationUnit) - return typeCompilationUnit->fileName(); + return typeCompilationUnit->finalUrlString(); return baseUrlString; } diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 6d0e4b915a..93bb67de20 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -272,7 +272,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!compilationUnit) return; - QML_MEMORY_SCOPE_URL(compilationUnit->url()); + QML_MEMORY_SCOPE_URL(compilationUnit->finalUrl()); QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 3663b06d55..9c6630190f 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -445,7 +445,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QString string = binding->valueAsString(qmlUnit); // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); - QUrl value = string.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(string)); + QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string)); // Apply URL interceptor if (engine->urlInterceptor()) value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString); @@ -643,7 +643,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); QString urlString = binding->valueAsString(qmlUnit); - QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(urlString)); + QUrl u = urlString.isEmpty() ? QUrl() + : compilationUnit->finalUrl().resolved(QUrl(urlString)); QList<QUrl> value; value.append(u); property->writeProperty(_qobject, &value, propertyWriteFlags); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f3077f673b..19e57fbdba 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -356,8 +356,10 @@ qreal QQmlDataBlob::progress() const } /*! -Returns the blob url passed to the constructor. If a network redirect -happens while fetching the data, this url remains the same. +Returns the physical url of the data. Initially this is the same as +finalUrl(), but if a network redirect happens while fetching the data, this url +is updated to reflect the new location. Also, if a URL interceptor is set, it +will work on this URL and leave finalUrl() alone. \sa finalUrl() */ @@ -366,16 +368,25 @@ QUrl QQmlDataBlob::url() const return m_url; } +QString QQmlDataBlob::urlString() const +{ + if (m_urlString.isEmpty()) + m_urlString = m_url.toString(); + + return m_urlString; +} + /*! -Returns the final url of the data. Initially this is the same as -url(), but if a network redirect happens while fetching the data, this url -is updated to reflect the new location. +Returns the logical URL to be used for resolving further URLs referred to in +the code. -May only be called from the load thread, or after the blob isCompleteOrError(). +This is the blob url passed to the constructor. If a network redirect +happens while fetching the data, this url remains the same. + +\sa url() */ QUrl QQmlDataBlob::finalUrl() const { - Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread())); return m_finalUrl; } @@ -384,7 +395,6 @@ Returns the finalUrl() as a string. */ QString QQmlDataBlob::finalUrlString() const { - Q_ASSERT(isCompleteOrError() || (m_typeLoader && m_typeLoader->m_thread->isThisThread())); if (m_finalUrlString.isEmpty()) m_finalUrlString = m_finalUrl.toString(); @@ -433,7 +443,7 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors) m_data.setStatus(Error); if (dumpErrors()) { - qWarning().nospace() << "Errors for " << m_finalUrl.toString(); + qWarning().nospace() << "Errors for " << urlString(); for (int ii = 0; ii < errors.count(); ++ii) qWarning().nospace() << " " << qPrintable(errors.at(ii).toString()); } @@ -472,7 +482,7 @@ void QQmlDataBlob::setError(const QString &description) { QQmlError e; e.setDescription(description); - e.setUrl(finalUrl()); + e.setUrl(url()); setError(e); } @@ -537,7 +547,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError) Q_UNUSED(networkError); QQmlError error; - error.setUrl(m_finalUrl); + error.setUrl(m_url); const char *errorString = 0; switch (networkError) { @@ -654,7 +664,7 @@ void QQmlDataBlob::tryDone() addref(); #ifdef DATABLOB_DEBUG - qWarning("QQmlDataBlob::done() %s", qPrintable(url().toString())); + qWarning("QQmlDataBlob::done() %s", qPrintable(urlString())); #endif done(); @@ -893,7 +903,7 @@ void QQmlTypeLoaderThread::callCompletedMain(QQmlDataBlob *b) { QML_MEMORY_SCOPE_URL(b->url()); #ifdef DATABLOB_DEBUG - qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->url().toString())); + qWarning("QQmlTypeLoaderThread: %s completed() callback", qPrintable(b->urlString())); #endif b->completed(); b->release(); @@ -903,7 +913,7 @@ void QQmlTypeLoaderThread::callDownloadProgressChangedMain(QQmlDataBlob *b, qrea { #ifdef DATABLOB_DEBUG qWarning("QQmlTypeLoaderThread: %s downloadProgressChanged(%f) callback", - qPrintable(b->url().toString()), p); + qPrintable(b->urlString()), p); #endif b->downloadProgressChanged(p); b->release(); @@ -1037,7 +1047,7 @@ template<typename Loader> void QQmlTypeLoader::doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode) { #ifdef DATABLOB_DEBUG - qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->m_url.toString()), + qWarning("QQmlTypeLoader::doLoad(%s): %s thread", qPrintable(blob->urlString()), m_thread->isThisThread()?"Compile":"Engine"); #endif blob->startLoading(); @@ -1159,7 +1169,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) } #ifdef DATABLOB_DEBUG - qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString())); + qWarning("QQmlDataBlob: requested %s", qPrintable(blob->urlString())); #endif // DATABLOB_DEBUG #endif // qml_network } @@ -1185,14 +1195,15 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); if (redirect.isValid()) { QUrl url = reply->url().resolved(redirect.toUrl()); - blob->m_finalUrl = url; + blob->m_url = url; + blob->m_urlString.clear(); QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(url)); QObject *nrp = m_thread->networkReplyProxy(); QObject::connect(reply, SIGNAL(finished()), nrp, SLOT(finished())); m_networkReplies.insert(reply, blob); #ifdef DATABLOB_DEBUG - qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->m_finalUrl.toString())); + qWarning("QQmlDataBlob: redirected to %s", qPrintable(blob->urlString())); #endif return; } @@ -1348,7 +1359,7 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData: bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors) { - QString qmldirIdentifier = data->url().toString(); + QString qmldirIdentifier = data->urlString(); QString qmldirUrl = qmldirIdentifier.left(qmldirIdentifier.lastIndexOf(QLatin1Char('/')) + 1); typeLoader()->setQmldirContent(qmldirIdentifier, data->content()); @@ -2104,7 +2115,7 @@ bool QQmlTypeData::tryLoadFromDiskCache() { QString error; if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), v4->iselFactory.data(), &error)) { - qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error; + qCDebug(DBG_DISK_CACHE) << "Error loading" << urlString() << "from disk cache:" << error; return false; } } @@ -2224,10 +2235,10 @@ void QQmlTypeData::done() if (script.script->isError()) { QList<QQmlError> errors = script.script->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(script.location.line); error.setColumn(script.location.column); - error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString())); + error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); return; @@ -2244,7 +2255,7 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(type.location.line); error.setColumn(type.location.column); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); @@ -2263,7 +2274,7 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(type.location.line); error.setColumn(type.location.column); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); @@ -2293,7 +2304,7 @@ void QQmlTypeData::done() // verify if any dependencies changed if we're using a cache if (m_document.isNull() && !m_compiledData->verifyChecksum(dependencyHasher)) { - qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString(); + qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->fileName(); if (!loadFromSource()) return; m_backupSourceCode = SourceCodeData(); @@ -2458,7 +2469,7 @@ bool QQmlTypeData::loadFromSource() errors.reserve(compiler.errors.count()); for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { QQmlError e; - e.setUrl(finalUrl()); + e.setUrl(url()); e.setLine(msg.loc.startLine); e.setColumn(msg.loc.startColumn); e.setDescription(msg.message); @@ -2475,7 +2486,8 @@ void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_document.reset(new QmlIR::Document(isDebugging())); QmlIR::IRLoader loader(unit->data, m_document.data()); loader.load(); - m_document->jsModule.setFileName(finalUrlString()); + m_document->jsModule.setFileName(urlString()); + m_document->jsModule.setFinalUrl(finalUrlString()); m_document->javaScriptCompilationUnit = unit; continueLoadFromIR(); } @@ -2598,7 +2610,7 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCach // ignore error, keep using the in-memory compilation unit. } } else { - qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString; + qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->fileName() << "to disk:" << errorString; } } } @@ -2969,7 +2981,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) initializeFromCompilationUnit(unit); return; } else { - qCDebug(DBG_DISK_CACHE()) << "Error loading" << url().toString() << "from disk cache:" << error; + qCDebug(DBG_DISK_CACHE()) << "Error loading" << urlString() << "from disk cache:" << error; } } @@ -2987,7 +2999,9 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator); QList<QQmlError> errors; - QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile(&irUnit.jsModule, &irUnit.jsGenerator, v4, finalUrl(), source, &errors, &collector); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile( + &irUnit.jsModule, &irUnit.jsGenerator, v4, urlString(), finalUrlString(), + source, &errors, &collector); // No need to addref on unit, it's initial refcount is 1 source.clear(); if (!errors.isEmpty()) { @@ -3011,7 +3025,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) if (!disableDiskCache() || forceDiskCache()) { QString errorString; if (!unit->saveToDisk(url(), &errorString)) { - qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->url().toString() << "to disk:" << errorString; + qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString; } } @@ -3035,10 +3049,10 @@ void QQmlScriptBlob::done() if (script.script->isError()) { QList<QQmlError> errors = script.script->errors(); QQmlError error; - error.setUrl(finalUrl()); + error.setUrl(url()); error.setLine(script.location.line); error.setColumn(script.location.column); - error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString())); + error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); return; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 22ac61968f..ab32bac7b2 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -129,6 +129,7 @@ public: qreal progress() const; QUrl url() const; + QString urlString() const; QUrl finalUrl() const; QString finalUrlString() const; @@ -207,6 +208,7 @@ private: QUrl m_url; QUrl m_finalUrl; + mutable QString m_urlString; mutable QString m_finalUrlString; // List of QQmlDataBlob's that are waiting for me to complete. |