74 const QList<MetaType> &types,
const QList<MetaType> &foreign,
75 const QAnyStringView &name,
const QList<QAnyStringView> &namespaces)
77 const auto tryFindType = [&](QAnyStringView qualifiedName) ->
FoundType {
79 for (
const QList<MetaType> &t : {types, foreign}) {
80 const auto [first, last] = std::equal_range(
81 t.begin(), t.end(), qualifiedName, Compare());
82 for (
auto it = first; it != last; ++it) {
83 Q_ASSERT(it->qualifiedClassName() == qualifiedName);
85 if (it->inputFile().isEmpty()) {
86 if (result.javaScript.isEmpty()) {
87 result.javaScript = *it;
88 result.javaScriptOrigin = (&t == &types)
90 : FoundType::ForeignTypes;
92 warning(result.javaScript)
93 <<
"Multiple JavaScript types called" << qualifiedName <<
"found!";
95 }
else if (result.native.isEmpty()) {
97 result.nativeOrigin = (&t == &types)
99 : FoundType::ForeignTypes;
101 warning(result.native)
102 <<
"Multiple C++ types called" << qualifiedName <<
"found!\n"
103 <<
"(other occurrence in :"
104 << it->inputFile() <<
":" << it->lineNumber() <<
")\n"
105 <<
"This violates the One Definition Rule!";
113 if (startsWith(name, QLatin1String(
"::")))
114 return tryFindType(name.mid(2));
117 for (
int i = 0, end = namespaces.length(); i != end; ++i) {
118 for (
int j = 0; j < end - i; ++j) {
119 namespaces[j].visit([&](
auto data) { qualified.append(data); });
120 qualified.append(QLatin1String(
"::"));
122 name.visit([&](
auto data) { qualified.append(data); });
123 if (
const FoundType found = tryFindType(qualified))
126 qualified.truncate(0);
129 return tryFindType(name);
215 const MetaType &classDef,
const QList<MetaType> &types,
216 const QList<MetaType> &foreign,
CollectMode mode, QTypeRevision defaultRevision)
218 if (file.isEmpty()) {
219 file = classDef.inputFile();
223 if (metaObjectHash.isEmpty())
224 metaObjectHash = classDef.metaObjectHash();
226 const QAnyStringView classDefName = classDef.className();
227 const QList<QAnyStringView> namespaces = MetaTypesJsonProcessor::namespaces(classDef);
229 QAnyStringView foreignTypeName;
230 bool foreignIsNamespace =
false;
231 bool isConstructible =
false;
232 for (
const ClassInfo &obj : classDef.classInfos()) {
233 const QAnyStringView name = obj.name;
234 const QAnyStringView value = obj.value;
236 if (name == S_DEFAULT_PROPERTY) {
237 if (mode != RelatedType && defaultProp.isEmpty())
242 if (name == S_PARENT_PROPERTY) {
243 if (mode != RelatedType && parentProp.isEmpty())
248 if (name == S_REGISTER_ENUM_CLASSES_UNSCOPED) {
249 if (mode != RelatedType)
250 handleRegisterEnumClassesUnscoped(classDef, value);
254 if (name == S_ADDED_IN_VERSION) {
255 const QTypeRevision revision = handleInMinorVersion(
256 QTypeRevision::fromEncodedVersion(toInt(value)),
257 defaultRevision.majorVersion());
258 revisions.append(revision);
259 if (mode == TopLevel)
260 addedInRevision = revision;
264 if (mode != TopLevel)
267 if (name == S_REMOVED_IN_VERSION) {
268 removedInRevision = handleInMinorVersion(
269 QTypeRevision::fromEncodedVersion(toInt(value)),
270 defaultRevision.majorVersion());
275 if (name == S_ELEMENT) {
277 elementNames.append(classDefName);
278 else if (value != S_ANONYMOUS)
279 elementNames.append(value);
280 }
else if (name == S_CREATABLE) {
281 isCreatable = (value != S_FALSE);
282 }
else if (name == S_CREATION_METHOD) {
283 isStructured = (value == S_STRUCTURED);
284 isConstructible = isStructured || (value == S_CONSTRUCT);
285 }
else if (name == S_ATTACHED) {
286 if (
const FoundType attached = collectRelated(
287 value, types, foreign, defaultRevision, namespaces)) {
288 attachedType = attached.select(classDef,
"Attached").qualifiedClassName();
290 }
else if (name == S_EXTENDED) {
291 if (
const FoundType extension = collectRelated(
292 value, types, foreign, defaultRevision, namespaces)) {
293 javaScriptExtensionType = extension.javaScript.qualifiedClassName();
294 nativeExtensionType = extension.native.qualifiedClassName();
296 }
else if (name == S_EXTENSION_IS_JAVA_SCRIPT) {
298 extensionIsJavaScript =
true;
299 }
else if (name == S_EXTENSION_IS_NAMESPACE) {
301 extensionIsNamespace =
true;
302 }
else if (name == S_SEQUENCE) {
303 if (
const FoundType element = collectRelated(
304 value, types, foreign, defaultRevision, namespaces)) {
305 sequenceValueType = element.select(classDef,
"Sequence value").qualifiedClassName();
308 sequenceValueType = value;
310 }
else if (name == S_SINGLETON) {
313 }
else if (name == S_FOREIGN) {
314 foreignTypeName = value;
315 }
else if (name == S_FOREIGN_IS_NAMESPACE) {
316 foreignIsNamespace = (value == S_TRUE);
317 }
else if (name == S_PRIMITIVE_ALIAS) {
318 primitiveAliases.append(value);
319 }
else if (name == S_ROOT) {
320 isRootClass = (value == S_TRUE);
321 }
else if (name == S_HAS_CUSTOM_PARSER) {
323 hasCustomParser =
true;
324 }
else if (name == S_DEFERRED_PROPERTY_NAMES) {
325 deferredNames = split(value, QLatin1StringView(
","));
326 }
else if (name == S_IMMEDIATE_PROPERTY_NAMES) {
327 immediateNames = split(value, QLatin1StringView(
","));
331 if (addedInRevision.isValid() && !elementNames.isEmpty())
332 revisions.append(addedInRevision);
336 const bool isNamespace = foreignIsNamespace || classDef.kind() == MetaType::Kind::Namespace;
339 if (!foreignTypeName.isEmpty()) {
341 if (
const FoundType found = findType(foreign, types, foreignTypeName, namespaces)) {
342 resolved = found.select(classDef,
"Foreign");
350 for (
const ClassInfo &obj : resolved.classInfos()) {
351 const QAnyStringView foreignName = obj.name;
352 const QAnyStringView foreignValue = obj.value;
353 if (defaultProp.isEmpty() && foreignName == S_DEFAULT_PROPERTY) {
354 defaultProp = foreignValue;
355 }
else if (parentProp.isEmpty() && foreignName == S_PARENT_PROPERTY) {
356 parentProp = foreignValue;
357 }
else if (foreignName == S_REGISTER_ENUM_CLASSES_UNSCOPED) {
358 handleRegisterEnumClassesUnscoped(resolved, foreignValue);
359 }
else if (foreignName == S_ATTACHED) {
360 if (
const FoundType attached = collectRelated(
361 foreignValue, types, foreign, defaultRevision, namespaces)) {
362 attachedType = attached.select(resolved,
"Attached").qualifiedClassName();
364 }
else if (foreignName == S_EXTENDED) {
365 if (
const FoundType extension = collectRelated(
366 foreignValue, types, foreign, defaultRevision, namespaces)) {
367 nativeExtensionType = extension.native.qualifiedClassName();
368 javaScriptExtensionType = extension.javaScript.qualifiedClassName();
370 }
else if (foreignName == S_EXTENSION_IS_JAVA_SCRIPT) {
371 if (foreignValue == S_TRUE)
372 extensionIsJavaScript =
true;
373 }
else if (foreignName == S_EXTENSION_IS_NAMESPACE) {
374 if (foreignValue == S_TRUE)
375 extensionIsNamespace =
true;
376 }
else if (foreignName == S_SEQUENCE) {
377 if (
const FoundType element = collectRelated(
378 foreignValue, types, foreign, defaultRevision, namespaces)) {
380 = element.select(resolved,
"Sequence value").qualifiedClassName();
385 className = foreignTypeName;
391 if (mode == RelatedType || !elementNames.isEmpty()) {
392 collectExtraVersions(resolved.properties(), revisions);
393 collectExtraVersions(resolved.methods(), revisions);
394 collectExtraVersions(resolved.sigs(), revisions);
397 collectSuperClasses(resolved, types, foreign, mode, defaultRevision);
404 collectInterfaces(resolved);
406 if (!addedInRevision.isValid()) {
407 addedInRevision = defaultRevision;
409 if (addedInRevision <= defaultRevision
410 && (!removedInRevision.isValid() || defaultRevision < removedInRevision)) {
411 revisions.append(defaultRevision);
414 std::sort(revisions.begin(), revisions.end());
415 const auto end = std::unique(revisions.begin(), revisions.end());
416 revisions.erase(QList<QTypeRevision>::const_iterator(end), revisions.constEnd());
419 if (className.isEmpty() && !resolved.isEmpty())
420 className = resolved.qualifiedClassName();
422 if (!sequenceValueType.isEmpty()) {
424 accessSemantics = DotQmltypes::S_SEQUENCE;
425 }
else if (isNamespace) {
427 accessSemantics = DotQmltypes::S_NONE;
428 }
else if (resolved.kind() == MetaType::Kind::Object) {
429 accessSemantics = DotQmltypes::S_REFERENCE;
434 if (elementNames.isEmpty()) {
437 accessSemantics = DotQmltypes::S_VALUE;
440 for (
auto elementName = elementNames.begin(); elementName != elementNames.end();) {
441 if (elementName->isEmpty() || elementName->front().isLower()) {
444 accessSemantics = DotQmltypes::S_VALUE;
453 <<
"Refusing to generate non-lowercase name"
454 << *elementName <<
"for unknown foreign type";
455 elementName = elementNames.erase(elementName);
457 if (elementNames.isEmpty()) {
460 accessSemantics = DotQmltypes::S_NONE;
464 }
else if (resolved.kind() == MetaType::Kind::Gadget) {
465 accessSemantics = DotQmltypes::S_VALUE;
467 accessSemantics = DotQmltypes::S_NONE;