diff options
author | Erik Verbruggen <erik.verbruggen@qt.io> | 2018-10-08 15:13:50 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@qt.io> | 2018-10-15 10:19:22 +0000 |
commit | 67fbdadb3ba1aa9f86ae2d6ca3bff69479fb12be (patch) | |
tree | 8f3e5e56f14350c64276cdda88b6a477806fe8f6 | |
parent | 50be4991d205bd392d6998b6fec88bb92a9e9e9a (diff) |
Fix translation contexts for paths with drive letters on Windows
Inside method_qtTr, the filename is assumed to be a (correct) URL. When
a (normalized) path with a windows drive letter is passed to
QJSEngine::evaluate, the URL will have a scheme that is the drive
letter. We cannot correct this in method_qtTr, because at that point we
might get in files that do not come from the file system, but through
actual URLs. The place where we know for sure that the filename is a
real file name and not a URL, is in QJSEngine::evaluate. So at that
point, make sure that the filename is a valid URL.
Task-number: QTBUG-70425
Change-Id: Ia41859c4024ac46e6f8c3d96057a5dffdecd8f56
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp | 4 | ||||
-rw-r--r-- | src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 28 | ||||
-rw-r--r-- | tests/auto/qml/qjsengine/tst_qjsengine.cpp | 69 |
4 files changed, 85 insertions, 19 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp index 3170ee0c1b..5521e7628b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -157,7 +157,7 @@ void QV4Debugger::clearPauseRequest() QV4Debugger::ExecutionState QV4Debugger::currentExecutionState() const { ExecutionState state; - state.fileName = getFunction()->sourceFile(); + state.fileName = QUrl(getFunction()->sourceFile()).fileName(); state.lineNumber = engine()->currentStackFrame->lineNumber(); return state; @@ -288,7 +288,7 @@ void QV4Debugger::pauseAndWait(PauseReason reason) bool QV4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) { QHash<BreakPoint, QString>::iterator it = m_breakPoints.find( - BreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr)); + BreakPoint(QUrl(filename).fileName(), linenr)); if (it == m_breakPoints.end()) return false; QString condition = it.value(); diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index ceaa8a8de1..a5c2f40420 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -689,8 +689,7 @@ bool NativeDebugger::reallyHitTheBreakPoint(const QV4::Function *function, int l for (int i = 0, n = m_service->m_breakHandler->m_breakPoints.size(); i != n; ++i) { const BreakPoint &bp = m_service->m_breakHandler->m_breakPoints.at(i); if (bp.lineNumber == lineNumber) { - const QString fileName = function->sourceFile(); - const QStringRef base = fileName.midRef(fileName.lastIndexOf('/') + 1); + const QString base = QUrl(function->sourceFile()).fileName(); if (bp.fileName.endsWith(base)) { if (bp.condition.isEmpty() || checkCondition(bp.condition)) { BreakPoint &mbp = m_service->m_breakHandler->m_breakPoints[i]; diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index b5eadf483a..69e1436c0a 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -469,6 +469,17 @@ void QJSEngine::installExtensions(QJSEngine::Extensions extensions, const QJSVal QV4::GlobalExtensions::init(obj, extensions); } +static QUrl urlForFileName(const QString &fileName) +{ + if (!fileName.startsWith(QLatin1Char(':'))) + return QUrl::fromLocalFile(fileName); + + QUrl url; + url.setPath(fileName.mid(1)); + url.setScheme(QLatin1String("qrc")); + return url; +} + /*! Evaluates \a program, using \a lineNumber as the base line number, and returns the result of the evaluation. @@ -503,7 +514,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in QV4::Scope scope(v4); QV4::ScopedValue result(scope); - QV4::Script script(v4->rootContext(), QV4::Compiler::ContextType::Global, program, fileName, lineNumber); + QV4::Script script(v4->rootContext(), QV4::Compiler::ContextType::Global, program, urlForFileName(fileName).toString(), lineNumber); script.strictMode = false; if (v4->currentStackFrame) script.strictMode = v4->currentStackFrame->v4Function->isStrict(); @@ -521,19 +532,6 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in return retval; } -static QUrl moduleUrlForFileName(const QString &fileName) -{ - QString absolutePath = QFileInfo(fileName).canonicalFilePath(); - if (!absolutePath.startsWith(QLatin1Char(':'))) - return QUrl::fromLocalFile(absolutePath); - - absolutePath.remove(0, 1); - QUrl url; - url.setPath(absolutePath); - url.setScheme(QLatin1String("qrc")); - return url; -} - /*! Imports the module located at \a fileName and returns a module namespace object that contains all exported variables, constants and functions as properties. @@ -556,7 +554,7 @@ static QUrl moduleUrlForFileName(const QString &fileName) */ QJSValue QJSEngine::importModule(const QString &fileName) { - const QUrl url = moduleUrlForFileName(fileName); + const QUrl url = urlForFileName(QFileInfo(fileName).canonicalFilePath()); auto moduleUnit = m_v4Engine->loadModule(url); if (m_v4Engine->hasException) return QJSValue(m_v4Engine, m_v4Engine->catchException()); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 6bc0359483..a38224ef81 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -177,6 +177,8 @@ private slots: void translateScriptUnicodeIdBased_data(); void translateScriptUnicodeIdBased(); void translateFromBuiltinCallback(); + void translationFilePath_data(); + void translationFilePath(); void installConsoleFunctions(); void logging(); @@ -3915,6 +3917,73 @@ void tst_QJSEngine::translateFromBuiltinCallback() eng.evaluate("[10,20].forEach(foo)", "script.js"); } +void tst_QJSEngine::translationFilePath_data() +{ + QTest::addColumn<QString>("filename"); + + QTest::newRow("relative") << QStringLiteral("script.js"); + QTest::newRow("absolute unix") << QStringLiteral("/script.js"); + QTest::newRow("absolute /windows/") << QStringLiteral("c:/script.js"); +#ifdef Q_OS_WIN + QTest::newRow("absolute \\windows\\") << QStringLiteral("c:\\script.js"); +#endif + QTest::newRow("relative url") << QStringLiteral("file://script.js"); + QTest::newRow("absolute url unix") << QStringLiteral("file:///script.js"); + QTest::newRow("absolute url windows") << QStringLiteral("file://c:/script.js"); +} + +class DummyTranslator : public QTranslator +{ + Q_OBJECT + +public: + DummyTranslator(const char *sourceText) + : srcTxt(sourceText) + {} + + QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const override + { + Q_UNUSED(disambiguation); + Q_UNUSED(n); + + if (srcTxt == sourceText) + ctxt = QByteArray(context); + + return QString(sourceText); + } + + bool isEmpty() const override + { + return false; + } + + const char *sourceText() const + { return srcTxt.constData(); } + + QByteArray context() const + { return ctxt; } + +private: + QByteArray srcTxt; + mutable QByteArray ctxt; +}; + +void tst_QJSEngine::translationFilePath() +{ + QFETCH(QString, filename); + + DummyTranslator translator("some text"); + QCoreApplication::installTranslator(&translator); + QByteArray scriptContent = QByteArray("qsTr('%1')").replace("%1", translator.sourceText()); + + QJSEngine engine; + engine.installExtensions(QJSEngine::TranslationExtension); + QJSValue result = engine.evaluate(scriptContent, filename); + QCOMPARE(translator.context(), QByteArray("script")); + + QCoreApplication::removeTranslator(&translator); +} + void tst_QJSEngine::installConsoleFunctions() { QJSEngine engine; |