aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp42
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h1
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp42
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h23
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader.cpp4
-rw-r--r--src/qmlcompiler/qqmljstypereader.cpp2
-rw-r--r--tools/qmllint/checkidentifiers.cpp38
-rw-r--r--tools/qmllint/findwarnings.cpp53
8 files changed, 112 insertions, 93 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 6595b1d8d7..04bb27dc84 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -68,14 +68,14 @@ void QQmlJSImportVisitor::resolveAliases()
while (!objects.isEmpty()) {
const QQmlJSScope::Ptr object = objects.dequeue();
- const auto properties = object->properties();
+ const auto properties = object->ownProperties();
for (auto property : properties) {
if (!property.isAlias())
continue;
const auto it = m_scopesById.find(property.typeName());
if (it != m_scopesById.end()) {
property.setType(QQmlJSScope::ConstPtr(*it));
- object->addProperty(property);
+ object->addOwnProperty(property);
}
}
@@ -90,31 +90,6 @@ QQmlJSScope::Ptr QQmlJSImportVisitor::result() const
return m_qmlRootScope;
}
-void QQmlJSImportVisitor::importExportedNames(QQmlJSScope::ConstPtr scope)
-{
- QList<QQmlJSScope::ConstPtr> scopes;
- while (!scope.isNull()) {
- if (scopes.contains(scope))
- break;
-
- scopes.append(scope);
-
- const auto properties = scope->properties();
- for (auto property : properties)
- m_currentScope->insertPropertyIdentifier(property);
-
- m_currentScope->addMethods(scope->methods());
-
- if (scope->baseTypeName().isEmpty())
- break;
-
- if (auto newScope = scope->baseType())
- scope = newScope;
- else
- break;
- }
-}
-
bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiProgram *)
{
m_rootScopeImports = m_importer->importBuiltins();
@@ -146,8 +121,6 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
m_qmlRootScope = m_currentScope;
m_currentScope->resolveTypes(m_rootScopeImports);
- importExportedNames(m_currentScope);
-
return true;
}
@@ -168,7 +141,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
method.addParameter(param->name.toString(), param->type->name.toString());
param = param->next;
}
- m_currentScope->addMethod(method);
+ m_currentScope->addOwnMethod(method);
break;
}
case UiPublicMember::Property: {
@@ -208,7 +181,7 @@ void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExp
method.addParameter(parameters->element->bindingIdentifier.toString(), QString());
parameters = parameters->next;
}
- m_currentScope->addMethod(method);
+ m_currentScope->addOwnMethod(method);
} else {
m_currentScope->insertJSIdentifier(
name, {
@@ -249,7 +222,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::ClassExpression *ast)
{
QQmlJSMetaProperty prop;
prop.setPropertyName(ast->name.toString());
- m_currentScope->addProperty(prop);
+ m_currentScope->addOwnProperty(prop);
enterEnvironment(QQmlJSScope::JSFunctionScope, ast->name.toString(),
ast->firstSourceLocation());
return true;
@@ -466,11 +439,10 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
prop.setIsPointer(true);
prop.setIsAlias(name == QLatin1String("alias"));
prop.setType(m_rootScopeImports.value(uiob->qualifiedTypeNameId->name.toString()));
- m_currentScope->addProperty(prop);
+ m_currentScope->addOwnProperty(prop);
enterEnvironment(QQmlJSScope::QMLScope, name, uiob->firstSourceLocation());
m_currentScope->resolveTypes(m_rootScopeImports);
- importExportedNames(m_currentScope);
return true;
}
@@ -481,7 +453,7 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
QQmlJSMetaProperty property = m_currentScope->property(uiob->qualifiedId->name.toString());
property.setType(childScope);
- m_currentScope->addProperty(property);
+ m_currentScope->addOwnProperty(property);
}
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index eef5889263..1f26536923 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -113,7 +113,6 @@ protected:
private:
void resolveAliases();
void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
- void importExportedNames(QQmlJSScope::ConstPtr scope);
};
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index ba74280ae2..bea6c29932 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -66,9 +66,9 @@ void QQmlJSScope::insertJSIdentifier(const QString &name, const JavaScriptIdenti
void QQmlJSScope::insertPropertyIdentifier(const QQmlJSMetaProperty &property)
{
- addProperty(property);
+ addOwnProperty(property);
QQmlJSMetaMethod method(property.propertyName() + QLatin1String("Changed"), QLatin1String("void"));
- addMethod(method);
+ addOwnMethod(method);
}
bool QQmlJSScope::isIdInCurrentScope(const QString &id) const
@@ -76,6 +76,25 @@ bool QQmlJSScope::isIdInCurrentScope(const QString &id) const
return isIdInCurrentQMlScopes(id) || isIdInCurrentJSScopes(id);
}
+bool QQmlJSScope::hasMethod(const QString &name) const
+{
+ for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
+ if (scope->m_methods.contains(name))
+ return true;
+ }
+ return false;
+}
+
+QQmlJSMetaMethod QQmlJSScope::method(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 {};
+}
+
bool QQmlJSScope::isIdInCurrentQMlScopes(const QString &id) const
{
if (m_scopeType == QQmlJSScope::QMLScope)
@@ -163,6 +182,25 @@ void QQmlJSScope::addExport(const QString &name, const QString &package,
m_exports.append(Export(package, name, version));
}
+bool QQmlJSScope::hasProperty(const QString &name) const
+{
+ for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
+ if (scope->m_properties.contains(name))
+ return true;
+ }
+ return false;
+}
+
+QQmlJSMetaProperty QQmlJSScope::property(const QString &name) const
+{
+ for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
+ const auto it = scope->m_properties.find(name);
+ if (it != scope->m_properties.end())
+ return *it;
+ }
+ return {};
+}
+
QQmlJSScope::Export::Export(QString package, QString type, const QTypeRevision &version) :
m_package(std::move(package)),
m_type(std::move(type)),
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index d656b2f5b4..175b2ecda1 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -156,11 +156,13 @@ public:
ScopeType scopeType() const { return m_scopeType; }
- void addMethods(const QMultiHash<QString, QQmlJSMetaMethod> &methods) { m_methods.unite(methods); }
- void addMethod(const QQmlJSMetaMethod &method) { m_methods.insert(method.methodName(), method); }
- QMultiHash<QString, QQmlJSMetaMethod> methods() const { return m_methods; }
- QQmlJSMetaMethod method(const QString &name) const { return m_methods.value(name); }
- bool hasMethod(const QString &name) const { return m_methods.contains(name); }
+ 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); }
+ bool hasOwnMethod(const QString &name) const { return m_methods.contains(name); }
+
+ bool hasMethod(const QString &name) const;
+ QQmlJSMetaMethod method(const QString &name) const;
void addEnum(const QQmlJSMetaEnum &fakeEnum) { m_enums.insert(fakeEnum.name(), fakeEnum); }
QHash<QString, QQmlJSMetaEnum> enums() const { return m_enums; }
@@ -182,10 +184,13 @@ public:
QString baseTypeName() const { return m_baseTypeName; }
QQmlJSScope::ConstPtr baseType() const { return m_baseType; }
- void addProperty(const QQmlJSMetaProperty &prop) { m_properties.insert(prop.propertyName(), prop); }
- QHash<QString, QQmlJSMetaProperty> properties() const { return m_properties; }
- QQmlJSMetaProperty property(const QString &name) const { return m_properties.value(name); }
- bool hasProperty(const QString &name) const { return m_properties.contains(name); }
+ void addOwnProperty(const QQmlJSMetaProperty &prop) { m_properties.insert(prop.propertyName(), prop); }
+ QHash<QString, QQmlJSMetaProperty> ownProperties() const { return m_properties; }
+ QQmlJSMetaProperty ownProperty(const QString &name) const { return m_properties.value(name); }
+ bool hasOwnProperty(const QString &name) const { return m_properties.contains(name); }
+
+ bool hasProperty(const QString &name) const;
+ QQmlJSMetaProperty property(const QString &name) const;
QString defaultPropertyName() const { return m_defaultPropertyName; }
void setDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; }
diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
index 4b7dcead31..17e3d2e707 100644
--- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp
+++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
@@ -308,7 +308,7 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bo
return;
}
- scope->addMethod(metaMethod);
+ scope->addOwnMethod(metaMethod);
}
void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQmlJSScope::Ptr &scope)
@@ -351,7 +351,7 @@ void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQ
return;
}
- scope->addProperty(property);
+ scope->addOwnProperty(property);
}
void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast, const QQmlJSScope::Ptr &scope)
diff --git a/src/qmlcompiler/qqmljstypereader.cpp b/src/qmlcompiler/qqmljstypereader.cpp
index 578b0378c3..2c45bb01d6 100644
--- a/src/qmlcompiler/qqmljstypereader.cpp
+++ b/src/qmlcompiler/qqmljstypereader.cpp
@@ -51,7 +51,7 @@ static QQmlJSScope::Ptr parseProgram(QQmlJS::AST::Program *program, const QStrin
method.setMethodType(QQmlJSMetaMethod::Method);
for (auto *parameters = function->formals; parameters; parameters = parameters->next)
method.addParameter(parameters->element->bindingIdentifier.toString(), QString());
- result->addMethod(method);
+ result->addOwnMethod(method);
}
}
return result;
diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp
index 09c39ddd63..86ac84fcf1 100644
--- a/tools/qmllint/checkidentifiers.cpp
+++ b/tools/qmllint/checkidentifiers.cpp
@@ -149,12 +149,11 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
return false;
}
- const auto properties = scope->properties();
- const auto scopeIt = properties.find(access.m_name);
- if (scopeIt != properties.end()) {
- const QString typeName = access.m_parentType.isEmpty() ? scopeIt->typeName()
+ const auto property = scope->property(access.m_name);
+ if (!property.propertyName().isEmpty()) {
+ const QString typeName = access.m_parentType.isEmpty() ? property.typeName()
: access.m_parentType;
- if (scopeIt->isList()) {
+ if (property.isList()) {
detectedRestrictiveKind = QLatin1String("list");
detectedRestrictiveName = access.m_name;
expectedNext.append(QLatin1String("length"));
@@ -169,7 +168,7 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
}
if (access.m_parentType.isEmpty()) {
- scope = scopeIt->type();
+ scope = property.type();
if (scope.isNull()) {
// Properties should always have a type. Otherwise something
// was missing from the import already.
@@ -194,9 +193,7 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
continue;
}
- const auto methods = scope->methods();
- const auto scopeMethodIt = methods.find(access.m_name);
- if (scopeMethodIt != methods.end())
+ if (scope->hasMethod(access.m_name))
return true; // Access to property of JS function
auto checkEnums = [&](const QQmlJSScope::ConstPtr &scope) {
@@ -232,14 +229,14 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
bool typeFound =
walkViaParentAndAttachedScopes(rootType, [&](QQmlJSScope::ConstPtr type) {
- const auto typeProperties = type->properties();
+ const auto typeProperties = type->ownProperties();
const auto typeIt = typeProperties.find(access.m_name);
if (typeIt != typeProperties.end()) {
scope = typeIt->type();
return true;
}
- const auto typeMethods = type->methods();
+ const auto typeMethods = type->ownMethods();
const auto typeMethodIt = typeMethods.find(access.m_name);
if (typeMethodIt != typeMethods.end()) {
detectedRestrictiveName = access.m_name;
@@ -326,18 +323,17 @@ bool CheckIdentifiers::operator()(
}
auto qmlScope = QQmlJSScope::findCurrentQMLScope(currentScope);
- if (qmlScope->methods().contains(memberAccessBase.m_name)) {
- // a property of a JavaScript function
+ if (qmlScope->hasMethod(memberAccessBase.m_name)) {
+ // a property of a JavaScript function, or a method
continue;
}
- const auto properties = qmlScope->properties();
- const auto qmlIt = properties.find(memberAccessBase.m_name);
- if (qmlIt != properties.end()) {
- if (memberAccessChain.isEmpty() || unknownBuiltins.contains(qmlIt->typeName()))
+ const auto property = qmlScope->property(memberAccessBase.m_name);
+ if (!property.propertyName().isEmpty()) {
+ if (memberAccessChain.isEmpty() || unknownBuiltins.contains(property.typeName()))
continue;
- if (!qmlIt->type()) {
+ if (!property.type()) {
m_colorOut->writePrefixedMessage(QString::fromLatin1(
"Type of property \"%2\" not found at %3:%4:%5\n")
.arg(memberAccessBase.m_name)
@@ -346,7 +342,7 @@ bool CheckIdentifiers::operator()(
.arg(memberAccessBase.m_location.startColumn), Warning);
printContext(m_code, m_colorOut, memberAccessBase.m_location);
noUnqualifiedIdentifier = false;
- } else if (!checkMemberAccess(memberAccessChain, qmlIt->type(), &*qmlIt)) {
+ } else if (!checkMemberAccess(memberAccessChain, property.type(), &property)) {
noUnqualifiedIdentifier = false;
}
@@ -375,8 +371,8 @@ bool CheckIdentifiers::operator()(
// root(JS) --> (first element)
const auto firstElement = root->childScopes()[0];
- if (firstElement->properties().contains(memberAccessBase.m_name)
- || firstElement->methods().contains(memberAccessBase.m_name)
+ if (firstElement->hasProperty(memberAccessBase.m_name)
+ || firstElement->hasMethod(memberAccessBase.m_name)
|| firstElement->enums().contains(memberAccessBase.m_name)) {
m_colorOut->writePrefixedMessage(
memberAccessBase.m_name
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index 9e8fbb853b..06e647dcd5 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -192,7 +192,7 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
if (signal.isEmpty())
return true;
- if (!m_currentScope->methods().contains(signal) && m_warnUnqualified) {
+ if (!m_currentScope->hasMethod(signal) && m_warnUnqualified) {
m_errors.append({
QStringLiteral("no matching signal found for handler \"%1\"\n")
.arg(name.toString()),
@@ -212,18 +212,20 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
}
}
- const auto methods = m_currentScope->methods();
- const auto methodsRange = methods.equal_range(signal);
- for (auto method = methodsRange.first; method != methodsRange.second; ++method) {
- if (method->methodType() != QQmlJSMetaMethod::Signal)
- continue;
-
- const auto firstSourceLocation = statement->firstSourceLocation();
- bool hasMultilineStatementBody
- = statement->lastSourceLocation().startLine > firstSourceLocation.startLine;
- m_pendingSingalHandler = firstSourceLocation;
- m_signalHandlers.insert(firstSourceLocation, {*method, hasMultilineStatementBody});
- break; // If there are multiple candidates for the signal, it's a mess anyway.
+ for (QQmlJSScope::ConstPtr scope = m_currentScope; scope; scope = scope->baseType()) {
+ const auto methods = scope->ownMethods();
+ const auto methodsRange = methods.equal_range(signal);
+ for (auto method = methodsRange.first; method != methodsRange.second; ++method) {
+ if (method->methodType() != QQmlJSMetaMethod::Signal)
+ continue;
+
+ const auto firstSourceLocation = statement->firstSourceLocation();
+ bool hasMultilineStatementBody
+ = statement->lastSourceLocation().startLine > firstSourceLocation.startLine;
+ m_pendingSingalHandler = firstSourceLocation;
+ m_signalHandlers.insert(firstSourceLocation, {*method, hasMultilineStatementBody});
+ return true; // If there are multiple candidates for the signal, it's a mess anyway.
+ }
}
return true;
@@ -319,8 +321,14 @@ bool FindWarningVisitor::check()
// now that all ids are known, revisit any Connections whose target were perviously unknown
for (auto const &outstandingConnection: m_outstandingConnections) {
auto targetScope = m_scopesById[outstandingConnection.targetName];
- if (outstandingConnection.scope && !targetScope.isNull())
- outstandingConnection.scope->addMethods(targetScope->methods());
+ if (outstandingConnection.scope) {
+ for (const auto scope = targetScope; targetScope;
+ targetScope = targetScope->baseType()) {
+ const auto connectionMethods = targetScope->ownMethods();
+ for (const auto &method : connectionMethods)
+ outstandingConnection.scope->addOwnMethod(method);
+ }
+ }
QScopedValueRollback<QQmlJSScope::Ptr> rollback(m_currentScope, outstandingConnection.scope);
outstandingConnection.uiod->initializer->accept(this);
}
@@ -392,8 +400,11 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
return false; // visit children later once target is known
}
}
- if (targetScope)
- m_currentScope->addMethods(targetScope->methods());
+ for (const auto scope = targetScope; targetScope; targetScope = targetScope->baseType()) {
+ const auto connectionMethods = targetScope->ownMethods();
+ for (const auto &method : connectionMethods)
+ m_currentScope->addOwnMethod(method);
+ }
}
return true;
}
@@ -427,12 +438,10 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *uiod)
return;
}
- const auto properties = childScope->properties();
- const auto it = properties.find(QStringLiteral("parent"));
- if (it != properties.end()) {
- auto property = *it;
+ auto property = childScope->property(QStringLiteral("parent"));
+ if (!property.propertyName().isEmpty()) {
property.setType(QQmlJSScope::ConstPtr(m_currentScope));
- childScope->addProperty(property);
+ childScope->addOwnProperty(property);
}
}