qmltyperegistrar: add line numbers to methods, properties and signals

Minimal cherry-pick of a20a9e83d4 that
only includes the reading of line numbers from moc output and the
writing of line numbers in qmltypes files. Line numbers are not read
from qmltypes files, and the qqmljsscopes won't contain that
information.

Task-number: QTBUG-119143
Task-number: QTBUG-128393
Change-Id: Id77ef37f1503bd17fa42a355770a1ffeb348b46e
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit a20a9e83d4)
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Sami Shalayel 2025-07-31 13:29:55 +02:00
parent 9aa8d8d8b4
commit 2393955890
6 changed files with 131 additions and 27 deletions

View File

@ -5,4 +5,5 @@ import QML
QtObject {
required property string name
property int lineNumber: 0
}

View File

@ -254,12 +254,13 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
scope->setIsJavaScriptBuiltin(true);
} else {
addWarning(script->firstSourceLocation(),
tr("Expected only name, prototype, defaultProperty, attachedType, "
tr("Expected only lineNumber, name, prototype, defaultProperty, "
"attachedType, "
"valueType, exports, interfaces, isSingleton, isCreatable, "
"isStructured, isComposite, hasCustomParser, enforcesScopedEnums, "
"aliases, exportMetaObjectRevisions, deferredNames, and "
"immediateNames in script bindings, not \"%1\".")
.arg(name));
.arg(name));
}
} else {
addWarning(member->firstSourceLocation(),
@ -303,6 +304,8 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(
QString name = toString(script->qualifiedId);
if (name == QLatin1String("name")) {
metaMethod.setMethodName(readStringBinding(script));
} else if (name == QLatin1String("lineNumber")) {
// only used in 6.11
} else if (name == QLatin1String("type")) {
metaMethod.setReturnTypeName(readStringBinding(script));
} else if (name == QLatin1String("revision")) {
@ -343,7 +346,8 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(
metaMethod.setIsConst(readBoolBinding(script));
} else {
addWarning(script->firstSourceLocation(),
tr("Expected only name, type, revision, isPointer, isTypeConstant, "
tr("Expected only name, lineNumber, type, revision, isPointer, "
"isTypeConstant, "
"isList, isCloned, isConstructor, isMethodConstant, and "
"isJavaScriptFunction in script bindings."));
}
@ -388,6 +392,8 @@ void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQ
QString id = toString(script->qualifiedId);
if (id == QLatin1String("name")) {
property.setPropertyName(readStringBinding(script));
} else if (id == QLatin1String("lineNumber")) {
// only used in 6.11
} else if (id == QLatin1String("type")) {
property.setTypeName(readStringBinding(script));
} else if (id == QLatin1String("isPointer")) {
@ -425,8 +431,10 @@ void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQ
property.setPrivateClass(readStringBinding(script));
} else {
addWarning(script->firstSourceLocation(),
tr("Expected only type, name, revision, isPointer, isTypeConstant, isReadonly, isRequired, "
"isFinal, isList, bindable, read, write, isPropertyConstant, reset, notify, index, and "
tr("Expected only type, name, lineNumber, revision, isPointer, "
"isTypeConstant, isReadonly, isRequired, "
"isFinal, isList, bindable, read, write, isPropertyConstant, reset, "
"notify, index, and "
"privateClass and script bindings."));
}
}
@ -467,9 +475,12 @@ void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast, const QQmlJS
metaEnum.setIsScoped(readBoolBinding(script));
} else if (name == QLatin1String("type")) {
metaEnum.setTypeName(readStringBinding(script));
} else if (name == QLatin1String("lineNumber")) {
// only used in 6.11
} else {
addWarning(script->firstSourceLocation(),
tr("Expected only name, alias, isFlag, values, isScoped, or type."));
tr("Expected only name, alias, isFlag, values, isScoped, type, or "
"lineNumber."));
}
}

View File

@ -757,6 +757,7 @@ Property::Property(const QCborMap &cbor)
, bindable(cbor[S_BINDABLE].toStringView())
, privateClass(cbor[S_PRIVATE_CLASS].toStringView())
, index(cbor[S_INDEX].toInteger(-1))
, lineNumber(cbor[S_LINENUMBER].toInteger(0))
, revision(getRevision(cbor))
, isFinal(cbor[S_FINAL].toBool())
, isConstant(cbor[S_CONSTANT].toBool())
@ -774,6 +775,7 @@ Method::Method(const QCborMap &cbor, bool isConstructor)
: name(cbor[S_NAME].toStringView())
, returnType(cbor[S_RETURN_TYPE].toStringView())
, index(cbor[S_INDEX].toInteger(InvalidIndex))
, lineNumber(cbor[S_LINENUMBER].toInteger(0))
, revision(getRevision(cbor))
, access(getAccess(cbor))
, isCloned(cbor[S_IS_CLONED].toBool())
@ -798,6 +800,7 @@ Enum::Enum(const QCborMap &cbor)
: name(cbor[S_NAME].toStringView())
, alias(cbor[S_ALIAS].toStringView())
, type(cbor[S_TYPE].toStringView())
, lineNumber(cbor[S_LINENUMBER].toInteger(0))
, isFlag(cbor[S_IS_FLAG].toBool())
, isClass(cbor[S_IS_CLASS].toBool())
{

View File

@ -84,6 +84,7 @@ struct Property
QAnyStringView privateClass;
int index = -1;
int lineNumber = 0;
QTypeRevision revision;
@ -117,6 +118,7 @@ struct Method
QAnyStringView returnType;
int index = InvalidIndex;
int lineNumber = 0;
QTypeRevision revision;
@ -141,6 +143,7 @@ struct Enum
QList<QAnyStringView> values;
int lineNumber = 0;
bool isFlag = false;
bool isClass = false;
};

View File

@ -216,6 +216,10 @@ void QmlTypesCreator::writeProperties(const Property::Container &properties)
if (index != -1) {
m_qml.writeNumberBinding(S_INDEX, index);
}
const auto lineNumber = obj.lineNumber;
if (lineNumber != 0)
m_qml.writeNumberBinding(S_LINE_NUMBER, obj.lineNumber);
const auto privateClass = obj.privateClass;
if (!privateClass.isEmpty()) {
m_qml.writeStringBinding(
@ -260,6 +264,9 @@ void QmlTypesCreator::writeMethods(const Method::Container &methods, QLatin1Stri
m_qml.writeBooleanBinding(S_IS_JAVASCRIPT_FUNCTION, true);
if (obj.isConst)
m_qml.writeBooleanBinding(S_IS_METHOD_CONSTANT, true);
const auto lineNumber = obj.lineNumber;
if (lineNumber != 0)
m_qml.writeNumberBinding(S_LINE_NUMBER, obj.lineNumber);
const Argument::Container &arguments = obj.arguments;
for (qsizetype i = 0, end = arguments.size(); i != end; ++i) {
@ -287,6 +294,9 @@ void QmlTypesCreator::writeEnums(const Enum::Container &enums)
if (obj.isClass)
m_qml.writeBooleanBinding(S_IS_SCOPED, true);
writeType(obj.type);
const auto lineNumber = obj.lineNumber;
if (lineNumber != 0)
m_qml.writeNumberBinding(S_LINE_NUMBER, obj.lineNumber);
m_qml.writeStringListBinding(S_VALUES, obj.values);
m_qml.writeEndObject();
}

View File

@ -104,9 +104,26 @@ void tst_qmltyperegistrar::superAndForeignTypes()
QVERIFY(qmltypesData.contains("values: [\"Pixel\", \"Centimeter\", \"Inch\", \"Point\"]"));
QVERIFY(qmltypesData.contains("name: \"SizeGadget\""));
QVERIFY(qmltypesData.contains("prototype: \"SizeEnums\""));
QVERIFY(qmltypesData.contains("Property { name: \"height\"; type: \"int\"; read: \"height\"; write: \"setHeight\"; index: 0; isFinal: true }"));
QVERIFY(qmltypesData.contains("Property { name: \"width\"; type: \"int\"; read: \"width\"; write: \"setWidth\"; index: 0; isFinal: true }"));
QVERIFY(qmltypesData.contains("Method { name: \"sizeToString\"; type: \"QString\"; isMethodConstant: true }"));
QVERIFY(qmltypesData.contains(R"(Property {
name: "height"
type: "int"
read: "height"
write: "setHeight"
index: 0
lineNumber: 31
isFinal: true
})"));
QVERIFY(qmltypesData.contains(R"(Property {
name: "width"
type: "int"
read: "width"
write: "setWidth"
index: 0
lineNumber: 94
isFinal: true
})"));
QVERIFY(qmltypesData.contains("Method { name: \"sizeToString\"; type: \"QString\"; "
"isMethodConstant: true; lineNumber: 100 }"));
QCOMPARE(qmltypesData.count("extension: \"SizeValueType\""), 1);
}
@ -118,7 +135,13 @@ void tst_qmltyperegistrar::accessSemantics()
void tst_qmltyperegistrar::isBindable()
{
QVERIFY(qmltypesData.contains(R"(Property { name: "someProperty"; type: "int"; bindable: "bindableSomeProperty"; index: 0 })"));
QVERIFY(qmltypesData.contains(R"(Property {
name: "someProperty"
type: "int"
bindable: "bindableSomeProperty"
index: 0
lineNumber: 162
})"));
}
void tst_qmltyperegistrar::doNotRestrictToImportVersion()
@ -250,7 +273,7 @@ void tst_qmltyperegistrar::finalProperty()
{
QCOMPARE(qmltypesData.count("name: \"FinalProperty\""), 1);
QCOMPARE(qmltypesData.count(
"Property { name: \"fff\"; type: \"int\"; index: 0; isFinal: true }"),
"Property { name: \"fff\"; type: \"int\"; index: 0; lineNumber: 244; isFinal: true }"),
1);
}
@ -574,16 +597,18 @@ void tst_qmltyperegistrar::clonedSignal()
{
QVERIFY(qmltypesData.contains(R"(Signal {
name: "clonedSignal"
lineNumber: 548
Parameter { name: "i"; type: "int" }
})"));
QVERIFY(qmltypesData.contains(R"(Signal { name: "clonedSignal"; isCloned: true })"));
QVERIFY(qmltypesData.contains(R"(Signal { name: "clonedSignal"; isCloned: true; lineNumber: 548 })"));
}
void tst_qmltyperegistrar::hasIsConstantInParameters()
{
QVERIFY(qmltypesData.contains(R"( Signal {
name: "mySignal"
lineNumber: 17
Parameter { name: "myObject"; type: "QObject"; isPointer: true }
Parameter { name: "myConstObject"; type: "QObject"; isPointer: true; isTypeConstant: true }
Parameter { name: "myConstObject2"; type: "QObject"; isPointer: true; isTypeConstant: true }
@ -594,6 +619,7 @@ void tst_qmltyperegistrar::hasIsConstantInParameters()
QVERIFY(qmltypesData.contains(R"(Signal {
name: "myVolatileSignal"
lineNumber: 19
Parameter { name: "a"; type: "volatile QObject"; isPointer: true; isTypeConstant: true }
Parameter { name: "b"; type: "volatile QObject"; isPointer: true; isTypeConstant: true }
Parameter { name: "nonConst"; type: "volatile QObject"; isPointer: true }
@ -783,9 +809,10 @@ void tst_qmltyperegistrar::constructibleValueType()
Method {
name: "Constructible"
isConstructor: true
lineNumber: 564
Parameter { name: "i"; type: "int" }
}
Method { name: "Constructible"; isCloned: true; isConstructor: true }
Method { name: "Constructible"; isCloned: true; isConstructor: true; lineNumber: 564 }
})"));
}
@ -800,7 +827,7 @@ void tst_qmltyperegistrar::structuredValueType()
exports: ["QmlTypeRegistrarTest/structured 1.0"]
isStructured: true
exportMetaObjectRevisions: [256]
Property { name: "i"; type: "int"; index: 0; isFinal: true }
Property { name: "i"; type: "int"; index: 0; lineNumber: 575; isFinal: true }
})"));
}
@ -842,56 +869,67 @@ void tst_qmltyperegistrar::typedEnum()
Enum {
name: "UChar"
type: "quint8"
lineNumber: 604
values: ["V0"]
}
Enum {
name: "Int8_T"
type: "qint8"
lineNumber: 606
values: ["V1"]
}
Enum {
name: "UInt8_T"
type: "quint8"
lineNumber: 608
values: ["V2"]
}
Enum {
name: "Int16_T"
type: "short"
lineNumber: 610
values: ["V3"]
}
Enum {
name: "UInt16_T"
type: "ushort"
lineNumber: 612
values: ["V4"]
}
Enum {
name: "Int32_T"
type: "int"
lineNumber: 614
values: ["V5"]
}
Enum {
name: "UInt32_T"
type: "uint"
lineNumber: 616
values: ["V6"]
}
Enum {
name: "S"
type: "short"
lineNumber: 622
values: ["A", "B", "C"]
}
Enum {
name: "T"
type: "ushort"
lineNumber: 627
values: ["D", "E", "F"]
}
Enum {
name: "U"
type: "qint8"
lineNumber: 632
values: ["G", "H", "I"]
}
Enum {
name: "V"
type: "quint8"
lineNumber: 637
values: ["J", "K", "L"]
}
})"));
@ -908,6 +946,7 @@ void tst_qmltyperegistrar::listSignal()
prototype: "QObject"
Signal {
name: "objectListHappened"
lineNumber: 649
Parameter { type: "QObjectList" }
}
})"));
@ -926,6 +965,7 @@ void tst_qmltyperegistrar::withNamespace()
type: "int"
read: "bar"
index: 0
lineNumber: 655
isReadonly: true
isPropertyConstant: true
}
@ -944,6 +984,7 @@ void tst_qmltyperegistrar::withNamespace()
type: "int"
read: "bar"
index: 0
lineNumber: 676
isReadonly: true
isPropertyConstant: true
}
@ -960,6 +1001,7 @@ void tst_qmltyperegistrar::withNamespace()
type: "int"
read: "foo"
index: 0
lineNumber: 666
isReadonly: true
isPropertyConstant: true
}
@ -1003,7 +1045,15 @@ void tst_qmltyperegistrar::valueTypeSelfReference()
lineNumber: 708
name: "QPersistentModelIndexValueType"
accessSemantics: "value"
Property { name: "row"; type: "int"; read: "row"; index: 0; isReadonly: true; isFinal: true }
Property {
name: "row"
type: "int"
read: "row"
index: 0
lineNumber: 711
isReadonly: true
isFinal: true
}
})"));
}
@ -1115,10 +1165,10 @@ void tst_qmltyperegistrar::longNumberTypes()
prototype: "QObject"
exports: ["QmlTypeRegistrarTest/LongNumberTypes 1.0"]
exportMetaObjectRevisions: [256]
Property { name: "a"; type: "qlonglong"; index: 0 }
Property { name: "b"; type: "qlonglong"; index: 1 }
Property { name: "c"; type: "qulonglong"; index: 2 }
Property { name: "d"; type: "qulonglong"; index: 3 }
Property { name: "a"; type: "qlonglong"; index: 0; lineNumber: 772 }
Property { name: "b"; type: "qlonglong"; index: 1; lineNumber: 773 }
Property { name: "c"; type: "qulonglong"; index: 2; lineNumber: 774 }
Property { name: "d"; type: "qulonglong"; index: 3; lineNumber: 775 }
})"));
}
@ -1142,7 +1192,13 @@ void tst_qmltyperegistrar::constReturnType()
prototype: "QObject"
exports: ["QmlTypeRegistrarTest/ConstInvokable 1.0"]
exportMetaObjectRevisions: [256]
Method { name: "getObject"; type: "QObject"; isPointer: true; isTypeConstant: true }
Method {
name: "getObject"
type: "QObject"
isPointer: true
isTypeConstant: true
lineNumber: 796
}
})"));
}
@ -1156,7 +1212,15 @@ void tst_qmltyperegistrar::usingDeclaration()
prototype: "QObject"
exports: ["QmlTypeRegistrarTest/WithMyInt 1.0"]
exportMetaObjectRevisions: [256]
Property { name: "a"; type: "int"; read: "a"; index: 0; isReadonly: true; isPropertyConstant: true }
Property {
name: "a"
type: "int"
read: "a"
index: 0
lineNumber: 812
isReadonly: true
isPropertyConstant: true
}
})"));
}
@ -1205,9 +1269,9 @@ void tst_qmltyperegistrar::slotsBeforeInvokables()
name: "SlotsBeforeInvokables"
accessSemantics: "reference"
prototype: "QObject"
Method { name: "bar" }
Method { name: "foo" }
Method { name: "baz" }
Method { name: "bar"; lineNumber: 833 }
Method { name: "foo"; lineNumber: 831 }
Method { name: "baz"; lineNumber: 835 }
})"));
}
@ -1221,7 +1285,7 @@ void tst_qmltyperegistrar::omitQQmlV4FunctionPtrArg()
prototype: "QObject"
exports: ["QmlTypeRegistrarTest/JavaScriptFunction 1.0"]
exportMetaObjectRevisions: [256]
Method { name: "jsfunc"; isJavaScriptFunction: true }
Method { name: "jsfunc"; isJavaScriptFunction: true; lineNumber: 844 }
})"));
}
@ -1241,6 +1305,7 @@ void tst_qmltyperegistrar::preserveVoidStarPropTypes()
isPointer: true
read: "void1"
index: 0
lineNumber: 858
isReadonly: true
isPropertyConstant: true
}
@ -1250,6 +1315,7 @@ void tst_qmltyperegistrar::preserveVoidStarPropTypes()
isPointer: true
read: "void2"
index: 1
lineNumber: 859
isReadonly: true
isPropertyConstant: true
}
@ -1271,7 +1337,7 @@ void tst_qmltyperegistrar::inaccessibleBase()
name: "InaccessibleBase"
accessSemantics: "reference"
prototype: "QObject"
Property { name: "a"; type: "int"; index: 0; isPropertyConstant: true }
Property { name: "a"; type: "int"; index: 0; lineNumber: 12; isPropertyConstant: true }
})"));
QVERIFY(!qmltypesData.contains(R"(name: "InaccessibleProperty")"));
@ -1289,6 +1355,7 @@ void tst_qmltyperegistrar::inaccessibleBase()
type: "InaccessibleProperty"
isPointer: true
index: 0
lineNumber: 872
isPropertyConstant: true
}
})"));
@ -1333,7 +1400,15 @@ void tst_qmltyperegistrar::derivedFromInvisible()
prototype: "InvisibleBase"
exports: ["QmlTypeRegistrarTest/DerivedFromInvisible 1.0"]
exportMetaObjectRevisions: [256]
Property { name: "b"; type: "int"; read: "b"; index: 0; isReadonly: true; isPropertyConstant: true }
Property {
name: "b"
type: "int"
read: "b"
index: 0
lineNumber: 890
isReadonly: true
isPropertyConstant: true
}
})"));
}
@ -1351,6 +1426,7 @@ void tst_qmltyperegistrar::foreignNamespacedWithEnum()
Enum {
name: "Enum"
isScoped: true
lineNumber: 903
values: ["ValueA", "ValueB"]
}
})"));