diff options
-rw-r--r-- | tests/auto/qml/qmllint/data/brokenNamespace.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/tst_qmllint.cpp | 4 | ||||
-rw-r--r-- | tools/qmllint/checkidentifiers.cpp | 47 |
3 files changed, 43 insertions, 13 deletions
diff --git a/tests/auto/qml/qmllint/data/brokenNamespace.qml b/tests/auto/qml/qmllint/data/brokenNamespace.qml new file mode 100644 index 0000000000..45f20b941c --- /dev/null +++ b/tests/auto/qml/qmllint/data/brokenNamespace.qml @@ -0,0 +1,5 @@ +import QtQuick as T + +T.Item { + objectName: T.some.bs +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index c1ccae7235..994bb2cea0 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -273,6 +273,10 @@ void TestQmllint::dirtyQmlCode_data() << QStringLiteral("badScript.qml") << QString("Warning: Property \"stuff\" not found on type \"Empty\"") << QString(); + QTest::newRow("brokenNamespace") + << QStringLiteral("brokenNamespace.qml") + << QString("Warning: type not found in namespace at %1:4:17") + << QString(); } void TestQmllint::dirtyQmlCode() diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp index 0517f67ed5..32a47891d5 100644 --- a/tools/qmllint/checkidentifiers.cpp +++ b/tools/qmllint/checkidentifiers.cpp @@ -299,7 +299,7 @@ bool CheckIdentifiers::operator()( if (memberAccessChain.isEmpty()) continue; - const auto memberAccessBase = memberAccessChain.takeFirst(); + auto memberAccessBase = memberAccessChain.takeFirst(); const auto jsId = currentScope->findJSIdentifier(memberAccessBase.m_name); if (jsId.has_value() && jsId->kind != QQmlJSScope::JavaScriptIdentifier::Injected) continue; @@ -354,24 +354,45 @@ bool CheckIdentifiers::operator()( continue; } - const auto typeIt = m_types.find(memberAccessBase.m_name); - if (typeIt != m_types.end()) { - if (typeIt->isNull()) { - // This is a namespaced import. Check with the full name. - if (!memberAccessChain.isEmpty()) - memberAccessChain.front().m_name.prepend(memberAccessBase.m_name + u'.'); - } else if (!checkMemberAccess(memberAccessChain, *typeIt)) { - noUnqualifiedIdentifier = false; + const QString baseName = memberAccessBase.m_name; + auto typeIt = m_types.find(memberAccessBase.m_name); + bool baseIsPrefixed = false; + while (typeIt != m_types.end() && typeIt->isNull()) { + // This is a namespaced import. Check with the full name. + if (!memberAccessChain.isEmpty()) { + auto location = memberAccessBase.m_location; + memberAccessBase = memberAccessChain.takeFirst(); + memberAccessBase.m_name.prepend(baseName + u'.'); + location.length = memberAccessBase.m_location.offset - location.offset + + memberAccessBase.m_location.length; + memberAccessBase.m_location = location; + typeIt = m_types.find(memberAccessBase.m_name); + baseIsPrefixed = true; } + } + + if (typeIt != m_types.end() && !typeIt->isNull()) { + if (!checkMemberAccess(memberAccessChain, *typeIt)) + noUnqualifiedIdentifier = false; continue; } noUnqualifiedIdentifier = false; const auto location = memberAccessBase.m_location; - m_colorOut->writePrefixedMessage(QString::fromLatin1("unqualified access at %1:%2:%3\n") - .arg(m_fileName) - .arg(location.startLine).arg(location.startColumn), - Warning); + + if (baseIsPrefixed) { + m_colorOut->writePrefixedMessage( + QString::fromLatin1("type not found in namespace at %1:%2:%3\n") + .arg(m_fileName) + .arg(location.startLine).arg(location.startColumn), + Warning); + } else { + m_colorOut->writePrefixedMessage( + QString::fromLatin1("unqualified access at %1:%2:%3\n") + .arg(m_fileName) + .arg(location.startLine).arg(location.startColumn), + Warning); + } printContext(m_code, m_colorOut, location); |