diff options
| author | Sami Shalayel <sami.shalayel@qt.io> | 2025-03-25 16:08:43 +0100 |
|---|---|---|
| committer | Sami Shalayel <sami.shalayel@qt.io> | 2025-04-04 14:51:21 +0200 |
| commit | bf6b29fbe87d01e5fa3066b29593f3315c3acfe0 (patch) | |
| tree | 2d0c366893700baa948b08e69d53224813ea7759 | |
| parent | 934831b0625d9fcaaf5649a083afdd1c2026ebc9 (diff) | |
qmllint: implement WarnEval
Complain about usages of Eval in qmllint, and make the
qqmljstypepropagator analyze eval calls.
Task-number: QTBUG-129307
Change-Id: I577612220383c624e960db60ed755e0f2dbc59aa
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
| -rw-r--r-- | src/qmlcompiler/qqmljslinter.cpp | 8 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljslogger.cpp | 3 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljsloggingutils.h | 1 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstypepropagator.cpp | 15 | ||||
| -rw-r--r-- | tests/auto/qml/qmllint/tst_qmllint.cpp | 9 |
5 files changed, 33 insertions, 3 deletions
diff --git a/src/qmlcompiler/qqmljslinter.cpp b/src/qmlcompiler/qqmljslinter.cpp index 77771f8e13..16e193d156 100644 --- a/src/qmlcompiler/qqmljslinter.cpp +++ b/src/qmlcompiler/qqmljslinter.cpp @@ -583,6 +583,14 @@ QQmlJSLinter::LintResult QQmlJSLinter::lintFile(const QString &filename, std::make_unique<QQmlJSTranslationFunctionMismatchCheck>(passMan.get()), QString(), QString(), QString()); + QQmlSA::PropertyPassBuilder(passMan.get()) + .withOnCall([](QQmlSA::PropertyPass *self, const QQmlSA::Element &, + const QString &, const QQmlSA::Element &, + QQmlSA::SourceLocation location) { + self->emitWarning("Do not use 'eval'", qmlEval, location); + }) + .registerOnBuiltin("GlobalObject", "eval"); + if (m_enablePlugins) { for (const Plugin &plugin : m_plugins) { if (!plugin.isValid() || !plugin.isEnabled()) diff --git a/src/qmlcompiler/qqmljslogger.cpp b/src/qmlcompiler/qqmljslogger.cpp index d289c80f52..de666e25f3 100644 --- a/src/qmlcompiler/qqmljslogger.cpp +++ b/src/qmlcompiler/qqmljslogger.cpp @@ -105,7 +105,8 @@ using namespace Qt::StringLiterals; X(qmlMissingEnumEntry, "missing-enum-entry", "MissingEnumEntry", \ "Warn about using missing enum values.", QtWarningMsg, false, false) \ X(qmlAssignmentInCondition, "assignment-in-condition", "AssignmentInCondition", \ - "Warn about using assignment in conditions.", QtWarningMsg, false, false) + "Warn about using assignment in conditions.", QtWarningMsg, false, false) \ + X(qmlEval, "eval", "Eval", "Warn about uses of eval()", QtWarningMsg, false, false) #define X(category, name, setting, description, level, ignored, isDefault) \ const QQmlSA::LoggerWarningId category{ name }; diff --git a/src/qmlcompiler/qqmljsloggingutils.h b/src/qmlcompiler/qqmljsloggingutils.h index c7431e7cc2..7dde44bf41 100644 --- a/src/qmlcompiler/qqmljsloggingutils.h +++ b/src/qmlcompiler/qqmljsloggingutils.h @@ -78,6 +78,7 @@ extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlTranslationFunction extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlUncreatableType; extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlMissingEnumEntry; extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlAssignmentInCondition; +extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlEval; QT_END_NAMESPACE diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp index c0a69a8ddd..d880e66030 100644 --- a/src/qmlcompiler/qqmljstypepropagator.cpp +++ b/src/qmlcompiler/qqmljstypepropagator.cpp @@ -1899,6 +1899,21 @@ void QQmlJSTypePropagator::generate_CallPossiblyDirectEval(int argc, int argv) m_state.setHasSideEffects(true); Q_UNUSED(argc) Q_UNUSED(argv) + + // qmllint needs to be able to warn about eval calls + if (m_passManager) { + const QQmlSA::SourceLocation saLocation{ + QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(currentSourceLocation()) + }; + const QQmlSA::Element saBaseType{ QQmlJSScope::createQQmlSAElement( + m_typeResolver->jsGlobalObject()) }; + const QQmlSA::Element saContainedType{ QQmlJSScope::createQQmlSAElement( + m_function->qmlScope.containedType()) }; + + QQmlSA::PassManagerPrivate::get(m_passManager) + ->analyzeCall(saBaseType, "eval"_L1, saContainedType, saLocation); + } + INSTR_PROLOGUE_NOT_IMPLEMENTED_POPULATES_ACC(); } diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index 51ddc6fd66..743e20f77f 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -1451,6 +1451,13 @@ void TestQmllint::dirtyJsSnippet_data() << Result{ { { "Assignment in condition: did you meant to use \"===\" or \"==\" " "instead of \"=\"?"_L1, 1, 21 } } }; + QTest::newRow("eval") << u"let x = eval();"_s << Result{ { { "Do not use 'eval'"_L1, 1, 9 } } }; + QTest::newRow("eval2") << u"let x = eval(\"1 + 1\");"_s + << Result{ { { "Do not use 'eval'"_L1, 1, 9 } } }; + QTest::newRow("indirectEval") << u"let x = (1, eval)();"_s + << Result{ { { "Do not use 'eval'"_L1, 1, 13 } } }; + QTest::newRow("indirectEval2") << u"let x = (1, eval)(\"1 + 1\");"_s + << Result{ { { "Do not use 'eval'"_L1, 1, 13 } } }; } void TestQmllint::dirtyJsSnippet() @@ -1482,8 +1489,6 @@ void TestQmllint::cleanJsSnippet_data() QTest::newRow("doubleInDifferentScopes") << u"const a = 42; for (let a = 1; a < 10; ++a) {}"_s; QTest::newRow("notAssignmentInCondition") << u"let x = 3; if (x==3) return;"_s; - QTest::newRow("eval") << u"eval()"_s; - QTest::newRow("eval2") << u"eval(\"1 + 1\")"_s; } void TestQmllint::cleanJsSnippet() |
