aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-11-13 13:40:56 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-11-18 08:54:47 +0100
commitdf179c52ec02aec91058d6977e08a405932af2bd (patch)
tree8415bb0adb85ecdfe43e2f0cd8182acb76c45dd9
parent7e3f5f2224ba0e57a9dffa6251bb002cde564f56 (diff)
QmlCompiler: Fix resolution of method and property types
We need to resolve the types for QML elements in two passes because only after finishing the parsing we have the QML-declared methods and properties available. We already need the base type before, though. Also, there can be multiple methods of the same name. We need API to access them. It also turns out that the internal name of the "var" type has to be QVariant in order to match reality. "var" properties and unnamed arguments to JS functions are implemented as QVariant. Change-Id: I541f11e96db72d832f4e4443d3a5d31079a56575 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/imports/builtins/builtins.qmltypes7
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp18
-rw-r--r--src/qmlcompiler/qqmljsmetatypes_p.h2
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp51
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h4
5 files changed, 56 insertions, 26 deletions
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index 909dab7707..572673e5c1 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -10,13 +10,18 @@ Module {
}
Component {
- name: "QJSValue"
+ name: "QVariant"
accessSemantics: "value"
exports: ["QML/var 1.0", "QML/variant 1.0"]
exportMetaObjectRevisions: [256]
}
Component {
+ name: "QJSValue"
+ accessSemantics: "value"
+ }
+
+ Component {
name: "varargs"
accessSemantics: "value"
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 41e8b4da88..0e16b02846 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -129,6 +129,7 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
void QQmlJSImportVisitor::endVisit(UiObjectDefinition *)
{
+ m_currentScope->resolveTypes(m_rootScopeImports);
m_currentScope->resolveGroupedScopes();
leaveEnvironment();
}
@@ -178,13 +179,19 @@ void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExp
auto name = fexpr->name.toString();
if (!name.isEmpty()) {
if (m_currentScope->scopeType() == QQmlJSScope::QMLScope) {
- QQmlJSMetaMethod method(name, QStringLiteral("void"));
+ QQmlJSMetaMethod method(name);
method.setMethodType(QQmlJSMetaMethod::Method);
- FormalParameterList *parameters = fexpr->formals;
- while (parameters) {
- method.addParameter(parameters->element->bindingIdentifier.toString(), QString());
- parameters = parameters->next;
+ if (const auto *formals = fexpr->formals) {
+ const auto parameters = formals->formals();
+ for (const auto &parameter : parameters) {
+ const QString type = parameter.typeName();
+ method.addParameter(parameter.id,
+ type.isEmpty() ? QStringLiteral("var") : type);
+ }
}
+ method.setReturnTypeName(fexpr->typeAnnotation
+ ? fexpr->typeAnnotation->type->toString()
+ : QStringLiteral("var"));
m_currentScope->addOwnMethod(method);
} else {
m_currentScope->insertJSIdentifier(
@@ -487,6 +494,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
{
+ m_currentScope->resolveTypes(m_rootScopeImports);
m_currentScope->resolveGroupedScopes();
const QQmlJSScope::ConstPtr childScope = m_currentScope;
leaveEnvironment();
diff --git a/src/qmlcompiler/qqmljsmetatypes_p.h b/src/qmlcompiler/qqmljsmetatypes_p.h
index 86a49c89c7..7d00eed199 100644
--- a/src/qmlcompiler/qqmljsmetatypes_p.h
+++ b/src/qmlcompiler/qqmljsmetatypes_p.h
@@ -156,6 +156,8 @@ public:
int revision() const { return m_revision; }
void setRevision(int r) { m_revision = r; }
+ bool isValid() const { return !m_name.isEmpty(); }
+
private:
QString m_name;
QString m_returnTypeName;
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 388de620b0..202e292838 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -85,14 +85,12 @@ bool QQmlJSScope::hasMethod(const QString &name) const
return false;
}
-QQmlJSMetaMethod QQmlJSScope::method(const QString &name) const
+QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name) const
{
- for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
- const auto it = scope->m_methods.find(name);
- if (it != scope->m_methods.end())
- return *it;
- }
- return {};
+ QList<QQmlJSMetaMethod> results;
+ for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data())
+ results.append(scope->ownMethods(name));
+ return results;
}
bool QQmlJSScope::isIdInCurrentQMlScopes(const QString &id) const
@@ -150,20 +148,37 @@ void QQmlJSScope::resolveTypes(const QHash<QString, QQmlJSScope::ConstPtr> &cont
return QQmlJSScope::ConstPtr();
};
- m_baseType = findType(m_baseTypeName);
- m_attachedType = findType(m_attachedTypeName);
- m_valueType = findType(m_valueTypeName);
+ if (!m_baseType && !m_baseTypeName.isEmpty())
+ m_baseType = findType(m_baseTypeName);
- for (auto it = m_properties.begin(), end = m_properties.end(); it != end; ++it)
- it->setType(findType(it->typeName()));
+ if (!m_attachedType && !m_attachedTypeName.isEmpty())
+ m_attachedType = findType(m_attachedTypeName);
- for (auto it = m_methods.begin(), end = m_methods.end(); it != end; ++it) {
- it->setReturnType(findType(it->returnTypeName()));
- const auto paramNames = it->parameterTypeNames();
- QList<QSharedPointer<const QQmlJSScope>> paramTypes;
+ if (!m_valueType && !m_valueTypeName.isEmpty())
+ m_valueType = findType(m_valueTypeName);
- for (const QString &paramName: paramNames)
- paramTypes.append(findType(paramName));
+ for (auto it = m_properties.begin(), end = m_properties.end(); it != end; ++it) {
+ const QString typeName = it->typeName();
+ if (!it->type() && !typeName.isEmpty())
+ it->setType(findType(typeName));
+ }
+
+ for (auto it = m_methods.begin(), end = m_methods.end(); it != end; ++it) {
+ const QString returnTypeName = it->returnTypeName();
+ if (!it->returnType() && !returnTypeName.isEmpty())
+ it->setReturnType(findType(returnTypeName));
+
+ const auto paramTypeNames = it->parameterTypeNames();
+ QList<QSharedPointer<const QQmlJSScope>> paramTypes = it->parameterTypes();
+ if (paramTypes.length() < paramTypeNames.length())
+ paramTypes.resize(paramTypeNames.length());
+
+ for (int i = 0, length = paramTypes.length(); i < length; ++i) {
+ auto &paramType = paramTypes[i];
+ const auto paramTypeName = paramTypeNames[i];
+ if (!paramType && !paramTypeName.isEmpty())
+ paramType = findType(paramTypeName);
+ }
it->setParameterTypes(paramTypes);
}
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index f1ead0ece2..de6ea58906 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -160,11 +160,11 @@ public:
void addOwnMethod(const QQmlJSMetaMethod &method) { m_methods.insert(method.methodName(), method); }
QMultiHash<QString, QQmlJSMetaMethod> ownMethods() const { return m_methods; }
- QQmlJSMetaMethod ownMethod(const QString &name) const { return m_methods.value(name); }
+ QList<QQmlJSMetaMethod> ownMethods(const QString &name) const { return m_methods.values(name); }
bool hasOwnMethod(const QString &name) const { return m_methods.contains(name); }
bool hasMethod(const QString &name) const;
- QQmlJSMetaMethod method(const QString &name) const;
+ QList<QQmlJSMetaMethod> methods(const QString &name) const;
void addEnumeration(const QQmlJSMetaEnum &enumeration)
{