aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler/qqmljsfunctioninitializer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlcompiler/qqmljsfunctioninitializer.cpp')
-rw-r--r--src/qmlcompiler/qqmljsfunctioninitializer.cpp98
1 files changed, 57 insertions, 41 deletions
diff --git a/src/qmlcompiler/qqmljsfunctioninitializer.cpp b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
index 997771489b..09928364b1 100644
--- a/src/qmlcompiler/qqmljsfunctioninitializer.cpp
+++ b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
@@ -8,6 +8,8 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qfileinfo.h>
+#include <QtQml/private/qqmlsignalnames_p.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -59,6 +61,7 @@ void QQmlJSFunctionInitializer::populateSignature(
error->type = QtWarningMsg;
error->loc = ast->firstSourceLocation();
error->message = message;
+ function->isFullyTyped = false;
};
if (!m_typeResolver->canCallJSFunctions()) {
@@ -71,6 +74,11 @@ void QQmlJSFunctionInitializer::populateSignature(
if (ast->formals)
arguments = ast->formals->formals();
+ // If the function has no arguments and no return type annotation we assume it's untyped.
+ // You can annotate it to return void to make it typed.
+ // Otherwise we first assume it's typed and reset the flag if we detect a problem.
+ function->isFullyTyped = !arguments.isEmpty() || ast->typeAnnotation;
+
if (function->argumentTypes.isEmpty()) {
for (const QQmlJS::AST::BoundName &argument : std::as_const(arguments)) {
if (argument.typeAnnotation) {
@@ -108,10 +116,11 @@ void QQmlJSFunctionInitializer::populateSignature(
}
}
- if (!function->returnType) {
+ if (!function->returnType.isValid()) {
if (ast->typeAnnotation) {
- function->returnType = m_typeResolver->typeFromAST(ast->typeAnnotation->type);
- if (!function->returnType)
+ function->returnType = m_typeResolver->globalType(
+ m_typeResolver->typeFromAST(ast->typeAnnotation->type));
+ if (!function->returnType.isValid())
signatureError(u"Cannot resolve return type %1"_s.arg(
QmlIR::IRBuilder::asString(ast->typeAnnotation->type->typeId)));
}
@@ -160,44 +169,45 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run(
}
function.isProperty = m_objectType->hasProperty(propertyName);
- if (!function.isProperty && QmlIR::IRBuilder::isSignalPropertyName(propertyName)) {
- const QString signalName = QmlIR::IRBuilder::signalNameFromSignalPropertyName(propertyName);
-
- if (signalName.endsWith(u"Changed"_s)
- && m_objectType->hasProperty(signalName.chopped(strlen("Changed")))) {
- function.isSignalHandler = true;
- } else {
- const auto methods = m_objectType->methods(signalName);
- for (const auto &method : methods) {
- if (method.isCloned())
- continue;
- if (method.methodType() == QQmlJSMetaMethod::Signal) {
- function.isSignalHandler = true;
- const auto arguments = method.parameters();
- for (qsizetype i = 0, end = arguments.size(); i < end; ++i) {
- const auto &type = arguments[i].type();
- if (type.isNull()) {
- diagnose(u"Cannot resolve the argument type %1."_s.arg(
- arguments[i].typeName()),
- QtDebugMsg, bindingLocation, error);
- function.argumentTypes.append(
+ if (!function.isProperty) {
+ if (QQmlSignalNames::isHandlerName(propertyName)) {
+ if (auto actualPropertyName =
+ QQmlSignalNames::changedHandlerNameToPropertyName(propertyName);
+ actualPropertyName && m_objectType->hasProperty(*actualPropertyName)) {
+ function.isSignalHandler = true;
+ } else {
+ auto signalName = QQmlSignalNames::handlerNameToSignalName(propertyName);
+ const auto methods = m_objectType->methods(*signalName);
+ for (const auto &method : methods) {
+ if (method.isCloned())
+ continue;
+ if (method.methodType() == QQmlJSMetaMethodType::Signal) {
+ function.isSignalHandler = true;
+ const auto arguments = method.parameters();
+ for (qsizetype i = 0, end = arguments.size(); i < end; ++i) {
+ const auto &type = arguments[i].type();
+ if (type.isNull()) {
+ diagnose(u"Cannot resolve the argument type %1."_s.arg(
+ arguments[i].typeName()),
+ QtDebugMsg, bindingLocation, error);
+ function.argumentTypes.append(
m_typeResolver->tracked(
- m_typeResolver->globalType(m_typeResolver->varType())));
- } else {
- function.argumentTypes.append(m_typeResolver->tracked(
- m_typeResolver->globalType(type)));
+ m_typeResolver->globalType(m_typeResolver->varType())));
+ } else {
+ function.argumentTypes.append(m_typeResolver->tracked(
+ m_typeResolver->globalType(type)));
+ }
}
+ break;
}
- break;
+ }
+ if (!function.isSignalHandler) {
+ diagnose(u"Could not compile signal handler for %1: The signal does not exist"_s.arg(
+ *signalName),
+ QtWarningMsg, bindingLocation, error);
}
}
}
-
- if (!function.isSignalHandler) {
- diagnose(u"Could not compile signal handler for %1: The signal does not exist"_s.arg(
- signalName),
- QtWarningMsg, bindingLocation, error);
- }
}
if (!function.isSignalHandler) {
@@ -209,13 +219,19 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run(
const auto property = m_objectType->property(propertyName);
if (const QQmlJSScope::ConstPtr propertyType = property.type()) {
- function.returnType = propertyType->isListProperty()
- ? m_typeResolver->qObjectListType()
- : propertyType;
+ function.returnType = m_typeResolver->globalType(propertyType->isListProperty()
+ ? m_typeResolver->qObjectListType()
+ : QQmlJSScope::ConstPtr(property.type()));
} else {
- diagnose(u"Cannot resolve property type %1 for binding on %2"_s.arg(
- property.typeName(), propertyName),
- QtWarningMsg, bindingLocation, error);
+ QString message = u"Cannot resolve property type %1 for binding on %2."_s
+ .arg(property.typeName(), propertyName);
+ if (m_objectType->isNameDeferred(propertyName)) {
+ // If the property doesn't exist but the name is deferred, then
+ // it's deferred via the presence of immediate names. Those are
+ // most commonly used to enable generalized grouped properties.
+ message += u" You may want use ID-based grouped properties here.";
+ }
+ diagnose(message, QtWarningMsg, bindingLocation, error);
}
if (!property.bindable().isEmpty() && !property.isPrivate())