From 3e57c56aa1d54ac4587284727ca9c952d33f3e43 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Mar 2020 11:20:47 +0100 Subject: qmllint: Add QFont to the list of unknown builtins And also check them when analyzing JavaScript access. Task-number: QTBUG-82817 Change-Id: I677e7883fb24ab80ff20d1998e2d7df440ef4112 Reviewed-by: Simon Hausmann Reviewed-by: Fabian Kosmale --- tools/qmllint/scopetree.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'tools/qmllint') diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp index e7e0113f35..5c0fa526a4 100644 --- a/tools/qmllint/scopetree.cpp +++ b/tools/qmllint/scopetree.cpp @@ -134,6 +134,15 @@ private: QStringRef m_afterText; }; +static const QStringList unknownBuiltins = { + // TODO: "string" should be added to builtins.qmltypes, and the special handling below removed + QStringLiteral("alias"), // TODO: we cannot properly resolve aliases, yet + QStringLiteral("QRectF"), // TODO: should be added to builtins.qmltypes + QStringLiteral("QFont"), // TODO: should be added to builtins.qmltypes + QStringLiteral("QJSValue"), // We cannot say anything intelligent about untyped JS values. + QStringLiteral("variant"), // Same for generic variants +}; + bool ScopeTree::checkMemberAccess( const QString &code, FieldMemberList *members, @@ -169,10 +178,14 @@ bool ScopeTree::checkMemberAccess( } return true; } - const ScopeTree *type = (scopeIt->type() && access->m_parentType.isEmpty()) - ? scopeIt->type() - : types.value(typeName).get(); - return checkMemberAccess(code, access.get(), type, types, colorOut); + + if (const ScopeTree *type = scopeIt->type()) { + if (access->m_parentType.isEmpty()) + return checkMemberAccess(code, access.get(), type, types, colorOut); + } + + return unknownBuiltins.contains(typeName) || checkMemberAccess( + code, access.get(), types.value(typeName).get(), types, colorOut); } const auto scopeMethodIt = scope->m_methods.find(access->m_name); @@ -251,13 +264,6 @@ bool ScopeTree::checkMemberAccess( return false; } -static const QStringList unknownBuiltins = { - QStringLiteral("alias"), // TODO: we cannot properly resolve aliases, yet - QStringLiteral("QRectF"), // TODO: should be added to builtins.qmltypes - QStringLiteral("QJSValue"), // We cannot say anything intelligent about untyped JS values. - QStringLiteral("variant"), // Same for generic variants -}; - bool ScopeTree::recheckIdentifiers( const QString &code, const QHash &qmlIDs, -- cgit v1.2.3 From afe20375bab3dea584c3b6c9bc5812da78f6618e Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Mar 2020 12:15:10 +0100 Subject: qmllint: Use fully qualified QML type names as superClass Otherwise we miss subtleties such as Label vs. T.Label. Task-number: QTBUG-82817 Change-Id: Idc2131426b2fd96f279dab83292a348b9295d5c0 Reviewed-by: Fabian Kosmale --- tools/qmllint/findunqualified.cpp | 9 ++++----- tools/qmllint/importedmembersvisitor.cpp | 11 +++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'tools/qmllint') diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp index ae23d6d5f8..5bb9b62529 100644 --- a/tools/qmllint/findunqualified.cpp +++ b/tools/qmllint/findunqualified.cpp @@ -43,6 +43,7 @@ static const QString prefixedName(const QString &prefix, const QString &name) { + Q_ASSERT(!prefix.endsWith('.')); return prefix.isEmpty() ? name : (prefix + QLatin1Char('.') + name); } @@ -88,11 +89,9 @@ void FindUnqualifiedIDVisitor::parseHeaders(QQmlJS::AST::UiHeaderItemList *heade uri = uri->next; } path.chop(1); - QString prefix = QLatin1String(""); - if (import->asToken.isValid()) { - prefix += import->importId + QLatin1Char('.'); - } - importHelper(path, prefix, import->version->majorVersion, + importHelper(path, + import->asToken.isValid() ? import->importId.toString() : QString(), + import->version->majorVersion, import->version->minorVersion); } } diff --git a/tools/qmllint/importedmembersvisitor.cpp b/tools/qmllint/importedmembersvisitor.cpp index 676903d135..c5214f2bb9 100644 --- a/tools/qmllint/importedmembersvisitor.cpp +++ b/tools/qmllint/importedmembersvisitor.cpp @@ -57,10 +57,13 @@ ScopeTree *ImportedMembersVisitor::result(const QString &scopeName) const bool ImportedMembersVisitor::visit(UiObjectDefinition *definition) { ScopeTree::Ptr scope(new ScopeTree(ScopeType::QMLScope)); - auto qualifiedId = definition->qualifiedTypeNameId; - while (qualifiedId && qualifiedId->next) - qualifiedId = qualifiedId->next; - scope->setSuperclassName(qualifiedId->name.toString()); + QString superType; + for (auto segment = definition->qualifiedTypeNameId; segment; segment = segment->next) { + if (!superType.isEmpty()) + superType.append('.'); + superType.append(segment->name.toString()); + } + scope->setSuperclassName(superType); if (!m_rootObject) m_rootObject = scope; m_currentObjects.append(scope); -- cgit v1.2.3 From 1b5a6c19ab701c9b94b1ffb094999c34643bcd1d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Mar 2020 15:07:04 +0100 Subject: qmllint: Don't crash on IDs that aren't scopes In particular, those can be qualifiers for imports, in which case we have to combine them with the next segment in order to find the type. Task-number: QTBUG-82817 Change-Id: I217a79572cd1e160dcbbcb9541c53941c81ab76c Reviewed-by: Fabian Kosmale --- tools/qmllint/scopetree.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'tools/qmllint') diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp index 5c0fa526a4..07413094c0 100644 --- a/tools/qmllint/scopetree.cpp +++ b/tools/qmllint/scopetree.cpp @@ -293,9 +293,24 @@ bool ScopeTree::recheckIdentifiers( auto it = qmlIDs.find(memberAccessTree->m_name); if (it != qmlIDs.end()) { - if (!checkMemberAccess(code, memberAccessTree.get(), *it, types, colorOut)) - noUnqualifiedIdentifier = false; - continue; + if (*it != nullptr) { + if (!checkMemberAccess(code, memberAccessTree.get(), *it, types, colorOut)) + noUnqualifiedIdentifier = false; + continue; + } else if (memberAccessTree->m_child + && memberAccessTree->m_child->m_name.front().isUpper()) { + // It could be a qualified type name + const QString qualified = memberAccessTree->m_name + QLatin1Char('.') + + memberAccessTree->m_child->m_name; + const auto typeIt = types.find(qualified); + if (typeIt != types.end()) { + if (!checkMemberAccess(code, memberAccessTree->m_child.get(), typeIt->get(), + types, colorOut)) { + noUnqualifiedIdentifier = false; + } + continue; + } + } } auto qmlScope = currentScope->currentQMLScope(); -- cgit v1.2.3 From 869efe4a49c5286493d7f039325992725bcac6c3 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Mar 2020 12:16:21 +0100 Subject: qmllint: Check for unknown types in JavaScript access There are many incomplete qmltypes files around. We should not just crash on those. Task-number: QTBUG-82817 Change-Id: Ie072b80473927570c80fb2f9ae329de711c35904 Reviewed-by: Fabian Kosmale --- tools/qmllint/scopetree.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'tools/qmllint') diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp index 07413094c0..8c5358c7a5 100644 --- a/tools/qmllint/scopetree.cpp +++ b/tools/qmllint/scopetree.cpp @@ -179,13 +179,30 @@ bool ScopeTree::checkMemberAccess( return true; } + if (!access->m_child) + return true; + if (const ScopeTree *type = scopeIt->type()) { if (access->m_parentType.isEmpty()) return checkMemberAccess(code, access.get(), type, types, colorOut); } - return unknownBuiltins.contains(typeName) || checkMemberAccess( - code, access.get(), types.value(typeName).get(), types, colorOut); + if (unknownBuiltins.contains(typeName)) + return true; + + const auto it = types.find(typeName); + if (it != types.end()) + return checkMemberAccess(code, access.get(), it->get(), types, colorOut); + + colorOut.write("Warning: ", Warning); + colorOut.write( + QString::fromLatin1("Type \"%1\" of member \"%2\" not found at %3:%4.\n") + .arg(typeName) + .arg(access->m_name) + .arg(access->m_location.startLine) + .arg(access->m_location.startColumn), Normal); + printContext(colorOut, code, access->m_location); + return false; } const auto scopeMethodIt = scope->m_methods.find(access->m_name); -- cgit v1.2.3