10#include <QtQml/private/qqmljsparser_p.h>
11#include <QtQml/private/qqmljslexer_p.h>
12#include <QtQml/private/qqmljsengine_p.h>
13#include <private/qqmljstypedescriptionreader_p.h>
15#include <QtCore/qdir.h>
22using namespace QQmlJS::AST;
24static ErrorGroups readerParseErrors()
31void QmltypesReader::insertProperty(
32 const QQmlJSScope::ConstPtr &jsScope,
const QQmlJSMetaProperty &property,
33 QMap<
int, QmlObject> &objs)
35 PropertyDefinition prop;
36 prop.name = property.propertyName();
37 prop.typeName = property.typeName();
38 prop.isPointer = property.isPointer();
39 prop.isReadonly = !property.isWritable();
40 prop.isRequired = jsScope->isPropertyLocallyRequired(prop.name);
41 prop.isList = property.isList();
42 int revision = property.revision();
43 prop.isFinal = property.isFinal();
44 prop.bindable = property.bindable();
45 prop.read = property.read();
46 prop.write = property.write();
47 prop.notify = property.notify();
49 if (prop.name.isEmpty() || prop.typeName.isEmpty()) {
50 addError(readerParseErrors()
51 .warning(tr(
"Property object is missing a name or type script binding."))
55 objs[revision].addPropertyDef(prop, AddOption::KeepExisting);
58void QmltypesReader::insertSignalOrMethod(
const QQmlJSMetaMethod &metaMethod,
59 QMap<
int, QmlObject> &objs)
61 MethodInfo methodInfo;
63 switch (metaMethod.methodType()) {
64 case QQmlJSMetaMethodType::Method:
65 case QQmlJSMetaMethodType::Slot:
66 methodInfo.methodType = MethodInfo::MethodType::Method;
68 case QQmlJSMetaMethodType::Signal:
69 methodInfo.methodType = MethodInfo::MethodType::Signal;
74 auto parameters = metaMethod.parameters();
75 qsizetype nParam = parameters.size();
76 for (
int i = 0; i < nParam; ++i) {
77 MethodParameter param;
78 param.name = parameters[i].name();
79 param.typeName = parameters[i].typeName();
80 methodInfo.parameters.append(param);
82 methodInfo.name = metaMethod.methodName();
83 methodInfo.typeName = metaMethod.returnTypeName();
84 int revision = metaMethod.revision();
85 methodInfo.isConstructor = metaMethod.isConstructor();
86 if (methodInfo.name.isEmpty()) {
87 addError(readerParseErrors().error(tr(
"Method or signal is missing a name.")).handle());
91 objs[revision].addMethod(methodInfo, AddOption::KeepExisting);
94EnumDecl QmltypesReader::enumFromMetaEnum(
const QQmlJSMetaEnum &metaEnum)
97 res.setName(metaEnum.name());
98 res.setAlias(metaEnum.alias());
99 res.setIsFlag(metaEnum.isFlag());
100 QList<EnumItem> values;
102 for (
const auto &k : metaEnum.keys()) {
103 if (metaEnum.hasValues())
104 lastValue = metaEnum.value(k);
107 values.append(EnumItem(k, lastValue));
109 res.setValues(values);
113void QmltypesReader::insertComponent(
const QQmlJSScope::ConstPtr &jsScope,
114 const QList<QQmlJSScope::Export> &exportsList)
116 QmltypesComponent comp;
117 comp.setSemanticScope(jsScope);
118 QMap<
int, QmlObject> objects;
120 bool hasExports =
false;
121 for (
const QQmlJSScope::Export &jsE : exportsList) {
122 int metaRev = jsE.version().toEncodedVersion<
int>();
125 object.setSemanticScope(jsScope);
126 objects.insert(metaRev, object);
130 object.setSemanticScope(jsScope);
131 objects.insert(0, object);
134 bool incrementedPath =
false;
136 QString defaultPropertyName;
138 QHash<QString, QQmlJSMetaProperty> els = jsScope->ownProperties();
139 auto it = els.cbegin();
140 auto end = els.cend();
142 insertProperty(jsScope, it.value(), objects);
147 QMultiHash<QString, QQmlJSMetaMethod> els = jsScope->ownMethods();
148 auto it = els.cbegin();
149 auto end = els.cend();
151 insertSignalOrMethod(it.value(), objects);
156 QHash<QString, QQmlJSMetaEnum> els = jsScope->ownEnumerations();
157 auto it = els.cbegin();
158 auto end = els.cend();
160 comp.addEnumeration(enumFromMetaEnum(it.value()));
164 comp.setFileName(jsScope->filePath());
165 comp.setName(jsScope->internalName());
166 m_currentPath = m_currentPath.withKey(comp.name())
167 .withIndex(qmltypesFilePtr()->components().values(comp.name()).size());
168 incrementedPath =
true;
169 prototype = jsScope->baseTypeName();
170 defaultPropertyName = jsScope->ownDefaultPropertyName();
171 comp.setInterfaceNames(jsScope->interfaceNames());
172 QString typeName = jsScope->ownAttachedTypeName();
173 comp.setAttachedTypeName(typeName);
174 if (!typeName.isEmpty())
175 comp.setAttachedTypePath(Paths::lookupCppTypePath(typeName));
176 comp.setIsSingleton(jsScope->isSingleton());
177 comp.setIsCreatable(jsScope->isCreatable());
178 comp.setIsComposite(jsScope->isComposite());
179 comp.setHasCustomParser(jsScope->hasCustomParser());
180 comp.setElementTypeName(jsScope->elementTypeName());
181 comp.setAccessSemantics(jsScope->accessSemantics());
182 comp.setExtensionTypeName(jsScope->extensionTypeName());
183 comp.setExtensionIsJavaScript(jsScope->extensionIsJavaScript());
184 comp.setExtensionIsNamespace(jsScope->extensionIsNamespace());
185 Path exportSourcePath = qmltypesFilePtr()->canonicalPath();
186 QMap<
int, Path> revToPath;
187 auto it = objects.end();
188 auto begin = objects.begin();
191 Path compPath = qmltypesFilePtr()
193 .withField(Fields::components)
194 .withKey(comp.name())
195 .withIndex(qmltypesFilePtr()->components().values(comp.name()).size());
198 while (it != begin) {
201 addError(readerParseErrors().error(
202 tr(
"negative meta revision %1 not supported").arg(it.key())));
204 revToPath.insert(it.key(), compPath.withField(Fields::objects).withIndex(objectIndex));
205 Path nextObjectPath = compPath.withField(Fields::objects).withIndex(++objectIndex);
207 if (!prototype.isEmpty())
208 it->addPrototypePath(Paths::lookupCppTypePath(prototype));
209 it->setName(prototype);
211 it->addPrototypePath(nextObjectPath);
212 it->setName(comp.name() + QLatin1String(
"-") + QString::number(it.key()));
215 metaRevs.append(it.key());
217 comp.setMetaRevisions(metaRevs);
220 QList<Export> exports;
221 for (
const QQmlJSScope::Export &jsE : exportsList) {
222 auto v = jsE.version();
223 int metaRev = v.toEncodedVersion<
int>();
225 e.uri = jsE.package();
226 e.typeName = jsE.type();
227 e.isSingleton = jsScope->isSingleton();
228 e.version = Version((v.hasMajorVersion() ? v.majorVersion() : Version::Latest),
229 (v.hasMinorVersion() ? v.minorVersion() : Version::Latest));
230 e.typePath = revToPath.value(metaRev);
232 qCWarning(domLog) <<
"could not find version" << metaRev <<
"in" << revToPath.keys();
234 e.exportSourcePath = exportSourcePath;
238 if (comp.name().isEmpty()) {
239 addError(readerParseErrors()
240 .error(tr(
"Component definition is missing a name binding."))
244 qmltypesFilePtr()->addComponent(comp, AddOption::KeepExisting);
246 m_currentPath = m_currentPath.dropTail().dropTail();
249bool QmltypesReader::parse()
251 QQmlJSTypeDescriptionReader reader(qmltypesFilePtr()->canonicalFilePath(),
252 qmltypesFilePtr()->code());
253 QStringList dependencies;
254 QList<QQmlJSExportedScope> objects;
255 const bool isValid = reader(&objects, &dependencies);
256 for (
const auto &obj : std::as_const(objects))
257 insertComponent(obj.scope, obj.exports);
258 qmltypesFilePtr()->setIsValid(isValid);
262void QmltypesReader::addError(ErrorMessage &&message)
264 if (message.file.isEmpty())
265 message.file = qmltypesFilePtr()->canonicalFilePath();
267 message.path = m_currentPath;
268 qmltypesFilePtr()->addErrorLocal(message.handle());
#define NewErrorGroup(name)