qmlcompiler: Suggest fix for multiline strings
We can now suggest a template string to use instead that is properly escaped. Once auto-fixing becomes available we can automatically replace deprecated multiline strings with the new suggestion. Task-number: QTBUG-92448 Change-Id: I4e77820b66ae960cde558a62689c5da328b8df5b Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
7e7582fc70
commit
31abba8cdc
|
@ -1112,10 +1112,36 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::StringLiteral *sl)
|
|||
|
||||
if (s.contains(QLatin1Char('\r')) || s.contains(QLatin1Char('\n')) || s.contains(QChar(0x2028u))
|
||||
|| s.contains(QChar(0x2029u))) {
|
||||
QString templateString;
|
||||
|
||||
bool escaped = false;
|
||||
const QChar stringQuote = s[0];
|
||||
for (qsizetype i = 1; i < s.length() - 1; i++) {
|
||||
const QChar c = s[i];
|
||||
|
||||
if (c == u'\\') {
|
||||
escaped = !escaped;
|
||||
} else if (escaped) {
|
||||
// If we encounter an escaped quote, unescape it since we use backticks here
|
||||
if (c == stringQuote)
|
||||
templateString.chop(1);
|
||||
|
||||
escaped = false;
|
||||
} else {
|
||||
if (c == u'`')
|
||||
templateString += u'\\';
|
||||
if (c == u'$' && i + 1 < s.length() - 1 && s[i + 1] == u'{')
|
||||
templateString += u'\\';
|
||||
}
|
||||
|
||||
templateString += c;
|
||||
}
|
||||
|
||||
const FixSuggestion suggestion = { { { u"Use a template literal instead"_qs,
|
||||
sl->literalToken, u"`" + templateString + u"`" } } };
|
||||
m_logger->log(QStringLiteral("String contains unescaped line terminator which is "
|
||||
"deprecated. Use a template "
|
||||
"literal instead."),
|
||||
Log_MultilineString, sl->literalToken);
|
||||
"deprecated."),
|
||||
Log_MultilineString, sl->literalToken, true, true, suggestion);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -241,6 +241,11 @@ void QQmlJSLogger::printFix(const FixSuggestion &fix)
|
|||
m_output.write(issueLocationWithContext.afterText().toString() + u'\n');
|
||||
|
||||
int tabCount = issueLocationWithContext.beforeText().count(u'\t');
|
||||
|
||||
// Do not draw location indicator for multiline replacement strings
|
||||
if (fixItem.replacementString.contains(u'\n'))
|
||||
continue;
|
||||
|
||||
m_output.write(u" "_qs.repeated(
|
||||
issueLocationWithContext.beforeText().length() - tabCount)
|
||||
+ u"\t"_qs.repeated(tabCount)
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import QtQml
|
||||
|
||||
QtObject {
|
||||
property string quote: "
|
||||
quote: \" \\\" \\\\\"
|
||||
ticks: ` \` \\\` \\\`
|
||||
singleTicks: ' \' \\' \\\'
|
||||
expression: \${expr} \${expr} \\\${expr} \\\${expr}
|
||||
"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import QtQml
|
||||
|
||||
QtObject {
|
||||
property string quote: '
|
||||
quote: " \" \\" \\\"
|
||||
ticks: \` \` \\\` \\\`
|
||||
singleTicks: \' \\\' \\\\\'
|
||||
expression: \${expr} \${expr} \\\${expr} \\\${expr}
|
||||
'
|
||||
}
|
|
@ -659,9 +659,26 @@ void TestQmllint::dirtyQmlCode_data()
|
|||
<< QString() << false;
|
||||
QTest::newRow("multilineString")
|
||||
<< QStringLiteral("multilineString.qml")
|
||||
<< QStringLiteral("String contains unescaped line terminator which is deprecated. Use "
|
||||
"a template literal instead.")
|
||||
<< QStringLiteral("String contains unescaped line terminator which is deprecated.")
|
||||
<< QString() << QString() << true;
|
||||
QTest::newRow("multilineStringTortureQuote")
|
||||
<< QStringLiteral("multilineStringTortureQuote.qml")
|
||||
<< QStringLiteral("String contains unescaped line terminator which is deprecated.")
|
||||
<< QString() << QStringLiteral(R"(`
|
||||
quote: " \\" \\\\"
|
||||
ticks: \` \` \\\` \\\`
|
||||
singleTicks: ' \' \\' \\\'
|
||||
expression: \${expr} \${expr} \\\${expr} \\\${expr}
|
||||
`)") << true;
|
||||
QTest::newRow("multilineStringTortureTick")
|
||||
<< QStringLiteral("multilineStringTortureTick.qml")
|
||||
<< QStringLiteral("String contains unescaped line terminator which is deprecated.")
|
||||
<< QString() << QStringLiteral(R"(`
|
||||
quote: " \" \\" \\\"
|
||||
ticks: \` \` \\\` \\\`
|
||||
singleTicks: ' \\' \\\\'
|
||||
expression: \${expr} \${expr} \\\${expr} \\\${expr}
|
||||
`)") << true;
|
||||
QTest::newRow("unresolvedType")
|
||||
<< QStringLiteral("unresolvedType.qml")
|
||||
<< QStringLiteral("UnresolvedType was not found. Did you add all import paths?")
|
||||
|
@ -1278,10 +1295,17 @@ void TestQmllint::searchWarnings(const QJsonArray &warnings, const QString &subs
|
|||
contains = true;
|
||||
break;
|
||||
}
|
||||
if (searchReplacements == DoReplacementSearch
|
||||
&& fix[u"replacement"].toString().contains(substring)) {
|
||||
contains = true;
|
||||
break;
|
||||
if (searchReplacements == DoReplacementSearch) {
|
||||
QString replacement = fix[u"replacement"].toString();
|
||||
#ifdef Q_OS_WIN
|
||||
// Replacements can contain native line endings
|
||||
// but we need them to be uniform in order for them to conform to our test data
|
||||
replacement = replacement.replace(u"\r\n"_qs, u"\n"_qs);
|
||||
#endif
|
||||
if (replacement.contains(substring)) {
|
||||
contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue