diff options
| author | Olivier De Cannière <olivier.decanniere@qt.io> | 2025-09-18 15:12:24 +0200 |
|---|---|---|
| committer | Olivier De Cannière <olivier.decanniere@qt.io> | 2025-11-05 13:43:51 +0100 |
| commit | a0a2a239dc8e1a486ae8bdf14ec7fd5db27311e1 (patch) | |
| tree | 7eab5e7b2f4078a91bc09b99f8b3bbacad749755 /src/qml/compiler/qqmlirbuilder.cpp | |
| parent | 7a94d502a8ded563e4f228b4cf00e879ce9a72fe (diff) | |
qmllint: Also lint inner functions
We were only collecting the 'QML' functions that would be passed to the
AOT compiler. Other function types were ignored.
Also collect those and pass them to the compiler but only use them when
linting. Defer invistigating whether it is a good idea to try to
compile JS functions as well to a later point.
Logic in a few places was adapted with this changing assumption.
[ChangeLog][QML][qmllint] qmllint will now lint inner functions,
defined in javascript, in addition to top-level functions and bindings.
Fixes: QTBUG-138845
Pick-to: 6.10 6.8 6.5
Change-Id: If6f62aeace8739442b6a1f355fad95ce19c0643c
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/compiler/qqmlirbuilder.cpp')
| -rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 85 |
1 files changed, 47 insertions, 38 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 484d2e6d9b..bf124a2272 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -138,9 +138,11 @@ QString IRBuilder::sanityCheckFunctionNames(Object *obj, QQmlJS::SourceLocation Function *f = functionit.ptr; errorLocation->startLine = f->location.line(); errorLocation->startColumn = f->location.column(); - if (functionNames.contains(f->nameIndex)) - return tr("Duplicate method name"); - functionNames.insert(f->nameIndex); + if (f->isQmlFunction) { + if (functionNames.contains(f->nameIndex)) + return tr("Duplicate method name"); + functionNames.insert(f->nameIndex); + } for (auto signalit = obj->signalsBegin(); signalit != obj->signalsEnd(); ++signalit) { QmlIR::Signal *s = signalit.ptr; @@ -149,7 +151,8 @@ QString IRBuilder::sanityCheckFunctionNames(Object *obj, QQmlJS::SourceLocation } const QString name = stringAt(f->nameIndex); - if (name.at(0).isUpper()) + Q_ASSERT(!f->isQmlFunction || !name.isEmpty()); + if (!name.isEmpty() && name.at(0).isUpper()) return tr("Method names cannot begin with an upper case letter"); if (QV4::Compiler::Codegen::isNameGlobal(name)) return tr("Illegal method name"); @@ -1096,6 +1099,45 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node) return false; } +void IRBuilder::registerFunctionExpr(QQmlJS::AST::FunctionExpression *fexp, IsQmlFunction isQmlFunction) +{ + CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>(); + foe->node = fexp; + foe->parentNode = fexp; + foe->nameIndex = registerString(fexp->name.toString()); + const int index = _object->functionsAndExpressions->append(foe); + + Function *f = New<Function>(); + QQmlJS::SourceLocation loc = fexp->identifierToken; + f->location.set(loc.startLine, loc.startColumn); + f->index = index; + f->nameIndex = registerString(fexp->name.toString()); + f->isQmlFunction = isQmlFunction == IsQmlFunction::Yes; + + const auto idGenerator = [this](const QString &str) { return registerString(str); }; + + Parameter::initType( + &f->returnType, idGenerator, + fexp->typeAnnotation ? fexp->typeAnnotation->type : nullptr); + + const QQmlJS::AST::BoundNames formals = fexp->formals ? fexp->formals->formals() + : QQmlJS::AST::BoundNames(); + int formalsCount = formals.size(); + f->formals.allocate(pool, formalsCount); + + int i = 0; + for (const auto &arg : formals) { + Parameter *functionParameter = &f->formals[i]; + functionParameter->nameIndex = registerString(arg.id); + Parameter::initType( + &functionParameter->type, idGenerator, + arg.typeAnnotation.isNull() ? nullptr : arg.typeAnnotation->type); + ++i; + } + + _object->appendFunction(f); +} + bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node) { if (QQmlJS::AST::FunctionExpression *funDecl = node->sourceElement->asFunctionDefinition()) { @@ -1106,40 +1148,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node) "QQmlParser", "Function declaration inside grouped property")); return false; } - - CompiledFunctionOrExpression *foe = New<CompiledFunctionOrExpression>(); - foe->node = funDecl; - foe->parentNode = funDecl; - foe->nameIndex = registerString(funDecl->name.toString()); - const int index = _object->functionsAndExpressions->append(foe); - - Function *f = New<Function>(); - QQmlJS::SourceLocation loc = funDecl->identifierToken; - f->location.set(loc.startLine, loc.startColumn); - f->index = index; - f->nameIndex = registerString(funDecl->name.toString()); - - const auto idGenerator = [this](const QString &str) { return registerString(str); }; - - Parameter::initType( - &f->returnType, idGenerator, - funDecl->typeAnnotation ? funDecl->typeAnnotation->type : nullptr); - - const QQmlJS::AST::BoundNames formals = funDecl->formals ? funDecl->formals->formals() : QQmlJS::AST::BoundNames(); - int formalsCount = formals.size(); - f->formals.allocate(pool, formalsCount); - - int i = 0; - for (const auto &arg : formals) { - Parameter *functionParameter = &f->formals[i]; - functionParameter->nameIndex = registerString(arg.id); - Parameter::initType( - &functionParameter->type, idGenerator, - arg.typeAnnotation.isNull() ? nullptr : arg.typeAnnotation->type); - ++i; - } - - _object->appendFunction(f); + registerFunctionExpr(funDecl, IsQmlFunction::Yes); } else { recordError(node->firstSourceLocation(), QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element")); } |
