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.bindable = property.bindable();
45 prop.read = property.read();
46 prop.write = property.write();
47 prop.notify = property.notify();
48
49 if (prop.name.isEmpty() || prop.typeName.isEmpty()) {
50 addError(readerParseErrors()
51 .warning(tr("Property object is missing a name or type script binding."))
52 .handle());
53 return;
54 }
55 objs[revision].addPropertyDef(prop, AddOption::KeepExisting);
56}
57
58void QmltypesReader::insertSignalOrMethod(const QQmlJSMetaMethod &metaMethod,
59 QMap<int, QmlObject> &objs)
60{
61 MethodInfo methodInfo;
62 // ### confusion between Method and Slot. Method should be removed.
63 switch (metaMethod.methodType()) {
64 case QQmlJSMetaMethodType::Method:
65 case QQmlJSMetaMethodType::Slot:
66 methodInfo.methodType = MethodInfo::MethodType::Method;
67 break;
68 case QQmlJSMetaMethodType::Signal:
69 methodInfo.methodType = MethodInfo::MethodType::Signal;
70 break;
71 default:
72 Q_UNREACHABLE();
73 }
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);
81 }
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());
88 return;
89 }
90
91 objs[revision].addMethod(methodInfo, AddOption::KeepExisting);
92}
93
94EnumDecl QmltypesReader::enumFromMetaEnum(const QQmlJSMetaEnum &metaEnum)
95{
96 EnumDecl res;
97 res.setName(metaEnum.name());
98 res.setAlias(metaEnum.alias());
99 res.setIsFlag(metaEnum.isFlag());
100 QList<EnumItem> values;
101 int lastValue = -1;
102 for (const auto &k : metaEnum.keys()) {
103 if (metaEnum.hasValues())
104 lastValue = metaEnum.value(k);
105 else
106 ++lastValue;
107 values.append(EnumItem(k, lastValue));
108 }
109 res.setValues(values);
110 return res;
111}
112
113void QmltypesReader::insertComponent(const QQmlJSScope::ConstPtr &jsScope,
114 const QList<QQmlJSScope::Export> &exportsList)
115{
116 QmltypesComponent comp;
117 comp.setSemanticScope(jsScope);
118 QMap<int, QmlObject> objects;
119 {
120 bool hasExports = false;
121 for (const QQmlJSScope::Export &jsE : exportsList) {
122 int metaRev = jsE.version().toEncodedVersion<int>();
123 hasExports = true;
124 QmlObject object;
125 object.setSemanticScope(jsScope);
126 objects.insert(metaRev, object);
127 }
128 if (!hasExports) {
129 QmlObject object;
130 object.setSemanticScope(jsScope);
131 objects.insert(0, object);
132 }
133 }
134 bool incrementedPath = false;
135 QString prototype;
136 QString defaultPropertyName;
137 {
138 QHash<QString, QQmlJSMetaProperty> els = jsScope->ownProperties();
139 auto it = els.cbegin();
140 auto end = els.cend();
141 while (it != end) {
142 insertProperty(jsScope, it.value(), objects);
143 ++it;
144 }
145 }
146 {
147 QMultiHash<QString, QQmlJSMetaMethod> els = jsScope->ownMethods();
148 auto it = els.cbegin();
149 auto end = els.cend();
150 while (it != end) {
151 insertSignalOrMethod(it.value(), objects);
152 ++it;
153 }
154 }
155 {
156 QHash<QString, QQmlJSMetaEnum> els = jsScope->ownEnumerations();
157 auto it = els.cbegin();
158 auto end = els.cend();
159 while (it != end) {
160 comp.addEnumeration(enumFromMetaEnum(it.value()));
161 ++it;
162 }
163 }
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();
189 int objectIndex = 0;
190 QList<int> metaRevs;
191 Path compPath = qmltypesFilePtr()
192 ->canonicalPath()
193 .withField(Fields::components)
194 .withKey(comp.name())
195 .withIndex(qmltypesFilePtr()->components().values(comp.name()).size());
196
197 // emit & map objs
198 while (it != begin) {
199 --it;
200 if (it.key() < 0) {
201 addError(readerParseErrors().error(
202 tr("negative meta revision %1 not supported").arg(it.key())));
203 }
204 revToPath.insert(it.key(), compPath.withField(Fields::objects).withIndex(objectIndex));
205 Path nextObjectPath = compPath.withField(Fields::objects).withIndex(++objectIndex);
206 if (it == begin) {
207 if (!prototype.isEmpty())
208 it->addPrototypePath(Paths::lookupCppTypePath(prototype));
209 it->setName(prototype);
210 } else {
211 it->addPrototypePath(nextObjectPath);
212 it->setName(comp.name() + QLatin1String("-") + QString::number(it.key()));
213 }
214 comp.addObject(*it);
215 metaRevs.append(it.key());
216 }
217 comp.setMetaRevisions(metaRevs);
218
219 // exports:
220 QList<Export> exports;
221 for (const QQmlJSScope::Export &jsE : exportsList) {
222 auto v = jsE.version();
223 int metaRev = v.toEncodedVersion<int>();
224 Export e;
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);
231 if (!e.typePath) {
232 qCWarning(domLog) << "could not find version" << metaRev << "in" << revToPath.keys();
233 }
234 e.exportSourcePath = exportSourcePath;
235 comp.addExport(e);
236 }
237
238 if (comp.name().isEmpty()) {
239 addError(readerParseErrors()
240 .error(tr("Component definition is missing a name binding."))
241 .handle());
242 return;
243 }
244 qmltypesFilePtr()->addComponent(comp, AddOption::KeepExisting);
245 if (incrementedPath)
246 m_currentPath = m_currentPath.dropTail().dropTail();
247}
248
249bool QmltypesReader::parse()
250{
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);
259 return isValid;
260}
261
262void QmltypesReader::addError(ErrorMessage &&message)
263{
264 if (message.file.isEmpty())
265 message.file = qmltypesFilePtr()->canonicalFilePath();
266 if (!message.path)
267 message.path = m_currentPath;
268 qmltypesFilePtr()->addErrorLocal(message.handle());
269}
270
271} // end namespace Dom
272} // end namespace QQmlJS
273QT_END_NAMESPACE
#define NewErrorGroup(name)