diff options
Diffstat (limited to 'tools/qmllint')
-rw-r--r-- | tools/qmllint/findunqualified.cpp | 28 | ||||
-rw-r--r-- | tools/qmllint/findunqualified.h | 3 | ||||
-rw-r--r-- | tools/qmllint/scopetree.cpp | 20 | ||||
-rw-r--r-- | tools/qmllint/scopetree.h | 4 |
4 files changed, 46 insertions, 9 deletions
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp index d0dc3a3711..dc1bb29567 100644 --- a/tools/qmllint/findunqualified.cpp +++ b/tools/qmllint/findunqualified.cpp @@ -900,11 +900,37 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::FieldMemberExpression *) void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::FieldMemberExpression *fieldMember) { - if (m_fieldMemberBase == fieldMember->base) { + using namespace QQmlJS::AST; + ExpressionNode *base = fieldMember->base; + while (auto *nested = cast<NestedExpression *>(base)) + base = nested->expression; + + if (m_fieldMemberBase == base) { + QString type; + if (auto *binary = cast<BinaryExpression *>(base)) { + if (binary->op == QSOperator::As) { + if (auto *right = cast<IdentifierExpression *>(binary->right)) + type = right->name.toString(); + } + } m_currentScope->accessMember(fieldMember->name.toString(), + type, fieldMember->identifierToken); m_fieldMemberBase = fieldMember; } else { m_fieldMemberBase = nullptr; } } + +bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::BinaryExpression *) +{ + return true; +} + +void FindUnqualifiedIDVisitor::endVisit(QQmlJS::AST::BinaryExpression *binExp) +{ + if (binExp->op == QSOperator::As && m_fieldMemberBase == binExp->left) + m_fieldMemberBase = binExp; + else + m_fieldMemberBase = nullptr; +} diff --git a/tools/qmllint/findunqualified.h b/tools/qmllint/findunqualified.h index f5955a3a74..6668b53b08 100644 --- a/tools/qmllint/findunqualified.h +++ b/tools/qmllint/findunqualified.h @@ -161,6 +161,9 @@ private: bool visit(QQmlJS::AST::PatternElement *) override; bool visit(QQmlJS::AST::FieldMemberExpression *idprop) override; void endVisit(QQmlJS::AST::FieldMemberExpression *) override; + + bool visit(QQmlJS::AST::BinaryExpression *) override; + void endVisit(QQmlJS::AST::BinaryExpression *) override; }; #endif // FINDUNQUALIFIED_H diff --git a/tools/qmllint/scopetree.cpp b/tools/qmllint/scopetree.cpp index e5b0eecc5f..6c122f0368 100644 --- a/tools/qmllint/scopetree.cpp +++ b/tools/qmllint/scopetree.cpp @@ -88,14 +88,15 @@ bool ScopeTree::isIdInCurrentScope(const QString &id) const } void ScopeTree::addIdToAccessed(const QString &id, const QQmlJS::AST::SourceLocation &location) { - m_currentFieldMember = new FieldMemberList {id, location, {}}; + m_currentFieldMember = new FieldMemberList {id, QString(), location, {}}; m_accessedIdentifiers.push_back(std::unique_ptr<FieldMemberList>(m_currentFieldMember)); } -void ScopeTree::accessMember(const QString &name, const QQmlJS::AST::SourceLocation &location) +void ScopeTree::accessMember(const QString &name, const QString &parentType, + const QQmlJS::AST::SourceLocation &location) { Q_ASSERT(m_currentFieldMember); - auto *fieldMember = new FieldMemberList {name, location, {}}; + auto *fieldMember = new FieldMemberList {name, parentType, location, {}}; m_currentFieldMember->m_child.reset(fieldMember); m_currentFieldMember = fieldMember; } @@ -150,7 +151,9 @@ bool ScopeTree::checkMemberAccess( const auto scopeIt = scope->m_properties.find(access->m_name); if (scopeIt != scope->m_properties.end()) { - if (scopeIt->isList() || scopeIt->typeName() == QLatin1String("string")) { + const QString typeName = access->m_parentType.isEmpty() ? scopeIt->typeName() + : access->m_parentType; + if (scopeIt->isList() || typeName == QLatin1String("string")) { if (access->m_child && access->m_child->m_name != QLatin1String("length")) { colorOut.write("Warning: ", Warning); colorOut.write( @@ -166,8 +169,9 @@ bool ScopeTree::checkMemberAccess( } return true; } - const ScopeTree *type = scopeIt->type() ? scopeIt->type() - : types.value(scopeIt->typeName()).get(); + const ScopeTree *type = (scopeIt->type() && access->m_parentType.isEmpty()) + ? scopeIt->type() + : types.value(typeName).get(); return checkMemberAccess(code, access.get(), type, types, colorOut); } @@ -199,7 +203,9 @@ bool ScopeTree::checkMemberAccess( while (type) { const auto typeIt = type->m_properties.find(access->m_name); if (typeIt != type->m_properties.end()) { - const auto propType = typeIt->type(); + const ScopeTree *propType = access->m_parentType.isEmpty() + ? typeIt->type() + : types.value(access->m_parentType).get(); return checkMemberAccess(code, access.get(), propType ? propType : types.value(typeIt->typeName()).get(), types, colorOut); diff --git a/tools/qmllint/scopetree.h b/tools/qmllint/scopetree.h index eb5f384477..f5d1155a49 100644 --- a/tools/qmllint/scopetree.h +++ b/tools/qmllint/scopetree.h @@ -120,7 +120,8 @@ public: bool isIdInCurrentScope(const QString &id) const; void addIdToAccessed(const QString &id, const QQmlJS::AST::SourceLocation &location); - void accessMember(const QString &name, const QQmlJS::AST::SourceLocation &location); + void accessMember(const QString &name, const QString &parentType, + const QQmlJS::AST::SourceLocation &location); void resetMemberScope(); bool isVisualRootScope() const; @@ -172,6 +173,7 @@ private: struct FieldMemberList { QString m_name; + QString m_parentType; QQmlJS::AST::SourceLocation m_location; std::unique_ptr<FieldMemberList> m_child; }; |