diff options
Diffstat (limited to 'src/qmlcompiler/qqmljsfunctioninitializer.cpp')
-rw-r--r-- | src/qmlcompiler/qqmljsfunctioninitializer.cpp | 98 |
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()) |