Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmljstypedescriptionreader.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include <QtQml/private/qqmljsparser_p.h>
7#include <QtQml/private/qqmljslexer_p.h>
8#include <QtQml/private/qqmljsengine_p.h>
9
10#include <QtCore/qdir.h>
11#include <QtCore/qstring.h>
12
14
15using namespace QQmlJS;
16using namespace QQmlJS::AST;
17using namespace Qt::StringLiterals;
18
19QString toString(const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char('.'))
20{
22
23 for (const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
24 if (iter != qualifiedId)
25 result += delimiter;
26
27 result += iter->name;
28 }
29
30 return result;
31}
32
34 QList<QQmlJSExportedScope> *objects, QStringList *dependencies)
35{
37
38 Lexer lexer(&engine);
39 Parser parser(&engine);
40
41 lexer.setCode(m_source, /*lineno = */ 1, /*qmlMode = */true);
42
43 if (!parser.parse()) {
44 m_errorMessage = QString::fromLatin1("%1:%2: %3").arg(
45 QString::number(parser.errorLineNumber()),
46 QString::number(parser.errorColumnNumber()),
47 parser.errorMessage());
48 return false;
49 }
50
51 m_objects = objects;
52 m_dependencies = dependencies;
53 readDocument(parser.ast());
54
55 return m_errorMessage.isEmpty();
56}
57
58void QQmlJSTypeDescriptionReader::readDocument(UiProgram *ast)
59{
60 if (!ast) {
61 addError(SourceLocation(), tr("Could not parse document."));
62 return;
63 }
64
65 if (!ast->headers || ast->headers->next || !cast<UiImport *>(ast->headers->headerItem)) {
66 addError(SourceLocation(), tr("Expected a single import."));
67 return;
68 }
69
70 auto *import = cast<UiImport *>(ast->headers->headerItem);
71 if (toString(import->importUri) != QLatin1String("QtQuick.tooling")) {
72 addError(import->importToken, tr("Expected import of QtQuick.tooling."));
73 return;
74 }
75
76 if (!import->version) {
77 addError(import->firstSourceLocation(), tr("Import statement without version."));
78 return;
79 }
80
81 if (import->version->version.majorVersion() != 1) {
82 addError(import->version->firstSourceLocation(),
83 tr("Major version different from 1 not supported."));
84 return;
85 }
86
87 if (!ast->members || !ast->members->member || ast->members->next) {
88 addError(SourceLocation(), tr("Expected document to contain a single object definition."));
89 return;
90 }
91
92 auto *module = cast<UiObjectDefinition *>(ast->members->member);
93 if (!module) {
94 addError(SourceLocation(), tr("Expected document to contain a single object definition."));
95 return;
96 }
97
98 if (toString(module->qualifiedTypeNameId) != QLatin1String("Module")) {
99 addError(SourceLocation(), tr("Expected document to contain a Module {} member."));
100 return;
101 }
102
103 readModule(module);
104}
105
106void QQmlJSTypeDescriptionReader::readModule(UiObjectDefinition *ast)
107{
108 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
109 UiObjectMember *member = it->member;
110 auto *component = cast<UiObjectDefinition *>(member);
111
112 auto *script = cast<UiScriptBinding *>(member);
113 if (script && (toString(script->qualifiedId) == QStringLiteral("dependencies"))) {
114 readDependencies(script);
115 continue;
116 }
117
119 if (component)
120 typeName = toString(component->qualifiedTypeNameId);
121
122 if (!component || typeName != QLatin1String("Component")) {
123 continue;
124 }
125
126 if (typeName == QLatin1String("Component"))
127 readComponent(component);
128 }
129}
130
131void QQmlJSTypeDescriptionReader::addError(const SourceLocation &loc, const QString &message)
132{
133 m_errorMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
134 QDir::toNativeSeparators(m_fileName),
137 message);
138}
139
140void QQmlJSTypeDescriptionReader::addWarning(const SourceLocation &loc, const QString &message)
141{
142 m_warningMessage += QString::fromLatin1("%1:%2:%3: %4\n").arg(
143 QDir::toNativeSeparators(m_fileName),
146 message);
147}
148
149void QQmlJSTypeDescriptionReader::readDependencies(UiScriptBinding *ast)
150{
151 auto *stmt = cast<ExpressionStatement*>(ast->statement);
152 if (!stmt) {
153 addError(ast->statement->firstSourceLocation(), tr("Expected dependency definitions"));
154 return;
155 }
156 auto *exp = cast<ArrayPattern *>(stmt->expression);
157 if (!exp) {
158 addError(stmt->expression->firstSourceLocation(), tr("Expected dependency definitions"));
159 return;
160 }
161 for (PatternElementList *l = exp->elements; l; l = l->next) {
162 auto *str = cast<StringLiteral *>(l->element->initializer);
163 *m_dependencies << str->value.toString();
164 }
165}
166
167void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
168{
169 m_currentCtorIndex = 0;
171 QList<QQmlJSScope::Export> exports;
172
173 UiScriptBinding *metaObjectRevisions = nullptr;
174 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
175 UiObjectMember *member = it->member;
176 auto *component = cast<UiObjectDefinition *>(member);
177 auto *script = cast<UiScriptBinding *>(member);
178 if (component) {
179 QString name = toString(component->qualifiedTypeNameId);
180 if (name == QLatin1String("Property"))
181 readProperty(component, scope);
182 else if (name == QLatin1String("Method") || name == QLatin1String("Signal"))
183 readSignalOrMethod(component, name == QLatin1String("Method"), scope);
184 else if (name == QLatin1String("Enum"))
185 readEnum(component, scope);
186 else
187 addWarning(component->firstSourceLocation(),
188 tr("Expected only Property, Method, Signal and Enum object definitions, "
189 "not \"%1\".").arg(name));
190 } else if (script) {
191 QString name = toString(script->qualifiedId);
192 if (name == QLatin1String("file")) {
193 scope->setFilePath(readStringBinding(script));
194 } else if (name == QLatin1String("name")) {
195 scope->setInternalName(readStringBinding(script));
196 } else if (name == QLatin1String("prototype")) {
197 scope->setBaseTypeName(readStringBinding(script));
198 } else if (name == QLatin1String("defaultProperty")) {
199 scope->setOwnDefaultPropertyName(readStringBinding(script));
200 } else if (name == QLatin1String("parentProperty")) {
201 scope->setOwnParentPropertyName(readStringBinding(script));
202 } else if (name == QLatin1String("exports")) {
203 exports = readExports(script);
204 } else if (name == QLatin1String("aliases")) {
205 readAliases(script, scope);
206 } else if (name == QLatin1String("interfaces")) {
207 readInterfaces(script, scope);
208 } else if (name == QLatin1String("exportMetaObjectRevisions")) {
209 metaObjectRevisions = script;
210 } else if (name == QLatin1String("attachedType")) {
211 scope->setOwnAttachedTypeName(readStringBinding(script));
212 } else if (name == QLatin1String("valueType")) {
213 scope->setValueTypeName(readStringBinding(script));
214 } else if (name == QLatin1String("isSingleton")) {
215 scope->setIsSingleton(readBoolBinding(script));
216 } else if (name == QLatin1String("isCreatable")) {
217 scope->setCreatableFlag(readBoolBinding(script));
218 } else if (name == QLatin1String("isStructured")) {
219 scope->setStructuredFlag(readBoolBinding(script));
220 } else if (name == QLatin1String("isComposite")) {
221 scope->setIsComposite(readBoolBinding(script));
222 } else if (name == QLatin1String("hasCustomParser")) {
223 scope->setHasCustomParser(readBoolBinding(script));
224 } else if (name == QLatin1String("accessSemantics")) {
225 const QString semantics = readStringBinding(script);
226 if (semantics == QLatin1String("reference")) {
227 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Reference);
228 } else if (semantics == QLatin1String("value")) {
229 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Value);
230 } else if (semantics == QLatin1String("none")) {
231 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::None);
232 } else if (semantics == QLatin1String("sequence")) {
233 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
234 } else {
235 addWarning(script->firstSourceLocation(),
236 tr("Unknown access semantics \"%1\".").arg(semantics));
237 }
238 } else if (name == QLatin1String("extension")) {
239 scope->setExtensionTypeName(readStringBinding(script));
240 } else if (name == QLatin1String("extensionIsJavaScript")) {
241 scope->setExtensionIsJavaScript(readBoolBinding(script));
242 } else if (name == QLatin1String("extensionIsNamespace")) {
243 scope->setExtensionIsNamespace(readBoolBinding(script));
244 } else if (name == QLatin1String("deferredNames")) {
245 readDeferredNames(script, scope);
246 } else if (name == QLatin1String("immediateNames")) {
247 readImmediateNames(script, scope);
248 } else {
249 addWarning(script->firstSourceLocation(),
250 tr("Expected only name, prototype, defaultProperty, attachedType, "
251 "valueType, exports, interfaces, isSingleton, isCreatable, "
252 "isStructured, isComposite, hasCustomParser, aliases, "
253 "exportMetaObjectRevisions, deferredNames, and immediateNames "
254 "in script bindings, not \"%1\".")
255 .arg(name));
256 }
257 } else {
258 addWarning(member->firstSourceLocation(),
259 tr("Expected only script bindings and object definitions."));
260 }
261 }
262
263 if (scope->internalName().isEmpty()) {
264 addError(ast->firstSourceLocation(), tr("Component definition is missing a name binding."));
265 return;
266 }
267
268 if (metaObjectRevisions)
269 checkMetaObjectRevisions(metaObjectRevisions, &exports);
270 m_objects->append({scope, exports});
271}
272
273void QQmlJSTypeDescriptionReader::readSignalOrMethod(
274 UiObjectDefinition *ast, bool isMethod, const QQmlJSScope::Ptr &scope)
275{
276 QQmlJSMetaMethod metaMethod;
277 // ### confusion between Method and Slot. Method should be removed.
278 if (isMethod)
279 metaMethod.setMethodType(QQmlJSMetaMethodType::Slot);
280 else
281 metaMethod.setMethodType(QQmlJSMetaMethodType::Signal);
282
283 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
284 UiObjectMember *member = it->member;
285 auto *component = cast<UiObjectDefinition *>(member);
286 auto *script = cast<UiScriptBinding *>(member);
287 if (component) {
288 QString name = toString(component->qualifiedTypeNameId);
289 if (name == QLatin1String("Parameter")) {
290 readParameter(component, &metaMethod);
291 } else {
292 addWarning(component->firstSourceLocation(),
293 tr("Expected only Parameter in object definitions."));
294 }
295 } else if (script) {
296 QString name = toString(script->qualifiedId);
297 if (name == QLatin1String("name")) {
298 metaMethod.setMethodName(readStringBinding(script));
299 } else if (name == QLatin1String("type")) {
300 metaMethod.setReturnTypeName(readStringBinding(script));
301 } else if (name == QLatin1String("revision")) {
302 metaMethod.setRevision(readIntBinding(script));
303 } else if (name == QLatin1String("isCloned")) {
304 metaMethod.setIsCloned(readBoolBinding(script));
305 } else if (name == QLatin1String("isConstructor")) {
306 // The constructors in the moc json output are ordered the same
307 // way as the ones in the metaobject. qmltyperegistrar moves them into
308 // the same list as the other members, but maintains their order.
309 if (readBoolBinding(script)) {
310 metaMethod.setIsConstructor(true);
311 metaMethod.setConstructorIndex(
312 QQmlJSMetaMethod::RelativeFunctionIndex(m_currentCtorIndex++));
313 }
314 } else if (name == QLatin1String("isJavaScriptFunction")) {
315 metaMethod.setIsJavaScriptFunction(readBoolBinding(script));
316 } else if (name == QLatin1String("isList")) {
317 auto metaReturnType = metaMethod.returnValue();
318 metaReturnType.setIsList(readBoolBinding(script));
319 metaMethod.setReturnValue(metaReturnType);
320 } else if (name == QLatin1String("isPointer")) {
321 // TODO: We don't need this information. We can probably drop all isPointer members
322 // once we make sure that the type information is always complete. The
323 // description of the type being referenced has access semantics after all.
324 auto metaReturnType = metaMethod.returnValue();
325 metaReturnType.setIsPointer(readBoolBinding(script));
326 metaMethod.setReturnValue(metaReturnType);
327 } else if (name == QLatin1String("isConstant")) {
328 auto metaReturnType = metaMethod.returnValue();
329 metaReturnType.setTypeQualifier(readBoolBinding(script)
331 : QQmlJSMetaParameter::NonConst);
332 metaMethod.setReturnValue(metaReturnType);
333 } else {
334 addWarning(script->firstSourceLocation(),
335 tr("Expected only name, type, revision, isPointer, isConstant, "
336 "isList, isCloned, isConstructor, and isJavaScriptFunction "
337 "in script bindings."));
338 }
339 } else {
340 addWarning(member->firstSourceLocation(),
341 tr("Expected only script bindings and object definitions."));
342 }
343 }
344
345 if (metaMethod.methodName().isEmpty()) {
346 addError(ast->firstSourceLocation(),
347 tr("Method or signal is missing a name script binding."));
348 return;
349 }
350
351 scope->addOwnMethod(metaMethod);
352}
353
354void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQmlJSScope::Ptr &scope)
355{
357 property.setIsWritable(true); // default is writable
358 bool isRequired = false;
359
360 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
361 UiObjectMember *member = it->member;
362 auto *script = cast<UiScriptBinding *>(member);
363 if (!script) {
364 addWarning(member->firstSourceLocation(), tr("Expected script binding."));
365 continue;
366 }
367
368 QString id = toString(script->qualifiedId);
369 if (id == QLatin1String("name")) {
370 property.setPropertyName(readStringBinding(script));
371 } else if (id == QLatin1String("type")) {
372 property.setTypeName(readStringBinding(script));
373 } else if (id == QLatin1String("isPointer")) {
374 property.setIsPointer(readBoolBinding(script));
375 } else if (id == QLatin1String("isReadonly")) {
376 property.setIsWritable(!readBoolBinding(script));
377 } else if (id == QLatin1String("isRequired")) {
378 isRequired = readBoolBinding(script);
379 } else if (id == QLatin1String("isList")) {
380 property.setIsList(readBoolBinding(script));
381 } else if (id == QLatin1String("isFinal")) {
382 property.setIsFinal(readBoolBinding(script));
383 } else if (id == QLatin1String("isConstant")) {
384 property.setIsConstant(readBoolBinding(script));
385 } else if (id == QLatin1String("revision")) {
386 property.setRevision(readIntBinding(script));
387 } else if (id == QLatin1String("bindable")) {
388 property.setBindable(readStringBinding(script));
389 } else if (id == QLatin1String("read")) {
390 property.setRead(readStringBinding(script));
391 } else if (id == QLatin1String("write")) {
392 property.setWrite(readStringBinding(script));
393 } else if (id == QLatin1String("reset")) {
394 property.setReset(readStringBinding(script));
395 } else if (id == QLatin1String("notify")) {
396 property.setNotify(readStringBinding(script));
397 } else if (id == QLatin1String("index")) {
398 property.setIndex(readIntBinding(script));
399 } else if (id == QLatin1String("privateClass")) {
400 property.setPrivateClass(readStringBinding(script));
401 } else {
402 addWarning(script->firstSourceLocation(),
403 tr("Expected only type, name, revision, isPointer, isReadonly, isRequired, "
404 "isFinal, isList, bindable, read, write, reset, notify, index, and "
405 "privateClass and script bindings."));
406 }
407 }
408
409 if (property.propertyName().isEmpty()) {
410 addError(ast->firstSourceLocation(),
411 tr("Property object is missing a name script binding."));
412 return;
413 }
414
415 scope->addOwnProperty(property);
416 if (isRequired)
417 scope->setPropertyLocallyRequired(property.propertyName(), true);
418}
419
420void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast, const QQmlJSScope::Ptr &scope)
421{
422 QQmlJSMetaEnum metaEnum;
423
424 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
425 UiObjectMember *member = it->member;
426 auto *script = cast<UiScriptBinding *>(member);
427 if (!script) {
428 addWarning(member->firstSourceLocation(), tr("Expected script binding."));
429 continue;
430 }
431
432 QString name = toString(script->qualifiedId);
433 if (name == QLatin1String("name")) {
434 metaEnum.setName(readStringBinding(script));
435 } else if (name == QLatin1String("alias")) {
436 metaEnum.setAlias(readStringBinding(script));
437 } else if (name == QLatin1String("isFlag")) {
438 metaEnum.setIsFlag(readBoolBinding(script));
439 } else if (name == QLatin1String("values")) {
440 readEnumValues(script, &metaEnum);
441 } else if (name == QLatin1String("isScoped")) {
442 metaEnum.setIsScoped(readBoolBinding(script));
443 } else if (name == QLatin1String("type")) {
444 metaEnum.setTypeName(readStringBinding(script));
445 } else {
446 addWarning(script->firstSourceLocation(),
447 tr("Expected only name, alias, isFlag, values, isScoped, or type."));
448 }
449 }
450
451 scope->addOwnEnumeration(metaEnum);
452}
453
454void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSMetaMethod *metaMethod)
455{
458 bool isConstant = false;
459 bool isPointer = false;
460 bool isList = false;
461
462 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
463 UiObjectMember *member = it->member;
464 auto *script = cast<UiScriptBinding *>(member);
465 if (!script) {
466 addWarning(member->firstSourceLocation(), tr("Expected script binding."));
467 continue;
468 }
469
470 const QString id = toString(script->qualifiedId);
471 if (id == QLatin1String("name")) {
472 name = readStringBinding(script);
473 } else if (id == QLatin1String("type")) {
474 type = readStringBinding(script);
475 } else if (id == QLatin1String("isPointer")) {
476 isPointer = readBoolBinding(script);
477 } else if (id == QLatin1String("isConstant")) {
478 isConstant = readBoolBinding(script);
479 } else if (id == QLatin1String("isReadonly")) {
480 // ### unhandled
481 } else if (id == QLatin1String("isList")) {
482 isList = readBoolBinding(script);
483 } else {
484 addWarning(script->firstSourceLocation(),
485 tr("Expected only name, type, isPointer, isConstant, isReadonly, "
486 "or IsList script bindings."));
487 }
488 }
489
491 p.setTypeQualifier(isConstant ? QQmlJSMetaParameter::Const : QQmlJSMetaParameter::NonConst);
492 p.setIsPointer(isPointer);
493 p.setIsList(isList);
494 metaMethod->addParameter(std::move(p));
495}
496
497QString QQmlJSTypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
498{
499 Q_ASSERT(ast);
500
501 if (!ast->statement) {
502 addError(ast->colonToken, tr("Expected string after colon."));
503 return QString();
504 }
505
506 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
507 if (!expStmt) {
508 addError(ast->statement->firstSourceLocation(), tr("Expected string after colon."));
509 return QString();
510 }
511
512 auto *stringLit = cast<StringLiteral *>(expStmt->expression);
513 if (!stringLit) {
514 addError(expStmt->firstSourceLocation(), tr("Expected string after colon."));
515 return QString();
516 }
517
518 return stringLit->value.toString();
519}
520
521bool QQmlJSTypeDescriptionReader::readBoolBinding(UiScriptBinding *ast)
522{
523 Q_ASSERT(ast);
524
525 if (!ast->statement) {
526 addError(ast->colonToken, tr("Expected boolean after colon."));
527 return false;
528 }
529
530 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
531 if (!expStmt) {
532 addError(ast->statement->firstSourceLocation(), tr("Expected boolean after colon."));
533 return false;
534 }
535
536 auto *trueLit = cast<TrueLiteral *>(expStmt->expression);
537 auto *falseLit = cast<FalseLiteral *>(expStmt->expression);
538 if (!trueLit && !falseLit) {
539 addError(expStmt->firstSourceLocation(), tr("Expected true or false after colon."));
540 return false;
541 }
542
543 return trueLit;
544}
545
546double QQmlJSTypeDescriptionReader::readNumericBinding(UiScriptBinding *ast)
547{
548 Q_ASSERT(ast);
549
550 if (!ast->statement) {
551 addError(ast->colonToken, tr("Expected numeric literal after colon."));
552 return 0;
553 }
554
555 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
556 if (!expStmt) {
557 addError(ast->statement->firstSourceLocation(),
558 tr("Expected numeric literal after colon."));
559 return 0;
560 }
561
562 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
563 if (!numericLit) {
564 addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
565 return 0;
566 }
567
568 return numericLit->value;
569}
570
571static QTypeRevision parseVersion(const QString &versionString)
572{
573 const int dotIdx = versionString.indexOf(QLatin1Char('.'));
574 if (dotIdx == -1)
575 return QTypeRevision();
576 bool ok = false;
577 const int maybeMajor = QStringView{versionString}.left(dotIdx).toInt(&ok);
578 if (!ok)
579 return QTypeRevision();
580 const int maybeMinor = QStringView{versionString}.mid(dotIdx + 1).toInt(&ok);
581 if (!ok)
582 return QTypeRevision();
583 return QTypeRevision::fromVersion(maybeMajor, maybeMinor);
584}
585
586QTypeRevision QQmlJSTypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast)
587{
588 QTypeRevision invalidVersion;
589
590 if (!ast || !ast->statement) {
591 addError((ast ? ast->colonToken : SourceLocation()),
592 tr("Expected numeric literal after colon."));
593 return invalidVersion;
594 }
595
596 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
597 if (!expStmt) {
598 addError(ast->statement->firstSourceLocation(),
599 tr("Expected numeric literal after colon."));
600 return invalidVersion;
601 }
602
603 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
604 if (!numericLit) {
605 addError(expStmt->firstSourceLocation(), tr("Expected numeric literal after colon."));
606 return invalidVersion;
607 }
608
609 return parseVersion(m_source.mid(numericLit->literalToken.begin(),
610 numericLit->literalToken.length));
611}
612
613int QQmlJSTypeDescriptionReader::readIntBinding(UiScriptBinding *ast)
614{
615 double v = readNumericBinding(ast);
616 int i = static_cast<int>(v);
617
618 if (i != v) {
619 addError(ast->firstSourceLocation(), tr("Expected integer after colon."));
620 return 0;
621 }
622
623 return i;
624}
625
626ArrayPattern* QQmlJSTypeDescriptionReader::getArray(UiScriptBinding *ast)
627{
628 Q_ASSERT(ast);
629
630 if (!ast->statement) {
631 addError(ast->colonToken, tr("Expected array of strings after colon."));
632 return nullptr;
633 }
634
635 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
636 if (!expStmt) {
637 addError(ast->statement->firstSourceLocation(),
638 tr("Expected array of strings after colon."));
639 return nullptr;
640 }
641
642 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
643 if (!arrayLit) {
644 addError(expStmt->firstSourceLocation(), tr("Expected array of strings after colon."));
645 return nullptr;
646 }
647
648 return arrayLit;
649}
650
651QList<QQmlJSScope::Export> QQmlJSTypeDescriptionReader::readExports(UiScriptBinding *ast)
652{
653 QList<QQmlJSScope::Export> exports;
654 auto *arrayLit = getArray(ast);
655
656 if (!arrayLit)
657 return exports;
658
659 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
660 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
661
662 if (!stringLit) {
663 addError(arrayLit->firstSourceLocation(),
664 tr("Expected array literal with only string literal members."));
665 return exports;
666 }
667
668 QString exp = stringLit->value.toString();
669 int slashIdx = exp.indexOf(QLatin1Char('/'));
670 int spaceIdx = exp.indexOf(QLatin1Char(' '));
671 const QTypeRevision version = parseVersion(exp.mid(spaceIdx + 1));
672
673 if (spaceIdx == -1 || !version.isValid()) {
674 addError(stringLit->firstSourceLocation(),
675 tr("Expected string literal to contain 'Package/Name major.minor' "
676 "or 'Name major.minor'."));
677 continue;
678 }
679 QString package;
680 if (slashIdx != -1)
681 package = exp.left(slashIdx);
682 QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
683
684 // ### relocatable exports where package is empty?
685 exports.append(QQmlJSScope::Export(package, name, version, version));
686 }
687
688 return exports;
689}
690
691void QQmlJSTypeDescriptionReader::readAliases(
693{
694 scope->setAliases(readStringList(ast));
695}
696
697void QQmlJSTypeDescriptionReader::readInterfaces(UiScriptBinding *ast, const QQmlJSScope::Ptr &scope)
698{
699 auto *arrayLit = getArray(ast);
700
701 if (!arrayLit)
702 return;
703
705
706 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
707 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
708 if (!stringLit) {
709 addError(arrayLit->firstSourceLocation(),
710 tr("Expected array literal with only string literal members."));
711 return;
712 }
713
714 list << stringLit->value.toString();
715 }
716
717 scope->setInterfaceNames(list);
718}
719
720void QQmlJSTypeDescriptionReader::checkMetaObjectRevisions(
721 UiScriptBinding *ast, QList<QQmlJSScope::Export> *exports)
722{
723 Q_ASSERT(ast);
724
725 if (!ast->statement) {
726 addError(ast->colonToken, tr("Expected array of numbers after colon."));
727 return;
728 }
729
730 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
731 if (!expStmt) {
732 addError(ast->statement->firstSourceLocation(),
733 tr("Expected array of numbers after colon."));
734 return;
735 }
736
737 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
738 if (!arrayLit) {
739 addError(expStmt->firstSourceLocation(), tr("Expected array of numbers after colon."));
740 return;
741 }
742
743 int exportIndex = 0;
744 const int exportCount = exports->size();
745 for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
746 auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
747 if (!numberLit) {
748 addError(arrayLit->firstSourceLocation(),
749 tr("Expected array literal with only number literal members."));
750 return;
751 }
752
753 if (exportIndex >= exportCount) {
754 addError(numberLit->firstSourceLocation(),
755 tr("Meta object revision without matching export."));
756 return;
757 }
758
759 const double v = numberLit->value;
760 const int metaObjectRevision = static_cast<int>(v);
761 if (metaObjectRevision != v) {
762 addError(numberLit->firstSourceLocation(), tr("Expected integer."));
763 return;
764 }
765
766 const QTypeRevision metaObjectVersion
767 = QTypeRevision::fromEncodedVersion(metaObjectRevision);
768 const QQmlJSScope::Export &entry = exports->at(exportIndex);
769 const QTypeRevision exportVersion = entry.version();
770 if (metaObjectVersion != exportVersion) {
771 addWarning(numberLit->firstSourceLocation(),
772 tr("Meta object revision and export version differ.\n"
773 "Revision %1 corresponds to version %2.%3; it should be %4.%5.")
774 .arg(metaObjectRevision)
775 .arg(metaObjectVersion.majorVersion()).arg(metaObjectVersion.minorVersion())
776 .arg(exportVersion.majorVersion()).arg(exportVersion.minorVersion()));
777 (*exports)[exportIndex] = QQmlJSScope::Export(entry.package(), entry.type(),
778 exportVersion, metaObjectVersion);
779 }
780 }
781}
782
783QStringList QQmlJSTypeDescriptionReader::readStringList(UiScriptBinding *ast)
784{
785 auto *arrayLit = getArray(ast);
786 if (!arrayLit)
787 return {};
788
790
791 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
792 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
793 if (!stringLit) {
794 addError(arrayLit->firstSourceLocation(),
795 tr("Expected array literal with only string literal members."));
796 return {};
797 }
798
799 list << stringLit->value.toString();
800 }
801
802 return list;
803}
804
805void QQmlJSTypeDescriptionReader::readDeferredNames(UiScriptBinding *ast,
806 const QQmlJSScope::Ptr &scope)
807{
808 scope->setOwnDeferredNames(readStringList(ast));
809}
810
811void QQmlJSTypeDescriptionReader::readImmediateNames(UiScriptBinding *ast,
812 const QQmlJSScope::Ptr &scope)
813{
814 scope->setOwnImmediateNames(readStringList(ast));
815}
816
817void QQmlJSTypeDescriptionReader::readEnumValues(UiScriptBinding *ast, QQmlJSMetaEnum *metaEnum)
818{
819 if (!ast)
820 return;
821 if (!ast->statement) {
822 addError(ast->colonToken, tr("Expected object literal after colon."));
823 return;
824 }
825
826 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
827 if (!expStmt) {
828 addError(ast->statement->firstSourceLocation(), tr("Expected expression after colon."));
829 return;
830 }
831
832 if (auto *objectLit = cast<ObjectPattern *>(expStmt->expression)) {
833 int currentValue = -1;
834 for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
835 if (PatternProperty *assignement = it->property) {
836 if (auto *name = cast<StringLiteralPropertyName *>(assignement->name)) {
837 metaEnum->addKey(name->id.toString());
838
839 if (auto *value = AST::cast<NumericLiteral *>(assignement->initializer)) {
840 currentValue = int(value->value);
841 } else if (auto *minus = AST::cast<UnaryMinusExpression *>(
842 assignement->initializer)) {
843 if (auto *value = AST::cast<NumericLiteral *>(minus->expression))
844 currentValue = -int(value->value);
845 else
846 ++currentValue;
847 } else {
848 ++currentValue;
849 }
850
851 metaEnum->addValue(currentValue);
852 continue;
853 }
854 }
855 addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
856 }
857 } else if (auto *arrayLit = cast<ArrayPattern *>(expStmt->expression)) {
858 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
859 if (PatternElement *element = it->element) {
860 if (auto *name = cast<StringLiteral *>(element->initializer)) {
861 metaEnum->addKey(name->value.toString());
862 continue;
863 }
864 }
865 addError(it->firstSourceLocation(), tr("Expected strings as enum keys."));
866 }
867 } else {
868 addError(ast->statement->firstSourceLocation(),
869 tr("Expected either array or object literal as enum definition."));
870 }
871}
872
void parse(QIODevice &input, const QString &name)
Definition parser.cpp:536
\inmodule QtCore
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
T value(qsizetype i) const
Definition qlist.h:664
QQmlJSMetaReturnType returnValue() const
void setIsConstructor(bool isConstructor)
void setIsJavaScriptFunction(bool isJavaScriptFunction)
QString methodName() const
void setMethodName(const QString &name)
void setMethodType(MethodType methodType)
void setReturnTypeName(const QString &typeName)
void setReturnValue(const QQmlJSMetaReturnType returnValue)
void setIsCloned(bool isCloned)
void setConstructorIndex(RelativeFunctionIndex index)
void addParameter(const QQmlJSMetaParameter &p)
void setIsPointer(bool isPointer)
void setIsList(bool isList)
void setTypeQualifier(Constness typeQualifier)
void setIsComposite(bool v)
void setOwnDeferredNames(const QStringList &names)
QQmlJS::Export Export
void setExtensionTypeName(const QString &name)
void setExtensionIsJavaScript(bool v)
void setInterfaceNames(const QStringList &interfaces)
static QQmlJSScope::Ptr create()
void setStructuredFlag(bool v)
void setAccessSemantics(AccessSemantics semantics)
void setOwnParentPropertyName(const QString &name)
void setOwnAttachedTypeName(const QString &name)
void setInternalName(const QString &internalName)
QString internalName() const
void setHasCustomParser(bool v)
void setIsSingleton(bool v)
void addOwnProperty(const QQmlJSMetaProperty &prop)
void setExtensionIsNamespace(bool v)
void setAliases(const QStringList &aliases)
void setBaseTypeName(const QString &baseTypeName)
void setValueTypeName(const QString &name)
void setOwnImmediateNames(const QStringList &names)
void addOwnEnumeration(const QQmlJSMetaEnum &enumeration)
void addOwnMethod(const QQmlJSMetaMethod &method)
void setCreatableFlag(bool v)
void setOwnDefaultPropertyName(const QString &name)
void setFilePath(const QString &file)
void setPropertyLocallyRequired(const QString &name, bool isRequired)
bool operator()(QList< QQmlJSExportedScope > *objects, QStringList *dependencies)
virtual SourceLocation firstSourceLocation() const =0
SourceLocation firstSourceLocation() const override
UiObjectInitializer * initializer
SourceLocation firstSourceLocation() const override=0
UiHeaderItemList * headers
UiObjectMemberList * members
SourceLocation firstSourceLocation() const override
void setCode(const QString &code, int lineno, bool qmlMode=true, CodeContinuation codeContinuation=CodeContinuation::Reset)
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition qstring.h:731
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
Produces a QTypeRevision from the given majorVersion and minorVersion, both of which need to be a val...
constexpr bool isValid() const
Returns true if the major version or the minor version is known, otherwise false.
static constexpr QTypeRevision fromEncodedVersion(Integer value)
Produces a QTypeRevision from the given value.
QString str
[2]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const char * typeName
GLsizei const GLfloat * v
[13]
GLenum type
GLuint GLsizei const GLchar * message
GLuint name
GLuint entry
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
static qreal component(const QPointF &point, unsigned int i)
static QTypeRevision parseVersion(const QString &str)
static QTypeRevision parseVersion(const QString &versionString)
QString toString(const UiQualifiedId *qualifiedId, QChar delimiter=QLatin1Char('.'))
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define tr(X)
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
char * toString(const MyType &t)
[31]
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18