7#include <QtQml/private/qqmljsparser_p.h>
8#include <QtQml/private/qqmljslexer_p.h>
9#include <QtQml/private/qqmljsengine_p.h>
11#include <QtCore/qdir.h>
12#include <QtCore/qstring.h>
13#include <QtCore/qtyperevision.h>
17using namespace QQmlJS;
18using namespace QQmlJS::AST;
19using namespace Qt::StringLiterals;
21QString toString(
const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char(
'.'))
25 for (
const UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
26 if (iter != qualifiedId)
35bool QQmlJSTypeDescriptionReader::operator()(
36 QList<QQmlJSExportedScope> *objects, QStringList *dependencies)
41 Parser parser(&engine);
43 lexer.setCode(m_source, 1,
true);
45 if (!parser.parse()) {
46 m_errorMessage = QString::fromLatin1(
"%1:%2: %3").arg(
47 QString::number(parser.errorLineNumber()),
48 QString::number(parser.errorColumnNumber()),
49 parser.errorMessage());
54 m_dependencies = dependencies;
55 readDocument(parser.ast());
57 return m_errorMessage.isEmpty();
60void QQmlJSTypeDescriptionReader::readDocument(UiProgram *ast)
63 addError(SourceLocation(), tr(
"Could not parse document."));
67 if (!ast->headers || ast->headers->next || !cast<UiImport *>(ast->headers->headerItem)) {
68 addError(SourceLocation(), tr(
"Expected a single import."));
72 auto *import = cast<UiImport *>(ast->headers->headerItem);
73 if (toString(import->importUri) != QLatin1String(
"QtQuick.tooling")) {
74 addError(import->importToken, tr(
"Expected import of QtQuick.tooling."));
78 if (!import->version) {
79 addError(import->firstSourceLocation(), tr(
"Import statement without version."));
83 if (import->version->version.majorVersion() != 1) {
84 addError(import->version->firstSourceLocation(),
85 tr(
"Major version different from 1 not supported."));
89 if (!ast->members || !ast->members->member || ast->members->next) {
90 addError(SourceLocation(), tr(
"Expected document to contain a single object definition."));
94 auto *module = cast<UiObjectDefinition *>(ast->members->member);
96 addError(SourceLocation(), tr(
"Expected document to contain a single object definition."));
100 if (toString(module->qualifiedTypeNameId) != QLatin1String(
"Module")) {
101 addError(SourceLocation(), tr(
"Expected document to contain a Module {} member."));
108void QQmlJSTypeDescriptionReader::readModule(UiObjectDefinition *ast)
110 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
111 UiObjectMember *member = it->member;
112 auto *component = cast<UiObjectDefinition *>(member);
114 auto *script = cast<UiScriptBinding *>(member);
115 if (script && (toString(script->qualifiedId) == QStringLiteral(
"dependencies"))) {
116 readDependencies(script);
122 typeName = toString(component->qualifiedTypeNameId);
124 if (!component || typeName != QLatin1String(
"Component")) {
128 if (typeName == QLatin1String(
"Component"))
129 readComponent(component);
133void QQmlJSTypeDescriptionReader::addError(
const SourceLocation &loc,
const QString &message)
135 m_errorMessage += QString::fromLatin1(
"%1:%2:%3: %4\n").arg(
136 QDir::toNativeSeparators(m_fileName),
137 QString::number(loc.startLine),
138 QString::number(loc.startColumn),
142void QQmlJSTypeDescriptionReader::addWarning(
const SourceLocation &loc,
const QString &message)
144 m_warningMessage += QString::fromLatin1(
"%1:%2:%3: %4\n").arg(
145 QDir::toNativeSeparators(m_fileName),
146 QString::number(loc.startLine),
147 QString::number(loc.startColumn),
151void QQmlJSTypeDescriptionReader::readDependencies(UiScriptBinding *ast)
153 auto *stmt = cast<ExpressionStatement*>(ast->statement);
155 addError(ast->statement->firstSourceLocation(), tr(
"Expected dependency definitions"));
158 auto *exp = cast<ArrayPattern *>(stmt->expression);
160 addError(stmt->expression->firstSourceLocation(), tr(
"Expected dependency definitions"));
163 for (PatternElementList *l = exp->elements; l; l = l->next) {
164 auto *str = cast<StringLiteral *>(l->element->initializer);
165 *m_dependencies << str->value.toString();
169void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
171 m_currentCtorIndex = 0;
172 m_currentMethodIndex = 0;
173 QQmlJSScope::Ptr scope = QQmlJSScope::create();
174 QList<QQmlJSScope::Export> exports;
176 UiScriptBinding *metaObjectRevisions =
nullptr;
177 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
178 UiObjectMember *member = it->member;
179 auto *component = cast<UiObjectDefinition *>(member);
180 auto *script = cast<UiScriptBinding *>(member);
182 QString name = toString(component->qualifiedTypeNameId);
183 if (name == QLatin1String(
"Property"))
184 readProperty(component, scope);
185 else if (name == QLatin1String(
"Method") || name == QLatin1String(
"Signal"))
186 readSignalOrMethod(component, name == QLatin1String(
"Method"), scope);
187 else if (name == QLatin1String(
"Enum"))
188 readEnum(component, scope);
190 addWarning(component->firstSourceLocation(),
191 tr(
"Expected only Property, Method, Signal and Enum object definitions, "
192 "not \"%1\".").arg(name));
194 QString name = toString(script->qualifiedId);
195 if (name == QLatin1String(
"file")) {
196 scope->setFilePath(readStringBinding(script));
197 }
else if (name == QLatin1String(
"lineNumber")) {
198 scope->setLineNumber(readNumericBinding(script));
199 }
else if (name == QLatin1String(
"name")) {
200 scope->setInternalName(readStringBinding(script));
201 }
else if (name == QLatin1String(
"prototype")) {
202 scope->setBaseTypeName(readStringBinding(script));
203 }
else if (name == QLatin1String(
"defaultProperty")) {
204 scope->setOwnDefaultPropertyName(readStringBinding(script));
205 }
else if (name == QLatin1String(
"parentProperty")) {
206 scope->setOwnParentPropertyName(readStringBinding(script));
207 }
else if (name == QLatin1String(
"exports")) {
208 exports = readExports(script);
209 }
else if (name == QLatin1String(
"aliases")) {
210 readAliases(script, scope);
211 }
else if (name == QLatin1String(
"interfaces")) {
212 readInterfaces(script, scope);
213 }
else if (name == QLatin1String(
"exportMetaObjectRevisions")) {
214 metaObjectRevisions = script;
215 }
else if (name == QLatin1String(
"attachedType")) {
216 scope->setOwnAttachedTypeName(readStringBinding(script));
217 }
else if (name == QLatin1String(
"valueType")) {
218 scope->setElementTypeName(readStringBinding(script));
219 }
else if (name == QLatin1String(
"isSingleton")) {
220 scope->setIsSingleton(readBoolBinding(script));
221 }
else if (name == QLatin1String(
"isCreatable")) {
222 scope->setCreatableFlag(readBoolBinding(script));
223 }
else if (name == QLatin1String(
"isStructured")) {
224 scope->setStructuredFlag(readBoolBinding(script));
225 }
else if (name == QLatin1String(
"isComposite")) {
226 scope->setIsComposite(readBoolBinding(script));
227 }
else if (name == QLatin1String(
"hasCustomParser")) {
228 scope->setHasCustomParser(readBoolBinding(script));
229 }
else if (name == QLatin1String(
"enforcesScopedEnums")) {
230 scope->setEnforcesScopedEnumsFlag(readBoolBinding(script));
231 }
else if (name == QLatin1String(
"accessSemantics")) {
232 const QString semantics = readStringBinding(script);
233 if (semantics == QLatin1String(
"reference")) {
234 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Reference);
235 }
else if (semantics == QLatin1String(
"value")) {
236 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Value);
237 }
else if (semantics == QLatin1String(
"none")) {
238 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::None);
239 }
else if (semantics == QLatin1String(
"sequence")) {
240 scope->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
242 addWarning(script->firstSourceLocation(),
243 tr(
"Unknown access semantics \"%1\".").arg(semantics));
245 }
else if (name == QLatin1String(
"extension")) {
246 scope->setExtensionTypeName(readStringBinding(script));
247 }
else if (name == QLatin1String(
"extensionIsJavaScript")) {
248 scope->setExtensionIsJavaScript(readBoolBinding(script));
249 }
else if (name == QLatin1String(
"extensionIsNamespace")) {
250 scope->setExtensionIsNamespace(readBoolBinding(script));
251 }
else if (name == QLatin1String(
"deferredNames")) {
252 readDeferredNames(script, scope);
253 }
else if (name == QLatin1String(
"immediateNames")) {
254 readImmediateNames(script, scope);
255 }
else if (name == QLatin1String(
"isJavaScriptBuiltin")) {
256 scope->setIsJavaScriptBuiltin(readBoolBinding(script));
258 addWarning(script->firstSourceLocation(),
259 tr(
"Expected only lineNumber, name, prototype, defaultProperty, "
261 "valueType, exports, interfaces, isSingleton, isCreatable, "
262 "isStructured, isComposite, hasCustomParser, enforcesScopedEnums, "
263 "aliases, exportMetaObjectRevisions, deferredNames, and "
264 "immediateNames in script bindings, not \"%1\".")
268 addWarning(member->firstSourceLocation(),
269 tr(
"Expected only script bindings and object definitions."));
273 if (scope->internalName().isEmpty()) {
274 addError(ast->firstSourceLocation(), tr(
"Component definition is missing a name binding."));
278 if (metaObjectRevisions)
279 checkMetaObjectRevisions(metaObjectRevisions, &exports);
280 m_objects->append({scope, exports});
283void QQmlJSTypeDescriptionReader::readSignalOrMethod(
284 UiObjectDefinition *ast,
bool isMethod,
const QQmlJSScope::Ptr &scope)
286 QQmlJSMetaMethod metaMethod;
289 metaMethod.setMethodType(QQmlJSMetaMethodType::Slot);
291 metaMethod.setMethodType(QQmlJSMetaMethodType::Signal);
293 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
294 UiObjectMember *member = it->member;
295 auto *component = cast<UiObjectDefinition *>(member);
296 auto *script = cast<UiScriptBinding *>(member);
298 QString name = toString(component->qualifiedTypeNameId);
299 if (name == QLatin1String(
"Parameter")) {
300 readParameter(component, &metaMethod);
302 addWarning(component->firstSourceLocation(),
303 tr(
"Expected only Parameter in object definitions."));
306 QString name = toString(script->qualifiedId);
307 if (name == QLatin1String(
"name")) {
308 metaMethod.setMethodName(readStringBinding(script));
309 }
else if (name == QLatin1String(
"lineNumber")) {
310 metaMethod.setSourceLocation(
311 SourceLocation::fromQSizeType(0, 0, readIntBinding(script), 1));
312 }
else if (name == QLatin1String(
"type")) {
313 metaMethod.setReturnTypeName(readStringBinding(script));
314 }
else if (name == QLatin1String(
"revision")) {
315 metaMethod.setRevision(readIntBinding(script));
316 }
else if (name == QLatin1String(
"isCloned")) {
317 metaMethod.setIsCloned(readBoolBinding(script));
318 }
else if (name == QLatin1String(
"isConstructor")) {
322 if (readBoolBinding(script)) {
323 metaMethod.setIsConstructor(
true);
324 metaMethod.setConstructorIndex(
325 QQmlJSMetaMethod::RelativeFunctionIndex(m_currentCtorIndex++));
327 }
else if (name == QLatin1String(
"isJavaScriptFunction")) {
328 metaMethod.setIsJavaScriptFunction(readBoolBinding(script));
329 }
else if (name == QLatin1String(
"isList")) {
330 auto metaReturnType = metaMethod.returnValue();
331 metaReturnType.setIsList(readBoolBinding(script));
332 metaMethod.setReturnValue(metaReturnType);
333 }
else if (name == QLatin1String(
"isPointer")) {
337 auto metaReturnType = metaMethod.returnValue();
338 metaReturnType.setIsPointer(readBoolBinding(script));
339 metaMethod.setReturnValue(metaReturnType);
340 }
else if (name == QLatin1String(
"isTypeConstant")
341 || name == QLatin1String(
"isConstant")) {
343 auto metaReturnType = metaMethod.returnValue();
344 metaReturnType.setTypeQualifier(readBoolBinding(script)
345 ? QQmlJSMetaParameter::Const
346 : QQmlJSMetaParameter::NonConst);
347 metaMethod.setReturnValue(metaReturnType);
348 }
else if (name == QLatin1String(
"isMethodConstant")) {
349 metaMethod.setIsConst(readBoolBinding(script));
351 addWarning(script->firstSourceLocation(),
352 tr(
"Expected only name, lineNumber, type, revision, isPointer, "
354 "isList, isCloned, isConstructor, isMethodConstant, and "
355 "isJavaScriptFunction in script bindings."));
358 addWarning(member->firstSourceLocation(),
359 tr(
"Expected only script bindings and object definitions."));
363 if (metaMethod.methodName().isEmpty()) {
364 addError(ast->firstSourceLocation(),
365 tr(
"Method or signal is missing a name script binding."));
372 if (!metaMethod.isConstructor())
373 metaMethod.setMethodIndex(QQmlJSMetaMethod::RelativeFunctionIndex(m_currentMethodIndex++));
375 if (metaMethod.returnTypeName().isEmpty())
376 metaMethod.setReturnTypeName(QLatin1String(
"void"));
378 scope->addOwnMethod(metaMethod);
381void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast,
const QQmlJSScope::Ptr &scope)
383 QQmlJSMetaProperty property;
384 property.setIsWritable(
true);
385 bool isRequired =
false;
387 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
388 UiObjectMember *member = it->member;
389 auto *script = cast<UiScriptBinding *>(member);
391 addWarning(member->firstSourceLocation(), tr(
"Expected script binding."));
395 QString id = toString(script->qualifiedId);
396 if (id == QLatin1String(
"name")) {
397 property.setPropertyName(readStringBinding(script));
398 }
else if (id == QLatin1String(
"lineNumber")) {
399 property.setSourceLocation(
400 SourceLocation::fromQSizeType(0, 0, readIntBinding(script), 1));
401 }
else if (id == QLatin1String(
"type")) {
402 property.setTypeName(readStringBinding(script));
403 }
else if (id == QLatin1String(
"isPointer")) {
404 property.setIsPointer(readBoolBinding(script));
405 }
else if (id == QLatin1String(
"isReadonly")) {
406 property.setIsWritable(!readBoolBinding(script));
407 }
else if (id == QLatin1String(
"isRequired")) {
408 isRequired = readBoolBinding(script);
409 }
else if (id == QLatin1String(
"isList")) {
410 property.setIsList(readBoolBinding(script));
411 }
else if (id == QLatin1String(
"isFinal")) {
412 property.setIsFinal(readBoolBinding(script));
413 }
else if (id == QLatin1String(
"isVirtual")) {
414 property.setIsVirtual(readBoolBinding(script));
415 }
else if (id == QLatin1String(
"isOverride")) {
416 property.setIsOverride(readBoolBinding(script));
417 }
else if (id == QLatin1String(
"isTypeConstant")) {
418 property.setIsTypeConstant(readBoolBinding(script));
419 }
else if (id == QLatin1String(
"isPropertyConstant")) {
420 property.setIsPropertyConstant(readBoolBinding(script));
421 }
else if (id == QLatin1String(
"isConstant")) {
423 property.setIsPropertyConstant(readBoolBinding(script));
424 }
else if (id == QLatin1String(
"revision")) {
425 property.setRevision(readIntBinding(script));
426 }
else if (id == QLatin1String(
"bindable")) {
427 property.setBindable(readStringBinding(script));
428 }
else if (id == QLatin1String(
"read")) {
429 property.setRead(readStringBinding(script));
430 }
else if (id == QLatin1String(
"write")) {
431 property.setWrite(readStringBinding(script));
432 }
else if (id == QLatin1String(
"reset")) {
433 property.setReset(readStringBinding(script));
434 }
else if (id == QLatin1String(
"notify")) {
435 property.setNotify(readStringBinding(script));
436 }
else if (id == QLatin1String(
"index")) {
437 property.setIndex(readIntBinding(script));
438 }
else if (id == QLatin1String(
"privateClass")) {
439 property.setPrivateClass(readStringBinding(script));
441 addWarning(script->firstSourceLocation(),
442 tr(
"Expected only type, name, lineNumber, revision, isPointer, "
443 "isTypeConstant, isReadonly, isRequired, "
444 "isFinal, isList, bindable, read, write, isPropertyConstant, reset, "
445 "notify, index, privateClass and script bindings."));
449 if (property.propertyName().isEmpty()) {
450 addError(ast->firstSourceLocation(),
451 tr(
"Property object is missing a name script binding."));
455 scope->addOwnProperty(property);
457 scope->setPropertyLocallyRequired(property.propertyName(),
true);
460void QQmlJSTypeDescriptionReader::readEnum(UiObjectDefinition *ast,
const QQmlJSScope::Ptr &scope)
462 QQmlJSMetaEnum metaEnum;
464 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
465 UiObjectMember *member = it->member;
466 auto *script = cast<UiScriptBinding *>(member);
468 addWarning(member->firstSourceLocation(), tr(
"Expected script binding."));
472 QString name = toString(script->qualifiedId);
473 if (name == QLatin1String(
"name")) {
474 metaEnum.setName(readStringBinding(script));
475 }
else if (name == QLatin1String(
"alias")) {
476 metaEnum.setAlias(readStringBinding(script));
477 }
else if (name == QLatin1String(
"isFlag")) {
478 metaEnum.setIsFlag(readBoolBinding(script));
479 }
else if (name == QLatin1String(
"values")) {
480 readEnumValues(script, &metaEnum);
481 }
else if (name == QLatin1String(
"isScoped")) {
482 metaEnum.setIsScoped(readBoolBinding(script));
483 }
else if (name == QLatin1String(
"type")) {
484 metaEnum.setTypeName(readStringBinding(script));
485 }
else if (name == QLatin1String(
"lineNumber")) {
486 metaEnum.setLineNumber(readIntBinding(script));
488 addWarning(script->firstSourceLocation(),
489 tr(
"Expected only name, alias, isFlag, values, isScoped, type, or "
494 scope->addOwnEnumeration(metaEnum);
497void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSMetaMethod *metaMethod)
501 bool isConstant =
false;
502 bool isPointer =
false;
505 for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
506 UiObjectMember *member = it->member;
507 auto *script = cast<UiScriptBinding *>(member);
509 addWarning(member->firstSourceLocation(), tr(
"Expected script binding."));
513 const QString id = toString(script->qualifiedId);
514 if (id == QLatin1String(
"name")) {
515 name = readStringBinding(script);
516 }
else if (id == QLatin1String(
"type")) {
517 type = readStringBinding(script);
518 }
else if (id == QLatin1String(
"isPointer")) {
519 isPointer = readBoolBinding(script);
520 }
else if (id == QLatin1String(
"isTypeConstant") || id == QLatin1String(
"isConstant")) {
522 isConstant = readBoolBinding(script);
523 }
else if (id == QLatin1String(
"isReadonly")) {
525 }
else if (id == QLatin1String(
"isList")) {
526 isList = readBoolBinding(script);
528 addWarning(script->firstSourceLocation(),
529 tr(
"Expected only name, type, isPointer, isTypeConstant, isReadonly, "
530 "or IsList script bindings."));
534 QQmlJSMetaParameter p(name, type);
535 p.setTypeQualifier(isConstant ? QQmlJSMetaParameter::Const : QQmlJSMetaParameter::NonConst);
536 p.setIsPointer(isPointer);
538 metaMethod->addParameter(std::move(p));
541QString QQmlJSTypeDescriptionReader::readStringBinding(UiScriptBinding *ast)
545 if (!ast->statement) {
546 addError(ast->colonToken, tr(
"Expected string after colon."));
550 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
552 addError(ast->statement->firstSourceLocation(), tr(
"Expected string after colon."));
556 auto *stringLit = cast<StringLiteral *>(expStmt->expression);
558 addError(expStmt->firstSourceLocation(), tr(
"Expected string after colon."));
562 return stringLit->value.toString();
565bool QQmlJSTypeDescriptionReader::readBoolBinding(UiScriptBinding *ast)
569 if (!ast->statement) {
570 addError(ast->colonToken, tr(
"Expected boolean after colon."));
574 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
576 addError(ast->statement->firstSourceLocation(), tr(
"Expected boolean after colon."));
580 auto *trueLit = cast<TrueLiteral *>(expStmt->expression);
581 auto *falseLit = cast<FalseLiteral *>(expStmt->expression);
582 if (!trueLit && !falseLit) {
583 addError(expStmt->firstSourceLocation(), tr(
"Expected true or false after colon."));
590double QQmlJSTypeDescriptionReader::readNumericBinding(UiScriptBinding *ast)
594 if (!ast->statement) {
595 addError(ast->colonToken, tr(
"Expected numeric literal after colon."));
599 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
601 addError(ast->statement->firstSourceLocation(),
602 tr(
"Expected numeric literal after colon."));
606 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
608 addError(expStmt->firstSourceLocation(), tr(
"Expected numeric literal after colon."));
612 return numericLit->value;
617 const int dotIdx = versionString.indexOf(QLatin1Char(
'.'));
619 return QTypeRevision();
621 const int maybeMajor = QStringView{versionString}.left(dotIdx).toInt(&ok);
623 return QTypeRevision();
624 const int maybeMinor = QStringView{versionString}.mid(dotIdx + 1).toInt(&ok);
626 return QTypeRevision();
627 return QTypeRevision::fromVersion(maybeMajor, maybeMinor);
630QTypeRevision QQmlJSTypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast)
632 QTypeRevision invalidVersion;
634 if (!ast || !ast->statement) {
635 addError((ast ? ast->colonToken : SourceLocation()),
636 tr(
"Expected numeric literal after colon."));
637 return invalidVersion;
640 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
642 addError(ast->statement->firstSourceLocation(),
643 tr(
"Expected numeric literal after colon."));
644 return invalidVersion;
647 auto *numericLit = cast<NumericLiteral *>(expStmt->expression);
649 addError(expStmt->firstSourceLocation(), tr(
"Expected numeric literal after colon."));
650 return invalidVersion;
653 return parseVersion(m_source.mid(numericLit->literalToken.begin(),
654 numericLit->literalToken.length));
657int QQmlJSTypeDescriptionReader::readIntBinding(UiScriptBinding *ast)
659 double v = readNumericBinding(ast);
660 int i =
static_cast<
int>(v);
663 addError(ast->firstSourceLocation(), tr(
"Expected integer after colon."));
670ArrayPattern* QQmlJSTypeDescriptionReader::getArray(UiScriptBinding *ast)
674 if (!ast->statement) {
675 addError(ast->colonToken, tr(
"Expected array of strings after colon."));
679 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
681 addError(ast->statement->firstSourceLocation(),
682 tr(
"Expected array of strings after colon."));
686 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
688 addError(expStmt->firstSourceLocation(), tr(
"Expected array of strings after colon."));
695QList<QQmlJSScope::Export> QQmlJSTypeDescriptionReader::readExports(UiScriptBinding *ast)
697 QList<QQmlJSScope::Export> exports;
698 auto *arrayLit = getArray(ast);
703 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
704 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
707 addError(arrayLit->firstSourceLocation(),
708 tr(
"Expected array literal with only string literal members."));
712 QString exp = stringLit->value.toString();
713 int slashIdx = exp.indexOf(QLatin1Char(
'/'));
714 int spaceIdx = exp.indexOf(QLatin1Char(
' '));
715 const QTypeRevision version = parseVersion(exp.mid(spaceIdx + 1));
717 if (spaceIdx == -1 || !version.isValid()) {
718 addError(stringLit->firstSourceLocation(),
719 tr(
"Expected string literal to contain 'Package/Name major.minor' "
720 "or 'Name major.minor'."));
725 package = exp.left(slashIdx);
726 QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
729 exports.append(QQmlJSScope::Export(package, name, version, version));
735void QQmlJSTypeDescriptionReader::readAliases(
736 QQmlJS::AST::UiScriptBinding *ast,
const QQmlJSScope::Ptr &scope)
738 scope->setAliases(readStringList(ast));
741void QQmlJSTypeDescriptionReader::readInterfaces(UiScriptBinding *ast,
const QQmlJSScope::Ptr &scope)
743 auto *arrayLit = getArray(ast);
750 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
751 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
753 addError(arrayLit->firstSourceLocation(),
754 tr(
"Expected array literal with only string literal members."));
758 list << stringLit->value.toString();
761 scope->setInterfaceNames(list);
764void QQmlJSTypeDescriptionReader::checkMetaObjectRevisions(
765 UiScriptBinding *ast, QList<QQmlJSScope::Export> *exports)
769 if (!ast->statement) {
770 addError(ast->colonToken, tr(
"Expected array of numbers after colon."));
774 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
776 addError(ast->statement->firstSourceLocation(),
777 tr(
"Expected array of numbers after colon."));
781 auto *arrayLit = cast<ArrayPattern *>(expStmt->expression);
783 addError(expStmt->firstSourceLocation(), tr(
"Expected array of numbers after colon."));
788 const int exportCount = exports->size();
789 for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
790 auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
792 addError(arrayLit->firstSourceLocation(),
793 tr(
"Expected array literal with only number literal members."));
797 if (exportIndex >= exportCount) {
798 addError(numberLit->firstSourceLocation(),
799 tr(
"Meta object revision without matching export."));
803 const double v = numberLit->value;
804 const int metaObjectRevision =
static_cast<
int>(v);
805 if (metaObjectRevision != v) {
806 addError(numberLit->firstSourceLocation(), tr(
"Expected integer."));
810 const QTypeRevision metaObjectVersion
811 = QTypeRevision::fromEncodedVersion(metaObjectRevision);
812 const QQmlJSScope::Export &entry = exports->at(exportIndex);
813 const QTypeRevision exportVersion = entry.version();
814 if (metaObjectVersion != exportVersion) {
815 addWarning(numberLit->firstSourceLocation(),
816 tr(
"Meta object revision and export version differ.\n"
817 "Revision %1 corresponds to version %2.%3; it should be %4.%5.")
818 .arg(metaObjectRevision)
819 .arg(metaObjectVersion.majorVersion()).arg(metaObjectVersion.minorVersion())
820 .arg(exportVersion.majorVersion()).arg(exportVersion.minorVersion()));
821 (*exports)[exportIndex] = QQmlJSScope::Export(entry.package(), entry.type(),
822 exportVersion, metaObjectVersion);
827QStringList QQmlJSTypeDescriptionReader::readStringList(UiScriptBinding *ast)
829 auto *arrayLit = getArray(ast);
835 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
836 auto *stringLit = cast<StringLiteral *>(it->element->initializer);
838 addError(arrayLit->firstSourceLocation(),
839 tr(
"Expected array literal with only string literal members."));
843 list << stringLit->value.toString();
849void QQmlJSTypeDescriptionReader::readDeferredNames(UiScriptBinding *ast,
850 const QQmlJSScope::Ptr &scope)
852 scope->setOwnDeferredNames(readStringList(ast));
855void QQmlJSTypeDescriptionReader::readImmediateNames(UiScriptBinding *ast,
856 const QQmlJSScope::Ptr &scope)
858 scope->setOwnImmediateNames(readStringList(ast));
861void QQmlJSTypeDescriptionReader::readEnumValues(UiScriptBinding *ast, QQmlJSMetaEnum *metaEnum)
865 if (!ast->statement) {
866 addError(ast->colonToken, tr(
"Expected object literal after colon."));
870 auto *expStmt = cast<ExpressionStatement *>(ast->statement);
872 addError(ast->statement->firstSourceLocation(), tr(
"Expected expression after colon."));
876 if (
auto *objectLit = cast<ObjectPattern *>(expStmt->expression)) {
877 int currentValue = -1;
878 for (PatternPropertyList *it = objectLit->properties; it; it = it->next) {
879 if (PatternProperty *assignement = it->property) {
880 if (
auto *name = cast<StringLiteralPropertyName *>(assignement->name)) {
881 metaEnum->addKey(name->id.toString());
883 if (
auto *value = AST::cast<NumericLiteral *>(assignement->initializer)) {
884 currentValue =
int(value->value);
885 }
else if (
auto *minus = AST::cast<UnaryMinusExpression *>(
886 assignement->initializer)) {
887 if (
auto *value = AST::cast<NumericLiteral *>(minus->expression))
888 currentValue = -
int(value->value);
895 metaEnum->addValue(currentValue);
899 addError(it->firstSourceLocation(), tr(
"Expected strings as enum keys."));
901 }
else if (
auto *arrayLit = cast<ArrayPattern *>(expStmt->expression)) {
902 for (PatternElementList *it = arrayLit->elements; it; it = it->next) {
903 if (PatternElement *element = it->element) {
904 if (
auto *name = cast<StringLiteral *>(element->initializer)) {
905 metaEnum->addKey(name->value.toString());
909 addError(it->firstSourceLocation(), tr(
"Expected strings as enum keys."));
912 addError(ast->statement->firstSourceLocation(),
913 tr(
"Expected either array or object literal as enum definition."));
Combined button and popup list for selecting options.
static QTypeRevision parseVersion(const QString &versionString)
QString toString(const UiQualifiedId *qualifiedId, QChar delimiter=QLatin1Char('.'))