aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Shalayel <sami.shalayel@qt.io>2025-03-25 16:08:43 +0100
committerSami Shalayel <sami.shalayel@qt.io>2025-04-04 14:51:21 +0200
commitbf6b29fbe87d01e5fa3066b29593f3315c3acfe0 (patch)
tree2d0c366893700baa948b08e69d53224813ea7759
parent934831b0625d9fcaaf5649a083afdd1c2026ebc9 (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.cpp8
-rw-r--r--src/qmlcompiler/qqmljslogger.cpp3
-rw-r--r--src/qmlcompiler/qqmljsloggingutils.h1
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp15
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp9
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()