aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qqmlirbuilder.cpp
diff options
context:
space:
mode:
authorOlivier De Cannière <olivier.decanniere@qt.io>2025-09-18 15:12:24 +0200
committerOlivier De Cannière <olivier.decanniere@qt.io>2025-11-05 13:43:51 +0100
commita0a2a239dc8e1a486ae8bdf14ec7fd5db27311e1 (patch)
tree7eab5e7b2f4078a91bc09b99f8b3bbacad749755 /src/qml/compiler/qqmlirbuilder.cpp
parent7a94d502a8ded563e4f228b4cf00e879ce9a72fe (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.cpp85
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"));
}