73 const QVector<MetaType> &types,
const QVector<MetaType> &foreign,
74 const QAnyStringView &name,
const QList<QAnyStringView> &namespaces)
76 const auto tryFindType = [&](QAnyStringView qualifiedName) ->
FoundType {
78 for (
const QVector<MetaType> &t : {types, foreign}) {
79 const auto [first, last] = std::equal_range(
80 t.begin(), t.end(), qualifiedName, Compare());
81 for (
auto it = first; it != last; ++it) {
82 Q_ASSERT(it->qualifiedClassName() == qualifiedName);
84 if (it->inputFile().isEmpty()) {
85 if (result.javaScript.isEmpty()) {
86 result.javaScript = *it;
87 result.javaScriptOrigin = (&t == &types)
89 : FoundType::ForeignTypes;
91 warning(result.javaScript)
92 <<
"Multiple JavaScript types called" << qualifiedName <<
"found!";
94 }
else if (result.native.isEmpty()) {
96 result.nativeOrigin = (&t == &types)
98 : FoundType::ForeignTypes;
100 warning(result.native)
101 <<
"Multiple C++ types called" << qualifiedName <<
"found!\n"
102 <<
"(other occurrence in :"
103 << it->inputFile() <<
":" << it->lineNumber() <<
")\n"
104 <<
"This violates the One Definition Rule!";
112 if (startsWith(name, QLatin1String(
"::")))
113 return tryFindType(name.mid(2));
116 for (
int i = 0, end = namespaces.length(); i != end; ++i) {
117 for (
int j = 0; j < end - i; ++j) {
118 namespaces[j].visit([&](
auto data) { qualified.append(data); });
119 qualified.append(QLatin1String(
"::"));
121 name.visit([&](
auto data) { qualified.append(data); });
122 if (
const FoundType found = tryFindType(qualified))
125 qualified.truncate(0);
128 return tryFindType(name);
214 const MetaType &classDef,
const QVector<MetaType> &types,
215 const QVector<MetaType> &foreign,
CollectMode mode, QTypeRevision defaultRevision)
217 if (file.isEmpty()) {
218 file = classDef.inputFile();
222 const QAnyStringView classDefName = classDef.className();
223 const QList<QAnyStringView> namespaces = MetaTypesJsonProcessor::namespaces(classDef);
225 QAnyStringView foreignTypeName;
226 bool foreignIsNamespace =
false;
227 bool isConstructible =
false;
228 for (
const ClassInfo &obj : classDef.classInfos()) {
229 const QAnyStringView name = obj.name;
230 const QAnyStringView value = obj.value;
232 if (name == S_DEFAULT_PROPERTY) {
233 if (mode != RelatedType && defaultProp.isEmpty())
238 if (name == S_PARENT_PROPERTY) {
239 if (mode != RelatedType && parentProp.isEmpty())
244 if (name == S_REGISTER_ENUM_CLASSES_UNSCOPED) {
245 if (mode != RelatedType)
246 handleRegisterEnumClassesUnscoped(classDef, value);
250 if (name == S_ADDED_IN_VERSION) {
251 const QTypeRevision revision = handleInMinorVersion(
252 QTypeRevision::fromEncodedVersion(toInt(value)),
253 defaultRevision.majorVersion());
254 revisions.append(revision);
255 if (mode == TopLevel)
256 addedInRevision = revision;
260 if (mode != TopLevel)
263 if (name == S_REMOVED_IN_VERSION) {
264 removedInRevision = handleInMinorVersion(
265 QTypeRevision::fromEncodedVersion(toInt(value)),
266 defaultRevision.majorVersion());
271 if (name == S_ELEMENT) {
273 elementNames.append(classDefName);
274 else if (value != S_ANONYMOUS)
275 elementNames.append(value);
276 }
else if (name == S_CREATABLE) {
277 isCreatable = (value != S_FALSE);
278 }
else if (name == S_CREATION_METHOD) {
279 isStructured = (value == S_STRUCTURED);
280 isConstructible = isStructured || (value == S_CONSTRUCT);
281 }
else if (name == S_ATTACHED) {
282 if (
const FoundType attached = collectRelated(
283 value, types, foreign, defaultRevision, namespaces)) {
284 attachedType = attached.select(classDef,
"Attached").qualifiedClassName();
286 }
else if (name == S_EXTENDED) {
287 if (
const FoundType extension = collectRelated(
288 value, types, foreign, defaultRevision, namespaces)) {
289 javaScriptExtensionType = extension.javaScript.qualifiedClassName();
290 nativeExtensionType = extension.native.qualifiedClassName();
292 }
else if (name == S_EXTENSION_IS_JAVA_SCRIPT) {
294 extensionIsJavaScript =
true;
295 }
else if (name == S_EXTENSION_IS_NAMESPACE) {
297 extensionIsNamespace =
true;
298 }
else if (name == S_SEQUENCE) {
299 if (
const FoundType element = collectRelated(
300 value, types, foreign, defaultRevision, namespaces)) {
301 sequenceValueType = element.select(classDef,
"Sequence value").qualifiedClassName();
304 sequenceValueType = value;
306 }
else if (name == S_SINGLETON) {
309 }
else if (name == S_FOREIGN) {
310 foreignTypeName = value;
311 }
else if (name == S_FOREIGN_IS_NAMESPACE) {
312 foreignIsNamespace = (value == S_TRUE);
313 }
else if (name == S_PRIMITIVE_ALIAS) {
314 primitiveAliases.append(value);
315 }
else if (name == S_ROOT) {
316 isRootClass = (value == S_TRUE);
317 }
else if (name == S_HAS_CUSTOM_PARSER) {
319 hasCustomParser =
true;
320 }
else if (name == S_DEFERRED_PROPERTY_NAMES) {
321 deferredNames = split(value, QLatin1StringView(
","));
322 }
else if (name == S_IMMEDIATE_PROPERTY_NAMES) {
323 immediateNames = split(value, QLatin1StringView(
","));
327 if (addedInRevision.isValid() && !elementNames.isEmpty())
328 revisions.append(addedInRevision);
332 const bool isNamespace = foreignIsNamespace || classDef.kind() == MetaType::Kind::Namespace;
335 if (!foreignTypeName.isEmpty()) {
337 if (
const FoundType found = findType(foreign, types, foreignTypeName, namespaces)) {
338 resolved = found.select(classDef,
"Foreign");
346 for (
const ClassInfo &obj : resolved.classInfos()) {
347 const QAnyStringView foreignName = obj.name;
348 const QAnyStringView foreignValue = obj.value;
349 if (defaultProp.isEmpty() && foreignName == S_DEFAULT_PROPERTY) {
350 defaultProp = foreignValue;
351 }
else if (parentProp.isEmpty() && foreignName == S_PARENT_PROPERTY) {
352 parentProp = foreignValue;
353 }
else if (foreignName == S_REGISTER_ENUM_CLASSES_UNSCOPED) {
354 handleRegisterEnumClassesUnscoped(resolved, foreignValue);
355 }
else if (foreignName == S_ATTACHED) {
356 if (
const FoundType attached = collectRelated(
357 foreignValue, types, foreign, defaultRevision, namespaces)) {
358 attachedType = attached.select(resolved,
"Attached").qualifiedClassName();
360 }
else if (foreignName == S_EXTENDED) {
361 if (
const FoundType extension = collectRelated(
362 foreignValue, types, foreign, defaultRevision, namespaces)) {
363 nativeExtensionType = extension.native.qualifiedClassName();
364 javaScriptExtensionType = extension.javaScript.qualifiedClassName();
366 }
else if (foreignName == S_EXTENSION_IS_JAVA_SCRIPT) {
367 if (foreignValue == S_TRUE)
368 extensionIsJavaScript =
true;
369 }
else if (foreignName == S_EXTENSION_IS_NAMESPACE) {
370 if (foreignValue == S_TRUE)
371 extensionIsNamespace =
true;
372 }
else if (foreignName == S_SEQUENCE) {
373 if (
const FoundType element = collectRelated(
374 foreignValue, types, foreign, defaultRevision, namespaces)) {
376 = element.select(resolved,
"Sequence value").qualifiedClassName();
381 className = foreignTypeName;
387 if (mode == RelatedType || !elementNames.isEmpty()) {
388 collectExtraVersions(resolved.properties(), revisions);
389 collectExtraVersions(resolved.methods(), revisions);
390 collectExtraVersions(resolved.sigs(), revisions);
393 collectSuperClasses(resolved, types, foreign, mode, defaultRevision);
400 collectInterfaces(resolved);
402 if (!addedInRevision.isValid()) {
403 addedInRevision = defaultRevision;
405 if (addedInRevision <= defaultRevision
406 && (!removedInRevision.isValid() || defaultRevision < removedInRevision)) {
407 revisions.append(defaultRevision);
410 std::sort(revisions.begin(), revisions.end());
411 const auto end = std::unique(revisions.begin(), revisions.end());
412 revisions.erase(QList<QTypeRevision>::const_iterator(end), revisions.constEnd());
415 if (className.isEmpty() && !resolved.isEmpty())
416 className = resolved.qualifiedClassName();
418 if (!sequenceValueType.isEmpty()) {
420 accessSemantics = DotQmltypes::S_SEQUENCE;
421 }
else if (isNamespace) {
423 accessSemantics = DotQmltypes::S_NONE;
424 }
else if (resolved.kind() == MetaType::Kind::Object) {
425 accessSemantics = DotQmltypes::S_REFERENCE;
430 if (elementNames.isEmpty()) {
433 accessSemantics = DotQmltypes::S_VALUE;
436 for (
auto elementName = elementNames.begin(); elementName != elementNames.end();) {
437 if (elementName->isEmpty() || elementName->front().isLower()) {
440 accessSemantics = DotQmltypes::S_VALUE;
449 <<
"Refusing to generate non-lowercase name"
450 << *elementName <<
"for unknown foreign type";
451 elementName = elementNames.erase(elementName);
453 if (elementNames.isEmpty()) {
456 accessSemantics = DotQmltypes::S_NONE;
460 }
else if (resolved.kind() == MetaType::Kind::Gadget) {
461 accessSemantics = DotQmltypes::S_VALUE;
463 accessSemantics = DotQmltypes::S_NONE;