Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmljsfunctioninitializer.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include <private/qqmljsmemorypool_p.h>
7
8#include <QtCore/qloggingcategory.h>
9#include <QtCore/qfileinfo.h>
10
11#include <QtQml/private/qqmlsignalnames_p.h>
12
14
15using namespace Qt::StringLiterals;
16
27{
28 switch (type) {
30 return u"invalid"_s;
32 return u"a boolean"_s;
34 return u"a number"_s;
36 return u"a string"_s;
38 return u"null"_s;
40 return u"a translation"_s;
42 return u"a translation by id"_s;
44 return u"a script"_s;
46 return u"an object"_s;
48 return u"an attached property"_s;
50 return u"a grouped property"_s;
51 }
52
53 return u"nothing"_s;
54}
55
56void QQmlJSFunctionInitializer::populateSignature(
59{
60 const auto signatureError = [&](const QString &message) {
61 error->type = QtWarningMsg;
62 error->loc = ast->firstSourceLocation();
63 error->message = message;
64 function->isFullyTyped = false;
65 };
66
67 if (!m_typeResolver->canCallJSFunctions()) {
68 signatureError(u"Ignoring type annotations as requested "
69 "by pragma FunctionSignatureBehavior"_s);
70 return;
71 }
72
74 if (ast->formals)
75 arguments = ast->formals->formals();
76
77 // If the function has no arguments and no return type annotation we assume it's untyped.
78 // You can annotate it to return void to make it typed.
79 // Otherwise we first assume it's typed and reset the flag if we detect a problem.
80 function->isFullyTyped = !arguments.isEmpty() || ast->typeAnnotation;
81
82 if (function->argumentTypes.isEmpty()) {
83 for (const QQmlJS::AST::BoundName &argument : std::as_const(arguments)) {
84 if (argument.typeAnnotation) {
85 if (const auto type = m_typeResolver->typeFromAST(argument.typeAnnotation->type)) {
86 function->argumentTypes.append(
87 m_typeResolver->tracked(
88 m_typeResolver->globalType(type)));
89 } else {
90 function->argumentTypes.append(
91 m_typeResolver->tracked(
92 m_typeResolver->globalType(m_typeResolver->varType())));
93 signatureError(u"Cannot resolve the argument type %1."_s
94 .arg(argument.typeAnnotation->type->toString()));
95 }
96 } else {
97 function->argumentTypes.append(
98 m_typeResolver->tracked(
99 m_typeResolver->globalType(m_typeResolver->varType())));
100 signatureError(u"Functions without type annotations won't be compiled"_s);
101 }
102 }
103 } else {
104 for (qsizetype i = 0, end = arguments.size(); i != end; ++i) {
106 if (argument.typeAnnotation) {
107 if (const auto type = m_typeResolver->typeFromAST(argument.typeAnnotation->type)) {
108 if (!m_typeResolver->registerContains(function->argumentTypes[i], type)) {
109 signatureError(u"Type annotation %1 on signal handler "
110 "contradicts signal argument type %2"_s
111 .arg(argument.typeAnnotation->type->toString(),
112 function->argumentTypes[i].descriptiveName()));
113 }
114 }
115 }
116 }
117 }
118
119 if (!function->returnType.isValid()) {
120 if (ast->typeAnnotation) {
121 function->returnType = m_typeResolver->globalType(
122 m_typeResolver->typeFromAST(ast->typeAnnotation->type));
123 if (!function->returnType.isValid())
124 signatureError(u"Cannot resolve return type %1"_s.arg(
126 }
127 }
128
129 for (int i = QQmlJSCompilePass::FirstArgument + function->argumentTypes.size();
130 i < context->registerCountInFunction; ++i) {
131 function->registerTypes.append(m_typeResolver->tracked(
132 m_typeResolver->globalType(m_typeResolver->voidType())));
133 }
134
135 function->addressableScopes = m_typeResolver->objectsById();
136 function->code = context->code;
137 function->sourceLocations = context->sourceLocationTable.get();
138}
139
150
153 const QString &propertyName,
154 QQmlJS::AST::Node *astNode,
155 const QmlIR::Binding &irBinding,
157{
158 QQmlJS::SourceLocation bindingLocation;
159 bindingLocation.startLine = irBinding.location.line();
160 bindingLocation.startColumn = irBinding.location.column();
161
163 function.qmlScope = m_scopeType;
164
165 if (irBinding.type() != QmlIR::Binding::Type_Script) {
166 diagnose(u"Binding is not a script binding, but %1."_s.arg(
168 QtDebugMsg, bindingLocation, error);
169 }
170
171 function.isProperty = m_objectType->hasProperty(propertyName);
172 if (!function.isProperty) {
173 if (QQmlSignalNames::isHandlerName(propertyName)) {
174 if (auto actualPropertyName =
176 actualPropertyName && m_objectType->hasProperty(*actualPropertyName)) {
177 function.isSignalHandler = true;
178 } else {
179 auto signalName = QQmlSignalNames::handlerNameToSignalName(propertyName);
180 const auto methods = m_objectType->methods(*signalName);
181 for (const auto &method : methods) {
182 if (method.isCloned())
183 continue;
184 if (method.methodType() == QQmlJSMetaMethodType::Signal) {
185 function.isSignalHandler = true;
186 const auto arguments = method.parameters();
187 for (qsizetype i = 0, end = arguments.size(); i < end; ++i) {
188 const auto &type = arguments[i].type();
189 if (type.isNull()) {
190 diagnose(u"Cannot resolve the argument type %1."_s.arg(
191 arguments[i].typeName()),
192 QtDebugMsg, bindingLocation, error);
193 function.argumentTypes.append(
194 m_typeResolver->tracked(
195 m_typeResolver->globalType(m_typeResolver->varType())));
196 } else {
197 function.argumentTypes.append(m_typeResolver->tracked(
198 m_typeResolver->globalType(type)));
199 }
200 }
201 break;
202 }
203 }
204 if (!function.isSignalHandler) {
205 diagnose(u"Could not compile signal handler for %1: The signal does not exist"_s.arg(
206 *signalName),
207 QtWarningMsg, bindingLocation, error);
208 }
209 }
210 }
211 }
212
213 if (!function.isSignalHandler) {
214 if (!function.isProperty) {
215 diagnose(u"Could not compile binding for %1: The property does not exist"_s.arg(
216 propertyName),
217 QtWarningMsg, bindingLocation, error);
218 }
219
220 const auto property = m_objectType->property(propertyName);
221 if (const QQmlJSScope::ConstPtr propertyType = property.type()) {
222 function.returnType = m_typeResolver->globalType(propertyType->isListProperty()
223 ? m_typeResolver->qObjectListType()
225 } else {
226 QString message = u"Cannot resolve property type %1 for binding on %2."_s
227 .arg(property.typeName(), propertyName);
228 if (m_objectType->isNameDeferred(propertyName)) {
229 // If the property doesn't exist but the name is deferred, then
230 // it's deferred via the presence of immediate names. Those are
231 // most commonly used to enable generalized grouped properties.
232 message += u" You may want use ID-based grouped properties here.";
233 }
234 diagnose(message, QtWarningMsg, bindingLocation, error);
235 }
236
237 if (!property.bindable().isEmpty() && !property.isPrivate())
238 function.isQPropertyBinding = true;
239 }
240
242 auto ast = astNode->asFunctionDefinition();
243 if (!ast) {
244 QQmlJS::AST::Statement *stmt = astNode->statementCast();
245 if (!stmt) {
246 Q_ASSERT(astNode->expressionCast());
248 stmt = new (&pool) QQmlJS::AST::ExpressionStatement(expr);
249 }
250 auto body = new (&pool) QQmlJS::AST::StatementList(stmt);
251 body = body->finish();
252
253 QString name = u"binding for "_s; // ####
255 pool.newString(name), /*formals*/ nullptr, body);
256 ast->lbraceToken = astNode->firstSourceLocation();
257 ast->functionToken = ast->lbraceToken;
258 ast->rbraceToken = astNode->lastSourceLocation();
259 }
260
261 populateSignature(context, ast, &function, error);
262 return function;
263}
264
267 const QString &functionName, QQmlJS::AST::Node *astNode,
269{
270 Q_UNUSED(functionName);
271
273 function.qmlScope = m_scopeType;
274
275 auto ast = astNode->asFunctionDefinition();
276 Q_ASSERT(ast);
277
278 populateSignature(context, ast, &function, error);
279 return function;
280}
281
static JNINativeMethod methods[]
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
QQmlJSCompilePass::Function run(const QV4::Compiler::Context *context, const QString &propertyName, QQmlJS::AST::Node *astNode, const QmlIR::Binding &irBinding, QQmlJS::DiagnosticMessage *error)
bool isNameDeferred(const QString &name) const
QHash< QString, QQmlJSMetaMethod > methods() const
Returns all methods visible from this scope including those of base types and extensions.
QDeferredSharedPointer< const QQmlJSScope > ConstPtr
QQmlJSMetaProperty property(const QString &name) const
bool hasProperty(const QString &name) const
const QQmlJSScopesById & objectsById() const
QQmlJSRegisterContent tracked(const QQmlJSRegisterContent &type) const
QQmlJSScope::ConstPtr qObjectListType() const
bool registerContains(const QQmlJSRegisterContent &reg, const QQmlJSScope::ConstPtr &type) const
QQmlJSRegisterContent globalType(const QQmlJSScope::ConstPtr &type) const
QQmlJSScope::ConstPtr voidType() const
QQmlJSScope::ConstPtr typeFromAST(QQmlJS::AST::Type *type) const
QQmlJSScope::ConstPtr varType() const
ExpressionNode * expressionCast() override
Definition qqmljsast.cpp:85
FormalParameterList * formals
SourceLocation firstSourceLocation() const override
FunctionExpression * asFunctionDefinition() override
StatementList * finish()
Statement * statementCast() override
UiQualifiedId * typeId
static std::optional< QString > changedHandlerNameToPropertyName(QStringView handler)
static bool isHandlerName(QStringView signalName)
static std::optional< QString > handlerNameToSignalName(QStringView handler)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8870
QList< QVariant > arguments
Combined button and popup list for selecting options.
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
QtMsgType
Definition qlogging.h:29
@ QtWarningMsg
Definition qlogging.h:31
@ QtDebugMsg
Definition qlogging.h:30
GLint location
GLuint GLuint end
GLenum type
GLuint GLsizei const GLchar * message
GLuint name
static void diagnose(const QString &message, QtMsgType type, const QQmlJS::SourceLocation &location, QQmlJS::DiagnosticMessage *error)
static QString bindingTypeDescription(QmlIR::Binding::Type type)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
ptrdiff_t qsizetype
Definition qtypes.h:165
const char property[13]
Definition qwizard.cpp:101
QDBusArgument argument
static QString asString(QQmlJS::AST::UiQualifiedId *node)