Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmldomtypesreader.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
9
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>
14
15#include <QtCore/qdir.h>
16
17QT_BEGIN_NAMESPACE
18
19namespace QQmlJS {
20namespace Dom {
21
22using namespace QQmlJS::AST;
23
24static ErrorGroups readerParseErrors()
25{
26 static ErrorGroups errs = { { NewErrorGroup("Dom"), NewErrorGroup("QmltypesFile"),
27 NewErrorGroup("Parsing") } };
28 return errs;
29}
30
31void QmltypesReader::insertProperty(
32 const QQmlJSScope::ConstPtr &jsScope, const QQmlJSMetaProperty &property,
33 QMap<int, QmlObject> &objs)
34{
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();
50
51 if (prop.name.isEmpty() || prop.typeName.isEmpty()) {
52 addError(readerParseErrors()
53 .warning(tr("Property object is missing a name or type script binding."))
54 .handle());
55 return;
56 }
57 objs[revision].addPropertyDef(prop, AddOption::KeepExisting);
58}
59
60void QmltypesReader::insertSignalOrMethod(const QQmlJSMetaMethod &metaMethod,
61 QMap<int, QmlObject> &objs)
62{
63 MethodInfo methodInfo;
64 // ### confusion between Method and Slot. Method should be removed.
65 switch (metaMethod.methodType()) {
66 case QQmlJSMetaMethodType::Method:
67 case QQmlJSMetaMethodType::Slot:
68 methodInfo.methodType = MethodInfo::MethodType::Method;
69 break;
70 case QQmlJSMetaMethodType::Signal:
71 methodInfo.methodType = MethodInfo::MethodType::Signal;
72 break;
73 default:
74 Q_UNREACHABLE();
75 }
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);
83 }
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());
90 return;
91 }
92
93 objs[revision].addMethod(methodInfo, AddOption::KeepExisting);
94}
95
96EnumDecl QmltypesReader::enumFromMetaEnum(const QQmlJSMetaEnum &metaEnum)
97{
98 EnumDecl res;
99 res.setName(metaEnum.name());
100 res.setAlias(metaEnum.alias());
101 res.setIsFlag(metaEnum.isFlag());
102 QList<EnumItem> values;
103 int lastValue = -1;
104 for (const auto &k : metaEnum.keys()) {
105 if (metaEnum.hasValues())
106 lastValue = metaEnum.value(k);
107 else
108 ++lastValue;
109 values.append(EnumItem(k, lastValue));
110 }
111 res.setValues(values);
112 return res;
113}
114
115void QmltypesReader::insertComponent(const QQmlJSScope::ConstPtr &jsScope,
116 const QList<QQmlJSScope::Export> &exportsList)
117{
118 QmltypesComponent comp;
119 comp.setSemanticScope(jsScope);
120 QMap<int, QmlObject> objects;
121 {
122 bool hasExports = false;
123 for (const QQmlJSScope::Export &jsE : exportsList) {
124 int metaRev = jsE.version().toEncodedVersion<int>();
125 hasExports = true;
126 QmlObject object;
127 object.setSemanticScope(jsScope);
128 objects.insert(metaRev, object);
129 }
130 if (!hasExports) {
131 QmlObject object;
132 object.setSemanticScope(jsScope);
133 objects.insert(0, object);
134 }
135 }
136 bool incrementedPath = false;
137 QString prototype;
138 QString defaultPropertyName;
139 {
140 QHash<QString, QQmlJSMetaProperty> els = jsScope->ownProperties();
141 auto it = els.cbegin();
142 auto end = els.cend();
143 while (it != end) {
144 insertProperty(jsScope, it.value(), objects);
145 ++it;
146 }
147 }
148 {
149 QMultiHash<QString, QQmlJSMetaMethod> els = jsScope->ownMethods();
150 auto it = els.cbegin();
151 auto end = els.cend();
152 while (it != end) {
153 insertSignalOrMethod(it.value(), objects);
154 ++it;
155 }
156 }
157 {
158 QHash<QString, QQmlJSMetaEnum> els = jsScope->ownEnumerations();
159 auto it = els.cbegin();
160 auto end = els.cend();
161 while (it != end) {
162 comp.addEnumeration(enumFromMetaEnum(it.value()));
163 ++it;
164 }
165 }
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();
191 int objectIndex = 0;
192 QList<int> metaRevs;
193 Path compPath = qmltypesFilePtr()
194 ->canonicalPath()
195 .withField(Fields::components)
196 .withKey(comp.name())
197 .withIndex(qmltypesFilePtr()->components().values(comp.name()).size());
198
199 // emit & map objs
200 while (it != begin) {
201 --it;
202 if (it.key() < 0) {
203 addError(readerParseErrors().error(
204 tr("negative meta revision %1 not supported").arg(it.key())));
205 }
206 revToPath.insert(it.key(), compPath.withField(Fields::objects).withIndex(objectIndex));
207 Path nextObjectPath = compPath.withField(Fields::objects).withIndex(++objectIndex);
208 if (it == begin) {
209 if (!prototype.isEmpty())
210 it->addPrototypePath(Paths::lookupCppTypePath(prototype));
211 it->setName(prototype);
212 } else {
213 it->addPrototypePath(nextObjectPath);
214 it->setName(comp.name() + QLatin1String("-") + QString::number(it.key()));
215 }
216 comp.addObject(*it);
217 metaRevs.append(it.key());
218 }
219 comp.setMetaRevisions(metaRevs);
220
221 // exports:
222 QList<Export> exports;
223 for (const QQmlJSScope::Export &jsE : exportsList) {
224 auto v = jsE.version();
225 int metaRev = v.toEncodedVersion<int>();
226 Export e;
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);
233 if (!e.typePath) {
234 qCWarning(domLog) << "could not find version" << metaRev << "in" << revToPath.keys();
235 }
236 e.exportSourcePath = exportSourcePath;
237 comp.addExport(e);
238 }
239
240 if (comp.name().isEmpty()) {
241 addError(readerParseErrors()
242 .error(tr("Component definition is missing a name binding."))
243 .handle());
244 return;
245 }
246 qmltypesFilePtr()->addComponent(comp, AddOption::KeepExisting);
247 if (incrementedPath)
248 m_currentPath = m_currentPath.dropTail().dropTail();
249}
250
251bool QmltypesReader::parse()
252{
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);
261 return isValid;
262}
263
264void QmltypesReader::addError(ErrorMessage &&message)
265{
266 if (message.file.isEmpty())
267 message.file = qmltypesFilePtr()->canonicalFilePath();
268 if (!message.path)
269 message.path = m_currentPath;
270 qmltypesFilePtr()->addErrorLocal(message.handle());
271}
272
273} // end namespace Dom
274} // end namespace QQmlJS
275QT_END_NAMESPACE
#define NewErrorGroup(name)