diff options
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 42 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor_p.h | 1 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 42 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 23 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypedescriptionreader.cpp | 4 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljstypereader.cpp | 2 | ||||
-rw-r--r-- | tools/qmllint/checkidentifiers.cpp | 38 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.cpp | 53 |
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); } } |