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.isVirtual = property.isVirtual();
45 prop.isOverride = property.isOverride();
46 prop.bindable = property.bindable();
47 prop.read = property.read();
48 prop.write = property.write();
49 prop.notify = property.notify();
51 if (prop.name.isEmpty() || prop.typeName.isEmpty()) {
52 addError(readerParseErrors()
53 .warning(tr(
"Property object is missing a name or type script binding."))
57 objs[revision].addPropertyDef(prop, AddOption::KeepExisting);
60void QmltypesReader::insertSignalOrMethod(
const QQmlJSMetaMethod &metaMethod,
61 QMap<
int, QmlObject> &objs)
63 MethodInfo methodInfo;
65 switch (metaMethod.methodType()) {
66 case QQmlJSMetaMethodType::Method:
67 case QQmlJSMetaMethodType::Slot:
68 methodInfo.methodType = MethodInfo::MethodType::Method;
70 case QQmlJSMetaMethodType::Signal:
71 methodInfo.methodType = MethodInfo::MethodType::Signal;
76 auto parameters = metaMethod.parameters();
77 qsizetype nParam = parameters.size();
78 for (
int i = 0; i < nParam; ++i) {
79 MethodParameter param;
80 param.name = parameters[i].name();
81 param.typeName = parameters[i].typeName();
82 methodInfo.parameters.append(param);
84 methodInfo.name = metaMethod.methodName();
85 methodInfo.typeName = metaMethod.returnTypeName();
86 int revision = metaMethod.revision();
87 methodInfo.isConstructor = metaMethod.isConstructor();
88 if (methodInfo.name.isEmpty()) {
89 addError(readerParseErrors().error(tr(
"Method or signal is missing a name.")).handle());
93 objs[revision].addMethod(methodInfo, AddOption::KeepExisting);
96EnumDecl QmltypesReader::enumFromMetaEnum(
const QQmlJSMetaEnum &metaEnum)
99 res.setName(metaEnum.name());
100 res.setAlias(metaEnum.alias());
101 res.setIsFlag(metaEnum.isFlag());
102 QList<EnumItem> values;
104 for (
const auto &k : metaEnum.keys()) {
105 if (metaEnum.hasValues())
106 lastValue = metaEnum.value(k);
109 values.append(EnumItem(k, lastValue));
111 res.setValues(values);
115void QmltypesReader::insertComponent(
const QQmlJSScope::ConstPtr &jsScope,
116 const QList<QQmlJSScope::Export> &exportsList)
118 QmltypesComponent comp;
119 comp.setSemanticScope(jsScope);
120 QMap<
int, QmlObject> objects;
122 bool hasExports =
false;
123 for (
const QQmlJSScope::Export &jsE : exportsList) {
124 int metaRev = jsE.version().toEncodedVersion<
int>();
127 object.setSemanticScope(jsScope);
128 objects.insert(metaRev, object);
132 object.setSemanticScope(jsScope);
133 objects.insert(0, object);
136 bool incrementedPath =
false;
138 QString defaultPropertyName;
140 QHash<QString, QQmlJSMetaProperty> els = jsScope->ownProperties();
141 auto it = els.cbegin();
142 auto end = els.cend();
144 insertProperty(jsScope, it.value(), objects);
149 QMultiHash<QString, QQmlJSMetaMethod> els = jsScope->ownMethods();
150 auto it = els.cbegin();
151 auto end = els.cend();
153 insertSignalOrMethod(it.value(), objects);
158 QHash<QString, QQmlJSMetaEnum> els = jsScope->ownEnumerations();
159 auto it = els.cbegin();
160 auto end = els.cend();
162 comp.addEnumeration(enumFromMetaEnum(it.value()));
166 comp.setFileName(jsScope->filePath());
167 comp.setName(jsScope->internalName());
168 m_currentPath = m_currentPath.withKey(comp.name())
169 .withIndex(qmltypesFilePtr()->components().values(comp.name()).size());
170 incrementedPath =
true;
171 prototype = jsScope->baseTypeName();
172 defaultPropertyName = jsScope->ownDefaultPropertyName();
173 comp.setInterfaceNames(jsScope->interfaceNames());
174 QString typeName = jsScope->ownAttachedTypeName();
175 comp.setAttachedTypeName(typeName);
176 if (!typeName.isEmpty())
177 comp.setAttachedTypePath(Paths::lookupCppTypePath(typeName));
178 comp.setIsSingleton(jsScope->isSingleton());
179 comp.setIsCreatable(jsScope->isCreatable());
180 comp.setIsComposite(jsScope->isComposite());
181 comp.setHasCustomParser(jsScope->hasCustomParser());
182 comp.setElementTypeName(jsScope->elementTypeName());
183 comp.setAccessSemantics(jsScope->accessSemantics());
184 comp.setExtensionTypeName(jsScope->extensionTypeName());
185 comp.setExtensionIsJavaScript(jsScope->extensionIsJavaScript());
186 comp.setExtensionIsNamespace(jsScope->extensionIsNamespace());
187 Path exportSourcePath = qmltypesFilePtr()->canonicalPath();
188 QMap<
int, Path> revToPath;
189 auto it = objects.end();
190 auto begin = objects.begin();
193 Path compPath = qmltypesFilePtr()
195 .withField(Fields::components)
196 .withKey(comp.name())
197 .withIndex(qmltypesFilePtr()->components().values(comp.name()).size());
200 while (it != begin) {
203 addError(readerParseErrors().error(
204 tr(
"negative meta revision %1 not supported").arg(it.key())));
206 revToPath.insert(it.key(), compPath.withField(Fields::objects).withIndex(objectIndex));
207 Path nextObjectPath = compPath.withField(Fields::objects).withIndex(++objectIndex);
209 if (!prototype.isEmpty())
210 it->addPrototypePath(Paths::lookupCppTypePath(prototype));
211 it->setName(prototype);
213 it->addPrototypePath(nextObjectPath);
214 it->setName(comp.name() + QLatin1String(
"-") + QString::number(it.key()));
217 metaRevs.append(it.key());
219 comp.setMetaRevisions(metaRevs);
222 QList<Export> exports;
223 for (
const QQmlJSScope::Export &jsE : exportsList) {
224 auto v = jsE.version();
225 int metaRev = v.toEncodedVersion<
int>();
227 e.uri = jsE.package();
228 e.typeName = jsE.type();
229 e.isSingleton = jsScope->isSingleton();
230 e.version = Version((v.hasMajorVersion() ? v.majorVersion() : Version::Latest),
231 (v.hasMinorVersion() ? v.minorVersion() : Version::Latest));
232 e.typePath = revToPath.value(metaRev);
234 qCWarning(domLog) <<
"could not find version" << metaRev <<
"in" << revToPath.keys();
236 e.exportSourcePath = exportSourcePath;
240 if (comp.name().isEmpty()) {
241 addError(readerParseErrors()
242 .error(tr(
"Component definition is missing a name binding."))
246 qmltypesFilePtr()->addComponent(comp, AddOption::KeepExisting);
248 m_currentPath = m_currentPath.dropTail().dropTail();
251bool QmltypesReader::parse()
253 QQmlJSTypeDescriptionReader reader(qmltypesFilePtr()->canonicalFilePath(),
254 qmltypesFilePtr()->code());
255 QStringList dependencies;
256 QList<QQmlJSExportedScope> objects;
257 const bool isValid = reader(&objects, &dependencies);
258 for (
const auto &obj : std::as_const(objects))
259 insertComponent(obj.scope, obj.exports);
260 qmltypesFilePtr()->setIsValid(isValid);
264void QmltypesReader::addError(ErrorMessage &&message)
266 if (message.file.isEmpty())
267 message.file = qmltypesFilePtr()->canonicalFilePath();
269 message.path = m_currentPath;
270 qmltypesFilePtr()->addErrorLocal(message.handle());
#define NewErrorGroup(name)