aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorOlivier De Cannière <[email protected]>2025-05-28 15:00:38 +0200
committerOlivier De Cannière <[email protected]>2025-05-30 22:25:39 +0200
commit2e00bc40cce9286dcb1ef9ff88845778c316592c (patch)
tree3806195ff655f2c41443748d4da8229d8c3b3ef6 /src
parentafc5a1c6f49e33cee07d098728e3c0702e95d168 (diff)
qmllint: Warn about unintentional empty blocksHEADdev
If a property binding is a js block without any statements, it could mean that the user intended to create an object literal instead of an empty block that returns undefined. Task-number: QTBUG-129307 Change-Id: If242ddac140cce6479062194b785096ba1f6c0a6 Reviewed-by: Fabian Kosmale <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h2
-rw-r--r--src/qmlcompiler/qqmljslintervisitor.cpp16
-rw-r--r--src/qmlcompiler/qqmljslintervisitor_p.h3
-rw-r--r--src/qmlcompiler/qqmljslogger.cpp2
-rw-r--r--src/qmlcompiler/qqmljsloggingutils.h1
5 files changed, 23 insertions, 1 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index 32f6915b32..c13f09f112 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -305,7 +305,7 @@ protected:
enum class BindingExpressionParseResult { Invalid, Script, Literal, Translation };
enum class BindingForPropertyDefintion { Yes, No };
- BindingExpressionParseResult parseBindingExpression(
+ virtual BindingExpressionParseResult parseBindingExpression(
const QString &name, const QQmlJS::AST::Statement *statement,
const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition = nullptr);
bool isImportPrefix(QString prefix) const;
diff --git a/src/qmlcompiler/qqmljslintervisitor.cpp b/src/qmlcompiler/qqmljslintervisitor.cpp
index b5d254a00c..540ba6c535 100644
--- a/src/qmlcompiler/qqmljslintervisitor.cpp
+++ b/src/qmlcompiler/qqmljslintervisitor.cpp
@@ -416,6 +416,22 @@ bool LinterVisitor::visit(ExpressionStatement *ast)
return true;
}
+QQmlJSImportVisitor::BindingExpressionParseResult LinterVisitor::parseBindingExpression(
+ const QString &name, const QQmlJS::AST::Statement *statement,
+ const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition)
+{
+ if (statement && statement->kind == (int)AST::Node::Kind::Kind_Block) {
+ const auto *block = static_cast<const AST::Block *>(statement);
+ if (!block->statements && associatedPropertyDefinition) {
+ m_logger->log("Unintentional empty block, use ({}) for empty object literal"_L1,
+ qmlUnintentionalEmptyBlock,
+ combine(block->lbraceToken, block->rbraceToken));
+ }
+ }
+
+ return QQmlJSImportVisitor::parseBindingExpression(name, statement, associatedPropertyDefinition);
+}
+
void LinterVisitor::handleLiteralBinding(const QQmlJSMetaPropertyBinding &binding,
const UiPublicMember *associatedPropertyDefinition)
{
diff --git a/src/qmlcompiler/qqmljslintervisitor_p.h b/src/qmlcompiler/qqmljslintervisitor_p.h
index 416dc972c1..efec9b3abf 100644
--- a/src/qmlcompiler/qqmljslintervisitor_p.h
+++ b/src/qmlcompiler/qqmljslintervisitor_p.h
@@ -92,6 +92,9 @@ private:
void warnCaseNoFlowControl(QQmlJS::SourceLocation caseToken) const;
void checkCaseFallthrough(QQmlJS::AST::StatementList *statements, SourceLocation errorLoc,
SourceLocation nextLoc);
+ BindingExpressionParseResult parseBindingExpression(
+ const QString &name, const QQmlJS::AST::Statement *statement,
+ const QQmlJS::AST::UiPublicMember *associatedPropertyDefinition = nullptr) override;
void handleLiteralBinding(const QQmlJSMetaPropertyBinding &binding,
const AST::UiPublicMember *associatedPropertyDefinition) override;
};
diff --git a/src/qmlcompiler/qqmljslogger.cpp b/src/qmlcompiler/qqmljslogger.cpp
index d3cf05fb1d..40bdd9c48d 100644
--- a/src/qmlcompiler/qqmljslogger.cpp
+++ b/src/qmlcompiler/qqmljslogger.cpp
@@ -131,6 +131,8 @@ using namespace Qt::StringLiterals;
false, false) \
X(qmlUncreatableType, "uncreatable-type", "UncreatableType", \
"Warn if uncreatable types are created", QtWarningMsg, false, false) \
+ X(qmlUnintentionalEmptyBlock, "unintentional-empty-block", "UnintentionalEmptyBlock", \
+ "Warn about bindings that contain only an empty block", QtWarningMsg, false, false) \
X(qmlUnqualified, "unqualified", "UnqualifiedAccess", \
"Warn about unqualified identifiers and how to fix them", QtWarningMsg, false, false) \
X(qmlUnreachableCode, "unreachable-code", "UnreachableCode", "Warn about unreachable code.", \
diff --git a/src/qmlcompiler/qqmljsloggingutils.h b/src/qmlcompiler/qqmljsloggingutils.h
index c33fe5a407..05067c7d64 100644
--- a/src/qmlcompiler/qqmljsloggingutils.h
+++ b/src/qmlcompiler/qqmljsloggingutils.h
@@ -88,6 +88,7 @@ extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlSyntaxIdQuotation;
extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlTopLevelComponent;
extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlTranslationFunctionMismatch;
extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlUncreatableType;
+extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlUnintentionalEmptyBlock;
extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlUnqualified;
extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlUnreachableCode;
extern const Q_QMLCOMPILER_EXPORT QQmlSA::LoggerWarningId qmlUnresolvedAlias;