qmllint: Complain if member access check fails for namespaced types

Before, we would prepend the namespace to the name, but then continue
right away, never checking the new name.

Change-Id: If90db7d33536fb4b549321c2d6b677040605b6f0
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2021-01-26 11:14:13 +01:00
parent 48b6e192bb
commit ed59dfeb70
3 changed files with 43 additions and 13 deletions

View File

@ -0,0 +1,5 @@
import QtQuick as T
T.Item {
objectName: T.some.bs
}

View File

@ -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()

View File

@ -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);