qmllint: Move deprecation logic to qmlcompiler

Moves the remaining logic for handling deprecation warnings to qmlcompiler furthering the goal of removing checkidentifiers for good.

Change-Id: I21ac524ea9c02b2e8c8f65962011976927fd7432
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Maximilian Goldstein 2021-07-22 18:46:18 +02:00
parent 96de5c702b
commit ad02973c05
4 changed files with 69 additions and 42 deletions

View File

@ -237,7 +237,7 @@ void QQmlJSTypePropagator::generate_LoadGlobalLookup(int index)
generate_LoadName(m_jsUnitGenerator->lookupNameIndex(index));
}
void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name)
QQmlJS::SourceLocation QQmlJSTypePropagator::getCurrentSourceLocation() const
{
Q_ASSERT(m_currentContext->sourceLocationTable);
const auto &entries = m_currentContext->sourceLocationTable->entries;
@ -247,6 +247,13 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name)
Q_ASSERT(item != entries.end());
auto location = item->location;
return location;
}
void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name) const
{
auto location = getCurrentSourceLocation();
if (m_currentScope->isInCustomParserParent()) {
Q_ASSERT(!m_currentScope->baseType().isNull());
// Only ignore custom parser based elements if it's not Connections.
@ -339,6 +346,54 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name)
}
}
void QQmlJSTypePropagator::checkDeprecated(QQmlJSScope::ConstPtr scope, const QString &name,
bool isMethod) const
{
Q_ASSERT(!scope.isNull());
auto qmlScope = QQmlJSScope::findCurrentQMLScope(scope);
if (qmlScope.isNull())
return;
QList<QQmlJSAnnotation> annotations;
QQmlJSMetaMethod method;
if (isMethod) {
const QVector<QQmlJSMetaMethod> methods = qmlScope->methods(name);
if (methods.isEmpty())
return;
method = methods.constFirst();
annotations = method.annotations();
} else {
QQmlJSMetaProperty property = qmlScope->property(name);
if (!property.isValid())
return;
annotations = property.annotations();
}
auto deprecationAnn = std::find_if(
annotations.constBegin(), annotations.constEnd(),
[](const QQmlJSAnnotation &annotation) { return annotation.isDeprecation(); });
if (deprecationAnn == annotations.constEnd())
return;
QQQmlJSDeprecation deprecation = deprecationAnn->deprecation();
QString descriptor = name;
if (isMethod)
descriptor += u'(' + method.parameterNames().join(u", "_qs) + u')';
QString message = QStringLiteral("%1 \"%2\" is deprecated")
.arg(isMethod ? u"Method"_qs : u"Property"_qs)
.arg(descriptor);
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
m_logger->logWarning(message, Log_Deprecation, getCurrentSourceLocation());
}
void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index)
{
const QString name =
@ -353,8 +408,9 @@ void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index)
return;
}
m_state.savedPrefix.clear();
checkDeprecated(m_currentScope, name, false);
m_state.savedPrefix.clear();
if (!m_state.accumulatorOut.isValid()) {
setError(u"Cannot access value for name "_qs + name, true);
handleUnqualifiedAccess(name);
@ -554,6 +610,8 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
return;
}
checkDeprecated(containedType, propertyName, true);
propagateCall(member.method(), argc, argv);
}
@ -670,7 +728,9 @@ void QQmlJSTypePropagator::generate_CallGlobalLookup(int index, int argc, int ar
void QQmlJSTypePropagator::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
{
propagateScopeLookupCall(m_jsUnitGenerator->lookupName(index), argc, argv);
const QString name = m_jsUnitGenerator->lookupName(index);
propagateScopeLookupCall(name, argc, argv);
checkDeprecated(m_currentScope, name, true);
}
void QQmlJSTypePropagator::generate_CallWithSpread(int func, int thisObject, int argc, int argv)

View File

@ -260,7 +260,9 @@ private:
bool needsMorePasses = false;
};
void handleUnqualifiedAccess(const QString &name);
void handleUnqualifiedAccess(const QString &name) const;
void checkDeprecated(QQmlJSScope::ConstPtr scope, const QString &name, bool isMethod) const;
QQmlJS::SourceLocation getCurrentSourceLocation() const;
void propagateBinaryOperation(QSOperator::Op op, int lhs);
void propagateCall(const QList<QQmlJSMetaMethod> &methods, int argc, int argv);

View File

@ -1,3 +1,5 @@
import QtQml
QtObject {
@Deprecated {}
property int deprecated: 10

View File

@ -306,48 +306,11 @@ void CheckIdentifiers::operator()(
}
auto qmlScope = QQmlJSScope::findCurrentQMLScope(currentScope);
if (qmlScope->hasMethod(memberAccessBase.m_name)) {
// a property of a JavaScript function, or a method
auto methods = qmlScope->methods(memberAccessBase.m_name);
const QQmlJSMetaMethod &method = methods.constFirst();
const auto &annotations = method.annotations();
auto deprecationAnn = std::find_if(annotations.constBegin(), annotations.constEnd(), [](const QQmlJSAnnotation& annotation) {
return annotation.isDeprecation();
});
// Once we encountered one possible method that is not deprecated,
// we can assume that the one beyond that is not what was being referenced
if (deprecationAnn == annotations.constEnd())
continue;
QQQmlJSDeprecation deprecation = deprecationAnn->deprecation();
QString message = QStringLiteral("Method \"%1(%2)\" is deprecated")
.arg(memberAccessBase.m_name, method.parameterNames().join(QStringLiteral(", ")));
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
m_logger->logWarning(message, Log_Deprecation, memberAccessBase.m_location);
if (qmlScope->hasMethod(memberAccessBase.m_name))
continue;
}
const auto property = qmlScope->property(memberAccessBase.m_name);
if (!property.propertyName().isEmpty()) {
for (const QQmlJSAnnotation &annotation : property.annotations()) {
if (annotation.isDeprecation()) {
QQQmlJSDeprecation deprecation = annotation.deprecation();
QString message = QStringLiteral("Property \"%1\" is deprecated")
.arg(memberAccessBase.m_name);
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
m_logger->logWarning(message, Log_Deprecation, memberAccessBase.m_location);
}
}
if (memberAccessChain.isEmpty() || unknownBuiltins.contains(property.typeName()))
continue;