qmllint: Remove exceptions for most unknown builtins
All those types are properly defined in the qmltypes files now. We just need to search the enumerations the same way as methods and properties in order to find everything. Also, deduplicate the code that resolves properties, methods, and enums by using a common template for iterating the scopes. Change-Id: I0bf1423974d0ec8f602ecd0342522b3e981a8586 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
90be89d771
commit
39944e8467
|
@ -298,7 +298,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
|
||||||
qmlEnum.addKey(member->member.toString());
|
qmlEnum.addKey(member->member.toString());
|
||||||
qmlEnum.addValue(int(member->value));
|
qmlEnum.addValue(int(member->value));
|
||||||
}
|
}
|
||||||
m_currentScope->addEnumeration(qmlEnum);
|
m_currentScope->addOwnEnumeration(qmlEnum);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,30 @@
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
template<typename Action>
|
||||||
|
static bool searchBaseAndExtensionTypes(const QQmlJSScope *type, const Action &check)
|
||||||
|
{
|
||||||
|
const QQmlJSScope *nonCompositeBase = nullptr;
|
||||||
|
for (const QQmlJSScope *scope = type; scope; scope = scope->baseType().data()) {
|
||||||
|
if (check(scope))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!nonCompositeBase && !scope->isComposite())
|
||||||
|
nonCompositeBase = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nonCompositeBase)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const QQmlJSScope *scope = nonCompositeBase->extensionType().data(); scope;
|
||||||
|
scope = scope->baseType().data()) {
|
||||||
|
if (check(scope))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QQmlJSScope::QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope)
|
QQmlJSScope::QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope)
|
||||||
: m_parentScope(parentScope), m_scopeType(type) {}
|
: m_parentScope(parentScope), m_scopeType(type) {}
|
||||||
|
|
||||||
|
@ -78,41 +102,55 @@ bool QQmlJSScope::isIdInCurrentScope(const QString &id) const
|
||||||
|
|
||||||
bool QQmlJSScope::hasMethod(const QString &name) const
|
bool QQmlJSScope::hasMethod(const QString &name) const
|
||||||
{
|
{
|
||||||
const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr;
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
||||||
for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
|
return scope->m_methods.contains(name);
|
||||||
if (scope->m_methods.contains(name))
|
});
|
||||||
return true;
|
|
||||||
if (!nonCompositeBase && !scope->isComposite())
|
|
||||||
nonCompositeBase = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nonCompositeBase && nonCompositeBase != this) {
|
|
||||||
if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType())
|
|
||||||
return extension->hasMethod(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name) const
|
QList<QQmlJSMetaMethod> QQmlJSScope::methods(const QString &name) const
|
||||||
{
|
{
|
||||||
QList<QQmlJSMetaMethod> results;
|
QList<QQmlJSMetaMethod> results;
|
||||||
|
|
||||||
const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr;
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
||||||
for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
|
|
||||||
results.append(scope->ownMethods(name));
|
results.append(scope->ownMethods(name));
|
||||||
if (!nonCompositeBase && !scope->isComposite())
|
return false;
|
||||||
nonCompositeBase = scope;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (nonCompositeBase && nonCompositeBase != this) {
|
|
||||||
if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType())
|
|
||||||
results.append(extension->methods(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QQmlJSScope::hasEnumeration(const QString &name) const
|
||||||
|
{
|
||||||
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
||||||
|
return scope->m_enumerations.contains(name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QQmlJSScope::hasEnumerationKey(const QString &name) const
|
||||||
|
{
|
||||||
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
||||||
|
for (const auto &e : scope->m_enumerations) {
|
||||||
|
if (e.keys().contains(name))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QQmlJSMetaEnum QQmlJSScope::enumeration(const QString &name) const
|
||||||
|
{
|
||||||
|
QQmlJSMetaEnum result;
|
||||||
|
|
||||||
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
||||||
|
const auto it = scope->m_enumerations.find(name);
|
||||||
|
if (it == scope->m_enumerations.end())
|
||||||
|
return false;
|
||||||
|
result = *it;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool QQmlJSScope::isIdInCurrentQmlScopes(const QString &id) const
|
bool QQmlJSScope::isIdInCurrentQmlScopes(const QString &id) const
|
||||||
{
|
{
|
||||||
if (m_scopeType == QQmlJSScope::QMLScope)
|
if (m_scopeType == QQmlJSScope::QMLScope)
|
||||||
|
@ -262,41 +300,22 @@ void QQmlJSScope::addExport(const QString &name, const QString &package,
|
||||||
|
|
||||||
bool QQmlJSScope::hasProperty(const QString &name) const
|
bool QQmlJSScope::hasProperty(const QString &name) const
|
||||||
{
|
{
|
||||||
const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr;
|
return searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
||||||
for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
|
return scope->m_properties.contains(name);
|
||||||
if (scope->m_properties.contains(name))
|
});
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!nonCompositeBase && !scope->isComposite())
|
|
||||||
nonCompositeBase = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nonCompositeBase && nonCompositeBase != this) {
|
|
||||||
if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType())
|
|
||||||
return extension->hasProperty(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlJSMetaProperty QQmlJSScope::property(const QString &name) const
|
QQmlJSMetaProperty QQmlJSScope::property(const QString &name) const
|
||||||
{
|
{
|
||||||
const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr;
|
QQmlJSMetaProperty prop;
|
||||||
for (const QQmlJSScope *scope = this; scope; scope = scope->baseType().data()) {
|
searchBaseAndExtensionTypes(this, [&](const QQmlJSScope *scope) {
|
||||||
const auto it = scope->m_properties.find(name);
|
const auto it = scope->m_properties.find(name);
|
||||||
if (it != scope->m_properties.end())
|
if (it == scope->m_properties.end())
|
||||||
return *it;
|
return false;
|
||||||
|
prop = *it;
|
||||||
if (!nonCompositeBase && !scope->isComposite())
|
return true;
|
||||||
nonCompositeBase = scope;
|
});
|
||||||
}
|
return prop;
|
||||||
|
|
||||||
if (nonCompositeBase && nonCompositeBase != this) {
|
|
||||||
if (QQmlJSScope::ConstPtr extension = nonCompositeBase->extensionType())
|
|
||||||
return extension->property(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlJSScope::Export::Export(QString package, QString type, const QTypeRevision &version) :
|
QQmlJSScope::Export::Export(QString package, QString type, const QTypeRevision &version) :
|
||||||
|
|
|
@ -175,13 +175,14 @@ public:
|
||||||
bool hasMethod(const QString &name) const;
|
bool hasMethod(const QString &name) const;
|
||||||
QList<QQmlJSMetaMethod> methods(const QString &name) const;
|
QList<QQmlJSMetaMethod> methods(const QString &name) const;
|
||||||
|
|
||||||
void addEnumeration(const QQmlJSMetaEnum &enumeration)
|
void addOwnEnumeration(const QQmlJSMetaEnum &enumeration) { m_enumerations.insert(enumeration.name(), enumeration); }
|
||||||
{
|
QHash<QString, QQmlJSMetaEnum> ownEnumerations() const { return m_enumerations; }
|
||||||
m_enumerations.insert(enumeration.name(), enumeration);
|
QQmlJSMetaEnum ownEnumeration(const QString &name) const { return m_enumerations.value(name); }
|
||||||
}
|
bool hasOwnEnumeration(const QString &name) const { return m_enumerations.contains(name); }
|
||||||
QHash<QString, QQmlJSMetaEnum> enumerations() const { return m_enumerations; }
|
|
||||||
QQmlJSMetaEnum enumeration(const QString &name) const { return m_enumerations.value(name); }
|
bool hasEnumeration(const QString &name) const;
|
||||||
bool hasEnumeration(const QString &name) const { return m_enumerations.contains(name); }
|
bool hasEnumerationKey(const QString &name) const;
|
||||||
|
QQmlJSMetaEnum enumeration(const QString &name) const;
|
||||||
|
|
||||||
QString fileName() const { return m_fileName; }
|
QString fileName() const { return m_fileName; }
|
||||||
void setFileName(const QString &file) { m_fileName = file; }
|
void setFileName(const QString &file) { m_fileName = file; }
|
||||||
|
|
|
@ -390,7 +390,7 @@ void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast, const QQmlJS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scope->addEnumeration(metaEnum);
|
scope->addOwnEnumeration(metaEnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSMetaMethod *metaMethod)
|
void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSMetaMethod *metaMethod)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import QtQml
|
||||||
import "." as MyStuff
|
import "." as MyStuff
|
||||||
|
|
||||||
MyStuff.Simple {
|
MyStuff.Simple {
|
||||||
property bool something: contains(Qt.point(12, 34))
|
property bool something: contains(Qt.point(12, 34))
|
||||||
|
property int other: Qt.AlignBottom
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,10 +56,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
static const QStringList unknownBuiltins = {
|
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("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("QJSValue"), // We cannot say anything intelligent about untyped JS values.
|
||||||
QStringLiteral("variant"), // Same for generic variants
|
QStringLiteral("variant"), // Same for generic variants
|
||||||
};
|
};
|
||||||
|
@ -208,22 +205,19 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
|
||||||
return true; // Access to property of JS function
|
return true; // Access to property of JS function
|
||||||
|
|
||||||
auto checkEnums = [&](const QQmlJSScope::ConstPtr &scope) {
|
auto checkEnums = [&](const QQmlJSScope::ConstPtr &scope) {
|
||||||
const auto enums = scope->enumerations();
|
if (scope->hasEnumeration(access.m_name)) {
|
||||||
for (const auto &enumerator : enums) {
|
detectedRestrictiveKind = QLatin1String("enum");
|
||||||
if (enumerator.name() == access.m_name) {
|
detectedRestrictiveName = access.m_name;
|
||||||
detectedRestrictiveKind = QLatin1String("enum");
|
expectedNext.append(scope->enumeration(access.m_name).keys());
|
||||||
detectedRestrictiveName = access.m_name;
|
return true;
|
||||||
expectedNext.append(enumerator.keys());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (const QString &key : enumerator.keys()) {
|
|
||||||
if (access.m_name == key) {
|
|
||||||
detectedRestrictiveKind = QLatin1String("enum");
|
|
||||||
detectedRestrictiveName = access.m_name;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scope->hasEnumerationKey(access.m_name)) {
|
||||||
|
detectedRestrictiveKind = QLatin1String("enum");
|
||||||
|
detectedRestrictiveName = access.m_name;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -360,10 +354,6 @@ bool CheckIdentifiers::operator()(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Lots of builtins are missing
|
|
||||||
if (memberAccessBase.m_name == QLatin1String("Qt"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto typeIt = m_types.find(memberAccessBase.m_name);
|
const auto typeIt = m_types.find(memberAccessBase.m_name);
|
||||||
if (typeIt != m_types.end()) {
|
if (typeIt != m_types.end()) {
|
||||||
if (typeIt->isNull()) {
|
if (typeIt->isNull()) {
|
||||||
|
@ -389,7 +379,7 @@ bool CheckIdentifiers::operator()(
|
||||||
const auto firstElement = root->childScopes()[0];
|
const auto firstElement = root->childScopes()[0];
|
||||||
if (firstElement->hasProperty(memberAccessBase.m_name)
|
if (firstElement->hasProperty(memberAccessBase.m_name)
|
||||||
|| firstElement->hasMethod(memberAccessBase.m_name)
|
|| firstElement->hasMethod(memberAccessBase.m_name)
|
||||||
|| firstElement->enumerations().contains(memberAccessBase.m_name)) {
|
|| firstElement->hasEnumeration(memberAccessBase.m_name)) {
|
||||||
m_colorOut->writePrefixedMessage(
|
m_colorOut->writePrefixedMessage(
|
||||||
memberAccessBase.m_name
|
memberAccessBase.m_name
|
||||||
+ QLatin1String(" is a member of the root element\n")
|
+ QLatin1String(" is a member of the root element\n")
|
||||||
|
|
Loading…
Reference in New Issue