| 1 | // Copyright (C) 2021 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 | |
| 4 | #ifndef QQMLDOMELEMENTS_P_H |
| 5 | #define QQMLDOMELEMENTS_P_H |
| 6 | |
| 7 | // |
| 8 | // W A R N I N G |
| 9 | // ------------- |
| 10 | // |
| 11 | // This file is not part of the Qt API. It exists purely as an |
| 12 | // implementation detail. This header file may change from version to |
| 13 | // version without notice, or even be removed. |
| 14 | // |
| 15 | // We mean it. |
| 16 | // |
| 17 | |
| 18 | #include "qqmldomitem_p.h" |
| 19 | #include "qqmldomconstants_p.h" |
| 20 | #include "qqmldomcomments_p.h" |
| 21 | #include "qqmldomlinewriter_p.h" |
| 22 | |
| 23 | #include <QtQml/private/qqmljsast_p.h> |
| 24 | #include <QtQml/private/qqmljsengine_p.h> |
| 25 | #include <QtQml/private/qqmlsignalnames_p.h> |
| 26 | |
| 27 | #include <QtCore/QCborValue> |
| 28 | #include <QtCore/QCborMap> |
| 29 | #include <QtCore/QMutexLocker> |
| 30 | |
| 31 | #include <memory> |
| 32 | #include <private/qqmljsscope_p.h> |
| 33 | |
| 34 | #include <functional> |
| 35 | #include <limits> |
| 36 | #include <utility> |
| 37 | |
| 38 | QT_BEGIN_NAMESPACE |
| 39 | |
| 40 | namespace QQmlJS { |
| 41 | namespace Dom { |
| 42 | |
| 43 | // namespace for utility methods building specific paths |
| 44 | // using a namespace one can reopen it and add more methods in other places |
| 45 | namespace Paths { |
| 46 | Path moduleIndexPath( |
| 47 | const QString &uri, int majorVersion, const ErrorHandler &errorHandler = nullptr); |
| 48 | Path moduleScopePath( |
| 49 | const QString &uri, Version version, const ErrorHandler &errorHandler = nullptr); |
| 50 | Path moduleScopePath( |
| 51 | const QString &uri, const QString &version, const ErrorHandler &errorHandler = nullptr); |
| 52 | inline Path moduleScopePath( |
| 53 | const QString &uri, const ErrorHandler &errorHandler = nullptr) |
| 54 | { |
| 55 | return moduleScopePath(uri, version: QString(), errorHandler); |
| 56 | } |
| 57 | inline Path qmlDirInfoPath(const QString &path) |
| 58 | { |
| 59 | return Path::fromRoot(r: PathRoot::Top).withField(name: Fields::qmldirWithPath).withKey(name: path); |
| 60 | } |
| 61 | inline Path qmlDirPath(const QString &path) |
| 62 | { |
| 63 | return qmlDirInfoPath(path).withField(name: Fields::currentItem); |
| 64 | } |
| 65 | inline Path qmldirFileInfoPath(const QString &path) |
| 66 | { |
| 67 | return Path::fromRoot(r: PathRoot::Top).withField(name: Fields::qmldirFileWithPath).withKey(name: path); |
| 68 | } |
| 69 | inline Path qmldirFilePath(const QString &path) |
| 70 | { |
| 71 | return qmldirFileInfoPath(path).withField(name: Fields::currentItem); |
| 72 | } |
| 73 | inline Path qmlFileInfoPath(const QString &canonicalFilePath) |
| 74 | { |
| 75 | return Path::fromRoot(r: PathRoot::Top).withField(name: Fields::qmlFileWithPath).withKey(name: canonicalFilePath); |
| 76 | } |
| 77 | inline Path qmlFilePath(const QString &canonicalFilePath) |
| 78 | { |
| 79 | return qmlFileInfoPath(canonicalFilePath).withField(name: Fields::currentItem); |
| 80 | } |
| 81 | inline Path qmlFileObjectPath(const QString &canonicalFilePath) |
| 82 | { |
| 83 | return qmlFilePath(canonicalFilePath) |
| 84 | .withField(name: Fields::components) |
| 85 | .withKey(name: QString()) |
| 86 | .withIndex(i: 0) |
| 87 | .withField(name: Fields::objects) |
| 88 | .withIndex(i: 0); |
| 89 | } |
| 90 | inline Path qmltypesFileInfoPath(const QString &path) |
| 91 | { |
| 92 | return Path::fromRoot(r: PathRoot::Top).withField(name: Fields::qmltypesFileWithPath).withKey(name: path); |
| 93 | } |
| 94 | inline Path qmltypesFilePath(const QString &path) |
| 95 | { |
| 96 | return qmltypesFileInfoPath(path).withField(name: Fields::currentItem); |
| 97 | } |
| 98 | inline Path jsFileInfoPath(const QString &path) |
| 99 | { |
| 100 | return Path::fromRoot(r: PathRoot::Top).withField(name: Fields::jsFileWithPath).withKey(name: path); |
| 101 | } |
| 102 | inline Path jsFilePath(const QString &path) |
| 103 | { |
| 104 | return jsFileInfoPath(path).withField(name: Fields::currentItem); |
| 105 | } |
| 106 | inline Path qmlDirectoryInfoPath(const QString &path) |
| 107 | { |
| 108 | return Path::fromRoot(r: PathRoot::Top).withField(name: Fields::qmlDirectoryWithPath).withKey(name: path); |
| 109 | } |
| 110 | inline Path qmlDirectoryPath(const QString &path) |
| 111 | { |
| 112 | return qmlDirectoryInfoPath(path).withField(name: Fields::currentItem); |
| 113 | } |
| 114 | inline Path globalScopeInfoPath(const QString &name) |
| 115 | { |
| 116 | return Path::fromRoot(r: PathRoot::Top).withField(name: Fields::globalScopeWithName).withKey(name); |
| 117 | } |
| 118 | inline Path globalScopePath(const QString &name) |
| 119 | { |
| 120 | return globalScopeInfoPath(name).withField(name: Fields::currentItem); |
| 121 | } |
| 122 | inline Path lookupCppTypePath(const QString &name) |
| 123 | { |
| 124 | return Path::fromCurrent(c: PathCurrent::Lookup).withField(name: Fields::cppType).withKey(name); |
| 125 | } |
| 126 | inline Path lookupPropertyPath(const QString &name) |
| 127 | { |
| 128 | return Path::fromCurrent(c: PathCurrent::Lookup).withField(name: Fields::propertyDef).withKey(name); |
| 129 | } |
| 130 | inline Path lookupSymbolPath(const QString &name) |
| 131 | { |
| 132 | return Path::fromCurrent(c: PathCurrent::Lookup).withField(name: Fields::symbol).withKey(name); |
| 133 | } |
| 134 | inline Path lookupTypePath(const QString &name) |
| 135 | { |
| 136 | return Path::fromCurrent(c: PathCurrent::Lookup).withField(name: Fields::type).withKey(name); |
| 137 | } |
| 138 | inline Path loadInfoPath(const Path &el) |
| 139 | { |
| 140 | return Path::fromRoot(r: PathRoot::Env).withField(name: Fields::loadInfo).withKey(name: el.toString()); |
| 141 | } |
| 142 | } // end namespace Paths |
| 143 | |
| 144 | class QMLDOM_EXPORT : public DomElement |
| 145 | { |
| 146 | public: |
| 147 | (const Path &pathFromOwner = Path()) : DomElement(pathFromOwner) { } |
| 148 | (const CommentableDomElement &o) : DomElement(o), m_comments(o.m_comments) |
| 149 | { |
| 150 | } |
| 151 | CommentableDomElement &(const CommentableDomElement &o) = default; |
| 152 | bool (const DomItem &self, DirectVisitor) const override; |
| 153 | RegionComments &() { return m_comments; } |
| 154 | const RegionComments &() const { return m_comments; } |
| 155 | |
| 156 | private: |
| 157 | RegionComments ; |
| 158 | }; |
| 159 | |
| 160 | class QMLDOM_EXPORT Version |
| 161 | { |
| 162 | public: |
| 163 | constexpr static DomType kindValue = DomType::Version; |
| 164 | constexpr static qint32 Undefined = -1; |
| 165 | constexpr static qint32 Latest = -2; |
| 166 | |
| 167 | Version(qint32 majorVersion = Undefined, qint32 minorVersion = Undefined); |
| 168 | static Version fromString(QStringView v); |
| 169 | |
| 170 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; |
| 171 | |
| 172 | bool isLatest() const; |
| 173 | bool isValid() const; |
| 174 | QString stringValue() const; |
| 175 | QString majorString() const |
| 176 | { |
| 177 | if (majorVersion >= 0 || majorVersion == Undefined) |
| 178 | return QString::number(majorVersion); |
| 179 | return QString(); |
| 180 | } |
| 181 | QString majorSymbolicString() const |
| 182 | { |
| 183 | if (majorVersion == Version::Latest) |
| 184 | return QLatin1String("Latest" ); |
| 185 | if (majorVersion >= 0 || majorVersion == Undefined) |
| 186 | return QString::number(majorVersion); |
| 187 | return QString(); |
| 188 | } |
| 189 | QString minorString() const |
| 190 | { |
| 191 | if (minorVersion >= 0 || minorVersion == Undefined) |
| 192 | return QString::number(minorVersion); |
| 193 | return QString(); |
| 194 | } |
| 195 | int compare(const Version &o) const |
| 196 | { |
| 197 | int c = majorVersion - o.majorVersion; |
| 198 | if (c != 0) |
| 199 | return c; |
| 200 | return minorVersion - o.minorVersion; |
| 201 | } |
| 202 | |
| 203 | qint32 majorVersion; |
| 204 | qint32 minorVersion; |
| 205 | }; |
| 206 | inline bool operator==(const Version &v1, const Version &v2) |
| 207 | { |
| 208 | return v1.compare(o: v2) == 0; |
| 209 | } |
| 210 | inline bool operator!=(const Version &v1, const Version &v2) |
| 211 | { |
| 212 | return v1.compare(o: v2) != 0; |
| 213 | } |
| 214 | inline bool operator<(const Version &v1, const Version &v2) |
| 215 | { |
| 216 | return v1.compare(o: v2) < 0; |
| 217 | } |
| 218 | inline bool operator<=(const Version &v1, const Version &v2) |
| 219 | { |
| 220 | return v1.compare(o: v2) <= 0; |
| 221 | } |
| 222 | inline bool operator>(const Version &v1, const Version &v2) |
| 223 | { |
| 224 | return v1.compare(o: v2) > 0; |
| 225 | } |
| 226 | inline bool operator>=(const Version &v1, const Version &v2) |
| 227 | { |
| 228 | return v1.compare(o: v2) >= 0; |
| 229 | } |
| 230 | |
| 231 | class QMLDOM_EXPORT QmlUri |
| 232 | { |
| 233 | public: |
| 234 | enum class Kind { Invalid, ModuleUri, DirectoryUrl, RelativePath, AbsolutePath }; |
| 235 | QmlUri() = default; |
| 236 | static QmlUri fromString(const QString &importStr); |
| 237 | static QmlUri fromUriString(const QString &importStr); |
| 238 | static QmlUri fromDirectoryString(const QString &importStr); |
| 239 | bool isValid() const; |
| 240 | bool isDirectory() const; |
| 241 | bool isModule() const; |
| 242 | QString moduleUri() const; |
| 243 | QString localPath() const; |
| 244 | QString absoluteLocalPath(const QString &basePath = QString()) const; |
| 245 | QUrl directoryUrl() const; |
| 246 | QString directoryString() const; |
| 247 | QString toString() const; |
| 248 | Kind kind() const; |
| 249 | |
| 250 | friend bool operator==(const QmlUri &i1, const QmlUri &i2) |
| 251 | { |
| 252 | return i1.m_kind == i2.m_kind && i1.m_value == i2.m_value; |
| 253 | } |
| 254 | friend bool operator!=(const QmlUri &i1, const QmlUri &i2) { return !(i1 == i2); } |
| 255 | |
| 256 | private: |
| 257 | QmlUri(const QUrl &url) : m_kind(Kind::DirectoryUrl), m_value(url) { } |
| 258 | QmlUri(Kind kind, const QString &value) : m_kind(kind), m_value(value) { } |
| 259 | Kind m_kind = Kind::Invalid; |
| 260 | std::variant<QString, QUrl> m_value; |
| 261 | }; |
| 262 | |
| 263 | class QMLDOM_EXPORT Import |
| 264 | { |
| 265 | Q_DECLARE_TR_FUNCTIONS(Import) |
| 266 | public: |
| 267 | constexpr static DomType kindValue = DomType::Import; |
| 268 | |
| 269 | static Import fromUriString( |
| 270 | const QString &importStr, Version v = Version(), const QString &importId = QString(), |
| 271 | const ErrorHandler &handler = nullptr); |
| 272 | static Import fromFileString( |
| 273 | const QString &importStr, const QString &importId = QString(), |
| 274 | const ErrorHandler &handler = nullptr); |
| 275 | |
| 276 | Import(const QmlUri &uri = QmlUri(), Version version = Version(), |
| 277 | const QString &importId = QString()) |
| 278 | : uri(uri), version(version), importId(importId) |
| 279 | { |
| 280 | } |
| 281 | |
| 282 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; |
| 283 | Path importedPath() const |
| 284 | { |
| 285 | if (uri.isDirectory()) { |
| 286 | QString path = uri.absoluteLocalPath(); |
| 287 | if (!path.isEmpty()) { |
| 288 | return Paths::qmlDirPath(path); |
| 289 | } else { |
| 290 | Q_ASSERT_X(false, "Import" , "url imports not supported" ); |
| 291 | return Paths::qmldirFilePath(path: uri.directoryString()); |
| 292 | } |
| 293 | } else { |
| 294 | return Paths::moduleScopePath(uri: uri.moduleUri(), version); |
| 295 | } |
| 296 | } |
| 297 | Import baseImport() const { return Import { uri, version }; } |
| 298 | |
| 299 | friend bool operator==(const Import &i1, const Import &i2) |
| 300 | { |
| 301 | return i1.uri == i2.uri && i1.version == i2.version && i1.importId == i2.importId |
| 302 | && i1.comments == i2.comments && i1.implicit == i2.implicit; |
| 303 | } |
| 304 | friend bool operator!=(const Import &i1, const Import &i2) { return !(i1 == i2); } |
| 305 | |
| 306 | void writeOut(const DomItem &self, OutWriter &ow) const; |
| 307 | |
| 308 | static QRegularExpression importRe(); |
| 309 | |
| 310 | QmlUri uri; |
| 311 | Version version; |
| 312 | QString importId; |
| 313 | RegionComments ; |
| 314 | bool implicit = false; |
| 315 | }; |
| 316 | |
| 317 | class QMLDOM_EXPORT ModuleAutoExport |
| 318 | { |
| 319 | public: |
| 320 | constexpr static DomType kindValue = DomType::ModuleAutoExport; |
| 321 | |
| 322 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
| 323 | { |
| 324 | bool cont = true; |
| 325 | cont = cont && self.dvWrapField(visitor, f: Fields::import, obj: import); |
| 326 | cont = cont && self.dvValueField(visitor, f: Fields::inheritVersion, value: inheritVersion); |
| 327 | return cont; |
| 328 | } |
| 329 | |
| 330 | friend bool operator==(const ModuleAutoExport &i1, const ModuleAutoExport &i2) |
| 331 | { |
| 332 | return i1.import == i2.import && i1.inheritVersion == i2.inheritVersion; |
| 333 | } |
| 334 | friend bool operator!=(const ModuleAutoExport &i1, const ModuleAutoExport &i2) |
| 335 | { |
| 336 | return !(i1 == i2); |
| 337 | } |
| 338 | |
| 339 | Import import; |
| 340 | bool inheritVersion = false; |
| 341 | }; |
| 342 | |
| 343 | class QMLDOM_EXPORT Pragma |
| 344 | { |
| 345 | public: |
| 346 | constexpr static DomType kindValue = DomType::Pragma; |
| 347 | |
| 348 | Pragma(const QString &pragmaName = QString(), const QStringList &pragmaValues = {}) |
| 349 | : name(pragmaName), values{ pragmaValues } |
| 350 | { |
| 351 | } |
| 352 | |
| 353 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
| 354 | { |
| 355 | bool cont = self.dvValueField(visitor, f: Fields::name, value: name); |
| 356 | cont = cont && self.dvValueField(visitor, f: Fields::values, value: values); |
| 357 | cont = cont && self.dvWrapField(visitor, f: Fields::comments, obj: comments); |
| 358 | return cont; |
| 359 | } |
| 360 | |
| 361 | void writeOut(const DomItem &self, OutWriter &ow) const; |
| 362 | |
| 363 | QString name; |
| 364 | QStringList values; |
| 365 | RegionComments ; |
| 366 | }; |
| 367 | |
| 368 | class QMLDOM_EXPORT Id |
| 369 | { |
| 370 | public: |
| 371 | constexpr static DomType kindValue = DomType::Id; |
| 372 | |
| 373 | Id(const QString &idName = QString(), const Path &referredObject = Path()); |
| 374 | |
| 375 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; |
| 376 | void updatePathFromOwner(const Path &pathFromOwner); |
| 377 | Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &ann, QmlObject **aPtr = nullptr); |
| 378 | |
| 379 | QString name; |
| 380 | Path referredObjectPath; |
| 381 | RegionComments ; |
| 382 | QList<QmlObject> annotations; |
| 383 | std::shared_ptr<ScriptExpression> value; |
| 384 | }; |
| 385 | |
| 386 | // TODO: rename? it may contain statements and stuff, not only expressions |
| 387 | // TODO QTBUG-121933 |
| 388 | class QMLDOM_EXPORT ScriptExpression final : public OwningItem |
| 389 | { |
| 390 | Q_GADGET |
| 391 | Q_DECLARE_TR_FUNCTIONS(ScriptExpression) |
| 392 | public: |
| 393 | enum class ExpressionType { |
| 394 | BindingExpression, |
| 395 | FunctionBody, |
| 396 | ArgInitializer, |
| 397 | ArgumentStructure, |
| 398 | ReturnType, |
| 399 | JSCode, // Used for storing the content of the whole .js file as "one" Expression |
| 400 | ESMCode, // Used for storing the content of the whole ECMAScript module (.mjs) as "one" |
| 401 | // Expression |
| 402 | }; |
| 403 | Q_ENUM(ExpressionType); |
| 404 | constexpr static DomType kindValue = DomType::ScriptExpression; |
| 405 | DomType kind() const override { return kindValue; } |
| 406 | |
| 407 | explicit ( |
| 408 | QStringView code, const std::shared_ptr<QQmlJS::Engine> &engine, AST::Node *ast, |
| 409 | const std::shared_ptr<AstComments> &, ExpressionType expressionType, |
| 410 | SourceLocation localOffset = SourceLocation(), int derivedFrom = 0, |
| 411 | QStringView preCode = QStringView(), QStringView postCode = QStringView()); |
| 412 | |
| 413 | ScriptExpression() |
| 414 | : ScriptExpression(QStringView(), std::shared_ptr<QQmlJS::Engine>(), nullptr, |
| 415 | std::shared_ptr<AstComments>(), ExpressionType::BindingExpression, |
| 416 | SourceLocation(), 0) |
| 417 | { |
| 418 | } |
| 419 | |
| 420 | explicit ScriptExpression( |
| 421 | const QString &code, ExpressionType expressionType, int derivedFrom = 0, |
| 422 | const QString &preCode = QString(), const QString &postCode = QString()) |
| 423 | : OwningItem(derivedFrom), m_expressionType(expressionType) |
| 424 | { |
| 425 | setCode(code, preCode, postCode); |
| 426 | } |
| 427 | |
| 428 | ScriptExpression(const ScriptExpression &e); |
| 429 | |
| 430 | std::shared_ptr<ScriptExpression> makeCopy(const DomItem &self) const |
| 431 | { |
| 432 | return std::static_pointer_cast<ScriptExpression>(r: doCopy(self)); |
| 433 | } |
| 434 | |
| 435 | std::shared_ptr<ScriptExpression> copyWithUpdatedCode(const DomItem &self, const QString &code) const; |
| 436 | |
| 437 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override; |
| 438 | |
| 439 | Path canonicalPath(const DomItem &self) const override { return self.m_ownerPath; } |
| 440 | // parsed and created if not available |
| 441 | AST::Node *ast() const { return m_ast; } |
| 442 | // dump of the ast (without locations) |
| 443 | void astDumper(const Sink &s, AstDumperOptions options) const; |
| 444 | QString astRelocatableDump() const; |
| 445 | |
| 446 | // definedSymbols name, value, from |
| 447 | // usedSymbols name, locations |
| 448 | QStringView code() const |
| 449 | { |
| 450 | QMutexLocker l(mutex()); |
| 451 | return m_code; |
| 452 | } |
| 453 | |
| 454 | ExpressionType expressionType() const |
| 455 | { |
| 456 | QMutexLocker l(mutex()); |
| 457 | return m_expressionType; |
| 458 | } |
| 459 | |
| 460 | bool isNull() const |
| 461 | { |
| 462 | QMutexLocker l(mutex()); |
| 463 | return m_code.isNull(); |
| 464 | } |
| 465 | std::shared_ptr<QQmlJS::Engine> engine() const |
| 466 | { |
| 467 | QMutexLocker l(mutex()); |
| 468 | return m_engine; |
| 469 | } |
| 470 | QStringView loc2Str(SourceLocation) const; |
| 471 | std::shared_ptr<AstComments> () const { return m_astComments; } |
| 472 | void writeOut(const DomItem &self, OutWriter &lw) const override; |
| 473 | SourceLocation globalLocation(const DomItem &self) const; |
| 474 | SourceLocation localOffset() const { return m_localOffset; } |
| 475 | QStringView preCode() const { return m_preCode; } |
| 476 | QStringView postCode() const { return m_postCode; } |
| 477 | void setScriptElement(const ScriptElementVariant &p); |
| 478 | ScriptElementVariant scriptElement() { return m_element; } |
| 479 | |
| 480 | protected: |
| 481 | std::shared_ptr<OwningItem> doCopy(const DomItem &) const override |
| 482 | { |
| 483 | return std::make_shared<ScriptExpression>(args: *this); |
| 484 | } |
| 485 | |
| 486 | std::function<SourceLocation(SourceLocation)> locationToGlobalF(const DomItem &self) const |
| 487 | { |
| 488 | SourceLocation loc = globalLocation(self); |
| 489 | return [loc, this](SourceLocation x) { |
| 490 | return SourceLocation(x.offset - m_localOffset.offset + loc.offset, x.length, |
| 491 | x.startLine - m_localOffset.startLine + loc.startLine, |
| 492 | ((x.startLine == m_localOffset.startLine) ? x.startColumn |
| 493 | - m_localOffset.startColumn + loc.startColumn |
| 494 | : x.startColumn)); |
| 495 | }; |
| 496 | } |
| 497 | |
| 498 | SourceLocation locationToLocal(SourceLocation x) const |
| 499 | { |
| 500 | return SourceLocation( |
| 501 | x.offset - m_localOffset.offset, x.length, x.startLine - m_localOffset.startLine, |
| 502 | ((x.startLine == m_localOffset.startLine) |
| 503 | ? x.startColumn - m_localOffset.startColumn |
| 504 | : x.startColumn)); // are line and column 1 based? then we should + 1 |
| 505 | } |
| 506 | |
| 507 | std::function<SourceLocation(SourceLocation)> locationToLocalF(const DomItem &) const |
| 508 | { |
| 509 | return [this](SourceLocation x) { return locationToLocal(x); }; |
| 510 | } |
| 511 | |
| 512 | private: |
| 513 | enum class ParseMode { |
| 514 | QML, |
| 515 | JS, |
| 516 | ESM, // ECMAScript module |
| 517 | }; |
| 518 | |
| 519 | inline ParseMode resolveParseMode() |
| 520 | { |
| 521 | switch (m_expressionType) { |
| 522 | case ExpressionType::BindingExpression: |
| 523 | // unfortunately there are no documentation explaining this resolution |
| 524 | // this was just moved from the original implementation |
| 525 | return ParseMode::QML; |
| 526 | case ExpressionType::ESMCode: |
| 527 | return ParseMode::ESM; |
| 528 | default: |
| 529 | return ParseMode::JS; |
| 530 | } |
| 531 | } |
| 532 | void setCode(const QString &code, const QString &preCode, const QString &postCode); |
| 533 | [[nodiscard]] AST::Node *parse(ParseMode mode); |
| 534 | |
| 535 | ExpressionType m_expressionType; |
| 536 | QString m_codeStr; |
| 537 | QStringView m_code; |
| 538 | QStringView m_preCode; |
| 539 | QStringView m_postCode; |
| 540 | mutable std::shared_ptr<QQmlJS::Engine> m_engine; |
| 541 | mutable AST::Node *m_ast; |
| 542 | std::shared_ptr<AstComments> ; |
| 543 | SourceLocation m_localOffset; |
| 544 | ScriptElementVariant m_element; |
| 545 | }; |
| 546 | |
| 547 | class BindingValue; |
| 548 | |
| 549 | class QMLDOM_EXPORT Binding |
| 550 | { |
| 551 | public: |
| 552 | constexpr static DomType kindValue = DomType::Binding; |
| 553 | |
| 554 | Binding(const QString &m_name = QString()); |
| 555 | Binding(const QString &m_name, std::unique_ptr<BindingValue> value, |
| 556 | BindingType bindingType = BindingType::Normal); |
| 557 | Binding(const QString &m_name, const std::shared_ptr<ScriptExpression> &value, |
| 558 | BindingType bindingType = BindingType::Normal); |
| 559 | Binding(const QString &m_name, const QString &scriptCode, |
| 560 | BindingType bindingType = BindingType::Normal); |
| 561 | Binding(const QString &m_name, const QmlObject &value, |
| 562 | BindingType bindingType = BindingType::Normal); |
| 563 | Binding(const QString &m_name, const QList<QmlObject> &value, |
| 564 | BindingType bindingType = BindingType::Normal); |
| 565 | Binding(const Binding &o); |
| 566 | Binding(Binding &&o) = default; |
| 567 | ~Binding(); |
| 568 | Binding &operator=(const Binding &); |
| 569 | Binding &operator=(Binding &&) = default; |
| 570 | |
| 571 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const; |
| 572 | DomItem valueItem(const DomItem &self) const; // ### REVISIT: consider replacing return value with variant |
| 573 | BindingValueKind valueKind() const; |
| 574 | QString name() const { return m_name; } |
| 575 | BindingType bindingType() const { return m_bindingType; } |
| 576 | QmlObject const *objectValue() const; |
| 577 | QList<QmlObject> const *arrayValue() const; |
| 578 | std::shared_ptr<ScriptExpression> scriptExpressionValue() const; |
| 579 | QmlObject *objectValue(); |
| 580 | QList<QmlObject> *arrayValue(); |
| 581 | std::shared_ptr<ScriptExpression> scriptExpressionValue(); |
| 582 | QList<QmlObject> annotations() const { return m_annotations; } |
| 583 | void setAnnotations(const QList<QmlObject> &annotations) { m_annotations = annotations; } |
| 584 | void setValue(std::unique_ptr<BindingValue> &&value); |
| 585 | Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &a, QmlObject **aPtr = nullptr); |
| 586 | const RegionComments &() const { return m_comments; } |
| 587 | RegionComments &() { return m_comments; } |
| 588 | void updatePathFromOwner(const Path &newPath); |
| 589 | void writeOut(const DomItem &self, OutWriter &lw) const; |
| 590 | void writeOutValue(const DomItem &self, OutWriter &lw) const; |
| 591 | bool isSignalHandler() const |
| 592 | { |
| 593 | QString baseName = m_name.split(sep: QLatin1Char('.')).last(); |
| 594 | return QQmlSignalNames::isHandlerName(signalName: baseName); |
| 595 | } |
| 596 | static QString preCodeForName(QStringView n) |
| 597 | { |
| 598 | return QStringLiteral(u"QtObject{\n %1: " ).arg(a: n.split(sep: u'.').last()); |
| 599 | } |
| 600 | static QString postCodeForName(QStringView) { return QStringLiteral(u"\n}\n" ); } |
| 601 | QString preCode() const { return preCodeForName(n: m_name); } |
| 602 | QString postCode() const { return postCodeForName(m_name); } |
| 603 | |
| 604 | ScriptElementVariant bindingIdentifiers() const { return m_bindingIdentifiers; } |
| 605 | void setBindingIdentifiers(const ScriptElementVariant &bindingIdentifiers) { m_bindingIdentifiers = bindingIdentifiers; } |
| 606 | |
| 607 | private: |
| 608 | friend class QQmlDomAstCreator; |
| 609 | BindingType m_bindingType; |
| 610 | QString m_name; |
| 611 | std::unique_ptr<BindingValue> m_value; |
| 612 | QList<QmlObject> m_annotations; |
| 613 | RegionComments ; |
| 614 | ScriptElementVariant m_bindingIdentifiers; |
| 615 | }; |
| 616 | |
| 617 | class QMLDOM_EXPORT AttributeInfo |
| 618 | { |
| 619 | public: |
| 620 | enum Access { Private, Protected, Public }; |
| 621 | |
| 622 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
| 623 | |
| 624 | Path addAnnotation(const Path &selfPathFromOwner, const QmlObject &annotation, |
| 625 | QmlObject **aPtr = nullptr); |
| 626 | void updatePathFromOwner(const Path &newPath); |
| 627 | |
| 628 | QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; } |
| 629 | void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; } |
| 630 | |
| 631 | QString name; |
| 632 | Access access = Access::Public; |
| 633 | QString typeName; |
| 634 | bool isReadonly = false; |
| 635 | bool isList = false; |
| 636 | QList<QmlObject> annotations; |
| 637 | RegionComments ; |
| 638 | QQmlJSScope::ConstPtr m_semanticScope; |
| 639 | }; |
| 640 | |
| 641 | struct QMLDOM_EXPORT LocallyResolvedAlias |
| 642 | { |
| 643 | enum class Status { Invalid, ResolvedProperty, ResolvedObject, Loop, TooDeep }; |
| 644 | bool valid() |
| 645 | { |
| 646 | switch (status) { |
| 647 | case Status::ResolvedProperty: |
| 648 | case Status::ResolvedObject: |
| 649 | return true; |
| 650 | default: |
| 651 | return false; |
| 652 | } |
| 653 | } |
| 654 | DomItem baseObject; |
| 655 | DomItem localPropertyDef; |
| 656 | QString typeName; |
| 657 | QStringList accessedPath; |
| 658 | Status status = Status::Invalid; |
| 659 | int nAliases = 0; |
| 660 | }; |
| 661 | |
| 662 | class QMLDOM_EXPORT PropertyDefinition : public AttributeInfo |
| 663 | { |
| 664 | public: |
| 665 | constexpr static DomType kindValue = DomType::PropertyDefinition; |
| 666 | |
| 667 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
| 668 | { |
| 669 | bool cont = AttributeInfo::iterateDirectSubpaths(self, visitor); |
| 670 | cont = cont && self.dvValueField(visitor, f: Fields::isPointer, value: isPointer); |
| 671 | cont = cont && self.dvValueField(visitor, f: Fields::isFinal, value: isFinal); |
| 672 | cont = cont && self.dvValueField(visitor, f: Fields::isAlias, value: isAlias()); |
| 673 | cont = cont && self.dvValueField(visitor, f: Fields::isDefaultMember, value: isDefaultMember); |
| 674 | cont = cont && self.dvValueField(visitor, f: Fields::isRequired, value: isRequired); |
| 675 | cont = cont && self.dvValueField(visitor, f: Fields::read, value: read); |
| 676 | cont = cont && self.dvValueField(visitor, f: Fields::write, value: write); |
| 677 | cont = cont && self.dvValueField(visitor, f: Fields::bindable, value: bindable); |
| 678 | cont = cont && self.dvValueField(visitor, f: Fields::notify, value: notify); |
| 679 | cont = cont && self.dvReferenceField(visitor, f: Fields::type, referencedObject: typePath()); |
| 680 | if (m_nameIdentifiers) { |
| 681 | cont = cont && self.dvItemField(visitor, f: Fields::nameIdentifiers, it: [this, &self]() { |
| 682 | return self.subScriptElementWrapperItem(obj: m_nameIdentifiers); |
| 683 | }); |
| 684 | } |
| 685 | return cont; |
| 686 | } |
| 687 | |
| 688 | Path typePath() const { return Paths::lookupTypePath(name: typeName); } |
| 689 | |
| 690 | bool isAlias() const { return typeName == u"alias" ; } |
| 691 | bool isParametricType() const; |
| 692 | void writeOut(const DomItem &self, OutWriter &lw) const; |
| 693 | ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; } |
| 694 | void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; } |
| 695 | |
| 696 | QString read; |
| 697 | QString write; |
| 698 | QString bindable; |
| 699 | QString notify; |
| 700 | bool isFinal = false; |
| 701 | bool isPointer = false; |
| 702 | bool isDefaultMember = false; |
| 703 | bool isRequired = false; |
| 704 | ScriptElementVariant m_nameIdentifiers; |
| 705 | }; |
| 706 | |
| 707 | class QMLDOM_EXPORT PropertyInfo |
| 708 | { |
| 709 | public: |
| 710 | constexpr static DomType kindValue = DomType::PropertyInfo; // used to get the correct kind in ObjectWrapper |
| 711 | |
| 712 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
| 713 | |
| 714 | QList<DomItem> propertyDefs; |
| 715 | QList<DomItem> bindings; |
| 716 | }; |
| 717 | |
| 718 | class QMLDOM_EXPORT MethodParameter |
| 719 | { |
| 720 | public: |
| 721 | constexpr static DomType kindValue = DomType::MethodParameter; |
| 722 | enum class TypeAnnotationStyle { |
| 723 | Prefix, // a(int x) |
| 724 | Suffix, // a(x : int) |
| 725 | }; |
| 726 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
| 727 | |
| 728 | void writeOut(const DomItem &self, OutWriter &ow) const; |
| 729 | void writeOutSignal(const DomItem &self, OutWriter &ow) const; |
| 730 | |
| 731 | QString name; |
| 732 | QString typeName; |
| 733 | bool isPointer = false; |
| 734 | bool isReadonly = false; |
| 735 | bool isList = false; |
| 736 | bool isRestElement = false; |
| 737 | std::shared_ptr<ScriptExpression> defaultValue; |
| 738 | /*! |
| 739 | \internal |
| 740 | Contains the scriptElement representing this argument, inclusive default value, |
| 741 | deconstruction, etc. |
| 742 | */ |
| 743 | std::shared_ptr<ScriptExpression> value; |
| 744 | QList<QmlObject> annotations; |
| 745 | RegionComments ; |
| 746 | TypeAnnotationStyle typeAnnotationStyle = TypeAnnotationStyle::Suffix; |
| 747 | }; |
| 748 | |
| 749 | // TODO (QTBUG-128423) |
| 750 | // Refactor to differentiate between Signals and Methods easily, |
| 751 | // considering their distinct handling and formatting needs. |
| 752 | // Explore separating Signal functionality or unifying shared methods. |
| 753 | class QMLDOM_EXPORT MethodInfo : public AttributeInfo |
| 754 | { |
| 755 | Q_GADGET |
| 756 | public: |
| 757 | enum MethodType { Signal, Method }; |
| 758 | Q_ENUM(MethodType) |
| 759 | |
| 760 | constexpr static DomType kindValue = DomType::MethodInfo; |
| 761 | |
| 762 | Path typePath(const DomItem &) const |
| 763 | { |
| 764 | return (typeName.isEmpty() ? Path() : Paths::lookupTypePath(name: typeName)); |
| 765 | } |
| 766 | |
| 767 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
| 768 | QString preCode(const DomItem &) const; // ### REVISIT, might be simplified by using different toplevel production rules at usage site |
| 769 | QString postCode(const DomItem &) const; |
| 770 | void writePre(const DomItem &self, OutWriter &ow) const; |
| 771 | void writeOut(const DomItem &self, OutWriter &ow) const; |
| 772 | QString signature(const DomItem &self) const; |
| 773 | |
| 774 | void setCode(const QString &code) |
| 775 | { |
| 776 | body = std::make_shared<ScriptExpression>( |
| 777 | args: code, args: ScriptExpression::ExpressionType::FunctionBody, args: 0, |
| 778 | args: QLatin1String("function foo(){\n" ), args: QLatin1String("\n}\n" )); |
| 779 | } |
| 780 | MethodInfo() = default; |
| 781 | |
| 782 | // TODO: make private + add getters/setters |
| 783 | QList<MethodParameter> parameters; |
| 784 | MethodType methodType = Method; |
| 785 | std::shared_ptr<ScriptExpression> body; |
| 786 | std::shared_ptr<ScriptExpression> returnType; |
| 787 | bool isConstructor = false; |
| 788 | |
| 789 | private: |
| 790 | void writeOutArguments(const DomItem &self, OutWriter &ow) const; |
| 791 | void writeOutReturnType(OutWriter &ow) const; |
| 792 | void writeOutBody(const DomItem &self, OutWriter &ow) const; |
| 793 | }; |
| 794 | |
| 795 | class QMLDOM_EXPORT EnumItem |
| 796 | { |
| 797 | public: |
| 798 | constexpr static DomType kindValue = DomType::EnumItem; |
| 799 | enum class ValueKind : quint8 { |
| 800 | ImplicitValue, |
| 801 | ExplicitValue |
| 802 | }; |
| 803 | EnumItem(const QString &name = QString(), int value = 0, ValueKind valueKind = ValueKind::ImplicitValue) |
| 804 | : m_name(name), m_value(value), m_valueKind(valueKind) |
| 805 | { |
| 806 | } |
| 807 | |
| 808 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
| 809 | |
| 810 | QString name() const { return m_name; } |
| 811 | double value() const { return m_value; } |
| 812 | RegionComments &() { return m_comments; } |
| 813 | const RegionComments &() const { return m_comments; } |
| 814 | void writeOut(const DomItem &self, OutWriter &lw) const; |
| 815 | |
| 816 | private: |
| 817 | QString m_name; |
| 818 | double m_value; |
| 819 | ValueKind m_valueKind; |
| 820 | RegionComments ; |
| 821 | }; |
| 822 | |
| 823 | class QMLDOM_EXPORT EnumDecl final : public CommentableDomElement |
| 824 | { |
| 825 | public: |
| 826 | constexpr static DomType kindValue = DomType::EnumDecl; |
| 827 | DomType kind() const override { return kindValue; } |
| 828 | |
| 829 | EnumDecl(const QString &name = QString(), QList<EnumItem> values = QList<EnumItem>(), |
| 830 | Path pathFromOwner = Path()) |
| 831 | : CommentableDomElement(pathFromOwner), m_name(name), m_values(values) |
| 832 | { |
| 833 | } |
| 834 | |
| 835 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const override; |
| 836 | |
| 837 | QString name() const { return m_name; } |
| 838 | void setName(const QString &name) { m_name = name; } |
| 839 | const QList<EnumItem> &values() const & { return m_values; } |
| 840 | bool isFlag() const { return m_isFlag; } |
| 841 | void setIsFlag(bool flag) { m_isFlag = flag; } |
| 842 | QString alias() const { return m_alias; } |
| 843 | void setAlias(const QString &aliasName) { m_alias = aliasName; } |
| 844 | void setValues(QList<EnumItem> values) { m_values = values; } |
| 845 | Path addValue(EnumItem value) |
| 846 | { |
| 847 | m_values.append(t: value); |
| 848 | return Path::fromField(s: Fields::values).withIndex(i: index_type(m_values.size() - 1)); |
| 849 | } |
| 850 | void updatePathFromOwner(const Path &newP) override; |
| 851 | |
| 852 | const QList<QmlObject> &annotations() const & { return m_annotations; } |
| 853 | void setAnnotations(const QList<QmlObject> &annotations); |
| 854 | Path addAnnotation(const QmlObject &child, QmlObject **cPtr = nullptr); |
| 855 | void writeOut(const DomItem &self, OutWriter &lw) const override; |
| 856 | |
| 857 | private: |
| 858 | QString m_name; |
| 859 | bool m_isFlag = false; |
| 860 | QString m_alias; |
| 861 | QList<EnumItem> m_values; |
| 862 | QList<QmlObject> m_annotations; |
| 863 | }; |
| 864 | |
| 865 | class QMLDOM_EXPORT QmlObject final : public CommentableDomElement |
| 866 | { |
| 867 | Q_DECLARE_TR_FUNCTIONS(QmlObject) |
| 868 | public: |
| 869 | constexpr static DomType kindValue = DomType::QmlObject; |
| 870 | DomType kind() const override { return kindValue; } |
| 871 | |
| 872 | QmlObject(const Path &pathFromOwner = Path()); |
| 873 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; |
| 874 | bool iterateBaseDirectSubpaths(const DomItem &self, DirectVisitor) const; |
| 875 | QList<QString> fields() const; |
| 876 | QList<QString> fields(const DomItem &) const override { return fields(); } |
| 877 | DomItem field(const DomItem &self, QStringView name) const override; |
| 878 | void updatePathFromOwner(const Path &newPath) override; |
| 879 | QString localDefaultPropertyName() const; |
| 880 | QString defaultPropertyName(const DomItem &self) const; |
| 881 | virtual bool iterateSubOwners(const DomItem &self, function_ref<bool(const DomItem &owner)> visitor) const; |
| 882 | |
| 883 | QString idStr() const { return m_idStr; } |
| 884 | QString name() const { return m_name; } |
| 885 | const QList<Path> &prototypePaths() const & { return m_prototypePaths; } |
| 886 | Path nextScopePath() const { return m_nextScopePath; } |
| 887 | const QMultiMap<QString, PropertyDefinition> &propertyDefs() const & { return m_propertyDefs; } |
| 888 | const QMultiMap<QString, Binding> &bindings() const & { return m_bindings; } |
| 889 | const QMultiMap<QString, MethodInfo> &methods() const & { return m_methods; } |
| 890 | QList<QmlObject> children() const { return m_children; } |
| 891 | QList<QmlObject> annotations() const { return m_annotations; } |
| 892 | |
| 893 | void setIdStr(const QString &id) { m_idStr = id; } |
| 894 | void setName(const QString &name) { m_name = name; } |
| 895 | void setDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; } |
| 896 | void setPrototypePaths(QList<Path> prototypePaths) { m_prototypePaths = prototypePaths; } |
| 897 | Path addPrototypePath(const Path &prototypePath) |
| 898 | { |
| 899 | index_type idx = index_type(m_prototypePaths.indexOf(t: prototypePath)); |
| 900 | if (idx == -1) { |
| 901 | idx = index_type(m_prototypePaths.size()); |
| 902 | m_prototypePaths.append(t: prototypePath); |
| 903 | } |
| 904 | return Path::fromField(s: Fields::prototypes).withIndex(i: idx); |
| 905 | } |
| 906 | void setNextScopePath(const Path &nextScopePath) { m_nextScopePath = nextScopePath; } |
| 907 | void setPropertyDefs(QMultiMap<QString, PropertyDefinition> propertyDefs) |
| 908 | { |
| 909 | m_propertyDefs = propertyDefs; |
| 910 | } |
| 911 | void setBindings(QMultiMap<QString, Binding> bindings) { m_bindings = bindings; } |
| 912 | void setMethods(QMultiMap<QString, MethodInfo> functionDefs) { m_methods = functionDefs; } |
| 913 | void setChildren(const QList<QmlObject> &children) |
| 914 | { |
| 915 | m_children = children; |
| 916 | if (pathFromOwner()) |
| 917 | updatePathFromOwner(newPath: pathFromOwner()); |
| 918 | } |
| 919 | void setAnnotations(const QList<QmlObject> &annotations) |
| 920 | { |
| 921 | m_annotations = annotations; |
| 922 | if (pathFromOwner()) |
| 923 | updatePathFromOwner(newPath: pathFromOwner()); |
| 924 | } |
| 925 | Path addPropertyDef(const PropertyDefinition &propertyDef, AddOption option, |
| 926 | PropertyDefinition **pDef = nullptr) |
| 927 | { |
| 928 | return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().withField(name: Fields::propertyDefs), |
| 929 | mmap&: m_propertyDefs, key: propertyDef.name, value: propertyDef, |
| 930 | option, valuePtr: pDef); |
| 931 | } |
| 932 | MutableDomItem addPropertyDef(MutableDomItem &self, const PropertyDefinition &propertyDef, |
| 933 | AddOption option); |
| 934 | |
| 935 | Path addBinding(Binding binding, AddOption option, Binding **bPtr = nullptr) |
| 936 | { |
| 937 | return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().withField(name: Fields::bindings), mmap&: m_bindings, |
| 938 | key: binding.name(), value: binding, option, valuePtr: bPtr); |
| 939 | } |
| 940 | MutableDomItem addBinding(MutableDomItem &self, Binding binding, AddOption option); |
| 941 | Path addMethod(const MethodInfo &functionDef, AddOption option, MethodInfo **mPtr = nullptr) |
| 942 | { |
| 943 | return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().withField(name: Fields::methods), mmap&: m_methods, |
| 944 | key: functionDef.name, value: functionDef, option, valuePtr: mPtr); |
| 945 | } |
| 946 | MutableDomItem addMethod(MutableDomItem &self, const MethodInfo &functionDef, AddOption option); |
| 947 | Path addChild(QmlObject child, QmlObject **cPtr = nullptr) |
| 948 | { |
| 949 | return appendUpdatableElementInQList(listPathFromOwner: pathFromOwner().withField(name: Fields::children), list&: m_children, |
| 950 | value: child, vPtr: cPtr); |
| 951 | } |
| 952 | MutableDomItem addChild(MutableDomItem &self, QmlObject child) |
| 953 | { |
| 954 | Path p = addChild(child); |
| 955 | return MutableDomItem(self.owner().item(), p); |
| 956 | } |
| 957 | Path addAnnotation(const QmlObject &annotation, QmlObject **aPtr = nullptr) |
| 958 | { |
| 959 | return appendUpdatableElementInQList(listPathFromOwner: pathFromOwner().withField(name: Fields::annotations), |
| 960 | list&: m_annotations, value: annotation, vPtr: aPtr); |
| 961 | } |
| 962 | |
| 963 | QList<std::pair<SourceLocation, DomItem>> orderOfAttributes(const DomItem &self, |
| 964 | const DomItem &component) const; |
| 965 | void writeOutAttributes(const DomItem &self, OutWriter &ow, const DomItem &component, |
| 966 | const QString &code) const; |
| 967 | |
| 968 | void writeOutSortedEnumerations(const DomItem &component, OutWriter &ow) const; |
| 969 | void writeOutSortedAttributes(const DomItem &self, OutWriter &ow, |
| 970 | const DomItem &component) const; |
| 971 | void writeOutSortedPropertyDefinition(const DomItem &self, OutWriter &ow, |
| 972 | QSet<QString> &mergedDefBinding) const; |
| 973 | |
| 974 | void writeOutId(const DomItem &self, OutWriter &ow) const; |
| 975 | void writeOut(const DomItem &self, OutWriter &ow, const QString &onTarget) const; |
| 976 | void writeOut(const DomItem &self, OutWriter &lw) const override { writeOut(self, ow&: lw, onTarget: QString()); } |
| 977 | |
| 978 | LocallyResolvedAlias resolveAlias(const DomItem &self, |
| 979 | std::shared_ptr<ScriptExpression> accessSequence) const; |
| 980 | LocallyResolvedAlias resolveAlias(const DomItem &self, const QStringList &accessSequence) const; |
| 981 | |
| 982 | QQmlJSScope::ConstPtr semanticScope() const { return m_scope; } |
| 983 | void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_scope = scope; } |
| 984 | |
| 985 | ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; } |
| 986 | void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; } |
| 987 | |
| 988 | private: |
| 989 | friend class QQmlDomAstCreator; |
| 990 | QString m_idStr; |
| 991 | QString m_name; |
| 992 | QList<Path> m_prototypePaths; |
| 993 | Path m_nextScopePath; |
| 994 | QString m_defaultPropertyName; |
| 995 | QMultiMap<QString, PropertyDefinition> m_propertyDefs; |
| 996 | QMultiMap<QString, Binding> m_bindings; |
| 997 | QMultiMap<QString, MethodInfo> m_methods; |
| 998 | QList<QmlObject> m_children; |
| 999 | QList<QmlObject> m_annotations; |
| 1000 | QQmlJSScope::ConstPtr m_scope; |
| 1001 | ScriptElementVariant m_nameIdentifiers; |
| 1002 | |
| 1003 | static constexpr quint32 posOfNewElements = std::numeric_limits<quint32>::max(); |
| 1004 | }; |
| 1005 | |
| 1006 | class Export |
| 1007 | { |
| 1008 | Q_DECLARE_TR_FUNCTIONS(Export) |
| 1009 | public: |
| 1010 | constexpr static DomType kindValue = DomType::Export; |
| 1011 | static Export fromString( |
| 1012 | const Path &source, QStringView exp, const Path &typePath, const ErrorHandler &h); |
| 1013 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const |
| 1014 | { |
| 1015 | bool cont = true; |
| 1016 | cont = cont && self.dvValueField(visitor, f: Fields::uri, value: uri); |
| 1017 | cont = cont && self.dvValueField(visitor, f: Fields::typeName, value: typeName); |
| 1018 | cont = cont && self.dvWrapField(visitor, f: Fields::version, obj: version); |
| 1019 | if (typePath) |
| 1020 | cont = cont && self.dvReferenceField(visitor, f: Fields::type, referencedObject: typePath); |
| 1021 | cont = cont && self.dvValueField(visitor, f: Fields::isInternal, value: isInternal); |
| 1022 | cont = cont && self.dvValueField(visitor, f: Fields::isSingleton, value: isSingleton); |
| 1023 | if (exportSourcePath) |
| 1024 | cont = cont && self.dvReferenceField(visitor, f: Fields::exportSource, referencedObject: exportSourcePath); |
| 1025 | return cont; |
| 1026 | } |
| 1027 | |
| 1028 | Path exportSourcePath; |
| 1029 | QString uri; |
| 1030 | QString typeName; |
| 1031 | Version version; |
| 1032 | Path typePath; |
| 1033 | bool isInternal = false; |
| 1034 | bool isSingleton = false; |
| 1035 | }; |
| 1036 | |
| 1037 | class QMLDOM_EXPORT Component : public CommentableDomElement |
| 1038 | { |
| 1039 | public: |
| 1040 | Component(const QString &name); |
| 1041 | Component(const Path &pathFromOwner = Path()); |
| 1042 | Component(const Component &o) = default; |
| 1043 | Component &operator=(const Component &) = default; |
| 1044 | |
| 1045 | bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override; |
| 1046 | void updatePathFromOwner(const Path &newPath) override; |
| 1047 | DomItem field(const DomItem &self, QStringView name) const override; |
| 1048 | |
| 1049 | QString name() const { return m_name; } |
| 1050 | const QMultiMap<QString, EnumDecl> &enumerations() const & { return m_enumerations; } |
| 1051 | const QList<QmlObject> &objects() const & { return m_objects; } |
| 1052 | bool isSingleton() const { return m_isSingleton; } |
| 1053 | bool isCreatable() const { return m_isCreatable; } |
| 1054 | bool isComposite() const { return m_isComposite; } |
| 1055 | QString attachedTypeName() const { return m_attachedTypeName; } |
| 1056 | Path attachedTypePath(const DomItem &) const { return m_attachedTypePath; } |
| 1057 | |
| 1058 | void setName(const QString &name) { m_name = name; } |
| 1059 | void setEnumerations(QMultiMap<QString, EnumDecl> enumerations) |
| 1060 | { |
| 1061 | m_enumerations = enumerations; |
| 1062 | } |
| 1063 | Path addEnumeration(const EnumDecl &enumeration, AddOption option = AddOption::Overwrite, |
| 1064 | EnumDecl **ePtr = nullptr) |
| 1065 | { |
| 1066 | return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().withField(name: Fields::enumerations), |
| 1067 | mmap&: m_enumerations, key: enumeration.name(), value: enumeration, |
| 1068 | option, valuePtr: ePtr); |
| 1069 | } |
| 1070 | void setObjects(const QList<QmlObject> &objects) { m_objects = objects; } |
| 1071 | Path addObject(const QmlObject &object, QmlObject **oPtr = nullptr); |
| 1072 | void setIsSingleton(bool isSingleton) { m_isSingleton = isSingleton; } |
| 1073 | void setIsCreatable(bool isCreatable) { m_isCreatable = isCreatable; } |
| 1074 | void setIsComposite(bool isComposite) { m_isComposite = isComposite; } |
| 1075 | void setAttachedTypeName(const QString &name) { m_attachedTypeName = name; } |
| 1076 | void setAttachedTypePath(const Path &p) { m_attachedTypePath = p; } |
| 1077 | |
| 1078 | private: |
| 1079 | friend class QQmlDomAstCreator; |
| 1080 | QString m_name; |
| 1081 | QMultiMap<QString, EnumDecl> m_enumerations; |
| 1082 | QList<QmlObject> m_objects; |
| 1083 | bool m_isSingleton = false; |
| 1084 | bool m_isCreatable = true; |
| 1085 | bool m_isComposite = true; |
| 1086 | QString m_attachedTypeName; |
| 1087 | Path m_attachedTypePath; |
| 1088 | }; |
| 1089 | |
| 1090 | class QMLDOM_EXPORT JsResource final : public Component |
| 1091 | { |
| 1092 | public: |
| 1093 | constexpr static DomType kindValue = DomType::JsResource; |
| 1094 | DomType kind() const override { return kindValue; } |
| 1095 | |
| 1096 | JsResource(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { } |
| 1097 | bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override |
| 1098 | { // to do: complete |
| 1099 | return true; |
| 1100 | } |
| 1101 | // globalSymbols defined/exported, required/used |
| 1102 | }; |
| 1103 | |
| 1104 | class QMLDOM_EXPORT QmltypesComponent final : public Component |
| 1105 | { |
| 1106 | public: |
| 1107 | constexpr static DomType kindValue = DomType::QmltypesComponent; |
| 1108 | DomType kind() const override { return kindValue; } |
| 1109 | |
| 1110 | QmltypesComponent(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { } |
| 1111 | bool iterateDirectSubpaths(const DomItem &, DirectVisitor) const override; |
| 1112 | const QList<Export> &exports() const & { return m_exports; } |
| 1113 | QString fileName() const { return m_fileName; } |
| 1114 | void setExports(QList<Export> exports) { m_exports = exports; } |
| 1115 | void addExport(const Export &exportedEntry) { m_exports.append(t: exportedEntry); } |
| 1116 | void setFileName(const QString &fileName) { m_fileName = fileName; } |
| 1117 | const QList<int> &metaRevisions() const & { return m_metaRevisions; } |
| 1118 | void setMetaRevisions(QList<int> metaRevisions) { m_metaRevisions = metaRevisions; } |
| 1119 | void setInterfaceNames(const QStringList& interfaces) { m_interfaceNames = interfaces; } |
| 1120 | const QStringList &interfaceNames() const & { return m_interfaceNames; } |
| 1121 | QString extensionTypeName() const { return m_extensionTypeName; } |
| 1122 | void setExtensionTypeName(const QString &name) { m_extensionTypeName = name; } |
| 1123 | QString valueTypeName() const { return m_valueTypeName; } |
| 1124 | void setValueTypeName(const QString &name) { m_valueTypeName = name; } |
| 1125 | bool hasCustomParser() const { return m_hasCustomParser; } |
| 1126 | void setHasCustomParser(bool v) { m_hasCustomParser = v; } |
| 1127 | bool extensionIsJavaScript() const { return m_extensionIsJavaScript; } |
| 1128 | void setExtensionIsJavaScript(bool v) { m_extensionIsJavaScript = v; } |
| 1129 | bool extensionIsNamespace() const { return m_extensionIsNamespace; } |
| 1130 | void setExtensionIsNamespace(bool v) { m_extensionIsNamespace = v; } |
| 1131 | QQmlJSScope::AccessSemantics accessSemantics() const { return m_accessSemantics; } |
| 1132 | void setAccessSemantics(QQmlJSScope::AccessSemantics v) { m_accessSemantics = v; } |
| 1133 | |
| 1134 | void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; } |
| 1135 | QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; } |
| 1136 | |
| 1137 | private: |
| 1138 | QList<Export> m_exports; |
| 1139 | QList<int> m_metaRevisions; |
| 1140 | QString m_fileName; // remove? |
| 1141 | QStringList m_interfaceNames; |
| 1142 | bool m_hasCustomParser = false; |
| 1143 | bool m_extensionIsJavaScript = false; |
| 1144 | bool m_extensionIsNamespace = false; |
| 1145 | QString m_valueTypeName; |
| 1146 | QString m_extensionTypeName; |
| 1147 | QQmlJSScope::AccessSemantics m_accessSemantics = QQmlJSScope::AccessSemantics::None; |
| 1148 | QQmlJSScope::ConstPtr m_semanticScope; |
| 1149 | }; |
| 1150 | |
| 1151 | class QMLDOM_EXPORT QmlComponent final : public Component |
| 1152 | { |
| 1153 | public: |
| 1154 | constexpr static DomType kindValue = DomType::QmlComponent; |
| 1155 | DomType kind() const override { return kindValue; } |
| 1156 | |
| 1157 | QmlComponent(const QString &name = QString()) : Component(name) |
| 1158 | { |
| 1159 | setIsComposite(true); |
| 1160 | setIsCreatable(true); |
| 1161 | } |
| 1162 | |
| 1163 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor) const override; |
| 1164 | |
| 1165 | const QMultiMap<QString, Id> &ids() const & { return m_ids; } |
| 1166 | Path nextComponentPath() const { return m_nextComponentPath; } |
| 1167 | void setIds(QMultiMap<QString, Id> ids) { m_ids = ids; } |
| 1168 | void setNextComponentPath(const Path &p) { m_nextComponentPath = p; } |
| 1169 | void updatePathFromOwner(const Path &newPath) override; |
| 1170 | Path addId(const Id &id, AddOption option = AddOption::Overwrite, Id **idPtr = nullptr) |
| 1171 | { |
| 1172 | // warning does nor remove old idStr when overwriting... |
| 1173 | return insertUpdatableElementInMultiMap(mapPathFromOwner: pathFromOwner().withField(name: Fields::ids), mmap&: m_ids, key: id.name, |
| 1174 | value: id, option, valuePtr: idPtr); |
| 1175 | } |
| 1176 | void writeOut(const DomItem &self, OutWriter &) const override; |
| 1177 | QList<QString> subComponentsNames(const DomItem &self) const; |
| 1178 | QList<DomItem> subComponents(const DomItem &self) const; |
| 1179 | |
| 1180 | void setSemanticScope(const QQmlJSScope::ConstPtr &scope) { m_semanticScope = scope; } |
| 1181 | QQmlJSScope::ConstPtr semanticScope() const { return m_semanticScope; } |
| 1182 | ScriptElementVariant nameIdentifiers() const { return m_nameIdentifiers; } |
| 1183 | void setNameIdentifiers(const ScriptElementVariant &name) { m_nameIdentifiers = name; } |
| 1184 | |
| 1185 | private: |
| 1186 | friend class QQmlDomAstCreator; |
| 1187 | Path m_nextComponentPath; |
| 1188 | QMultiMap<QString, Id> m_ids; |
| 1189 | QQmlJSScope::ConstPtr m_semanticScope; |
| 1190 | // m_nameIdentifiers contains the name of the component as FieldMemberExpression, and therefore |
| 1191 | // only exists in inline components! |
| 1192 | ScriptElementVariant m_nameIdentifiers; |
| 1193 | }; |
| 1194 | |
| 1195 | class QMLDOM_EXPORT GlobalComponent final : public Component |
| 1196 | { |
| 1197 | public: |
| 1198 | constexpr static DomType kindValue = DomType::GlobalComponent; |
| 1199 | DomType kind() const override { return kindValue; } |
| 1200 | |
| 1201 | GlobalComponent(const Path &pathFromOwner = Path()) : Component(pathFromOwner) { } |
| 1202 | }; |
| 1203 | |
| 1204 | static ErrorGroups importErrors = { .groups: { DomItem::domErrorGroup, NewErrorGroup("importError" ) } }; |
| 1205 | |
| 1206 | class QMLDOM_EXPORT ImportScope |
| 1207 | { |
| 1208 | Q_DECLARE_TR_FUNCTIONS(ImportScope) |
| 1209 | public: |
| 1210 | constexpr static DomType kindValue = DomType::ImportScope; |
| 1211 | |
| 1212 | ImportScope() = default; |
| 1213 | |
| 1214 | const QList<Path> &importSourcePaths() const & { return m_importSourcePaths; } |
| 1215 | |
| 1216 | const QMap<QString, ImportScope> &subImports() const & { return m_subImports; } |
| 1217 | |
| 1218 | QList<Path> allSources(const DomItem &self) const; |
| 1219 | |
| 1220 | QSet<QString> importedNames(const DomItem &self) const |
| 1221 | { |
| 1222 | QSet<QString> res; |
| 1223 | const auto sources = allSources(self); |
| 1224 | for (const Path &p : sources) { |
| 1225 | QSet<QString> ks = self.path(p: p.withField(name: Fields::exports), h: self.errorHandler()).keys(); |
| 1226 | res += ks; |
| 1227 | } |
| 1228 | return res; |
| 1229 | } |
| 1230 | |
| 1231 | QList<DomItem> importedItemsWithName(const DomItem &self, const QString &name) const |
| 1232 | { |
| 1233 | QList<DomItem> res; |
| 1234 | const auto sources = allSources(self); |
| 1235 | for (const Path &p : sources) { |
| 1236 | DomItem source = self.path(p: p.withField(name: Fields::exports), h: self.errorHandler()); |
| 1237 | DomItem els = source.key(name); |
| 1238 | int nEls = els.indexes(); |
| 1239 | for (int i = 0; i < nEls; ++i) |
| 1240 | res.append(t: els.index(i)); |
| 1241 | if (nEls == 0 && els) { |
| 1242 | self.addError(msg: importErrors.warning( |
| 1243 | message: tr(sourceText: "Looking up '%1' expected a list of exports, not %2" ) |
| 1244 | .arg(args: name, args: els.toString()))); |
| 1245 | } |
| 1246 | } |
| 1247 | return res; |
| 1248 | } |
| 1249 | |
| 1250 | QList<Export> importedExportsWithName(const DomItem &self, const QString &name) const |
| 1251 | { |
| 1252 | QList<Export> res; |
| 1253 | for (const DomItem &i : importedItemsWithName(self, name)) |
| 1254 | if (const Export *e = i.as<Export>()) |
| 1255 | res.append(t: *e); |
| 1256 | else |
| 1257 | self.addError(msg: importErrors.warning( |
| 1258 | message: tr(sourceText: "Expected Export looking up '%1', not %2" ).arg(args: name, args: i.toString()))); |
| 1259 | return res; |
| 1260 | } |
| 1261 | |
| 1262 | bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const; |
| 1263 | |
| 1264 | void addImport(QStringList p, const Path &targetExports) |
| 1265 | { |
| 1266 | if (!p.isEmpty()) { |
| 1267 | const QString current = p.takeFirst(); |
| 1268 | m_subImports[current].addImport(p: std::move(p), targetExports); |
| 1269 | } else if (!m_importSourcePaths.contains(t: targetExports)) { |
| 1270 | m_importSourcePaths.append(t: targetExports); |
| 1271 | } |
| 1272 | } |
| 1273 | |
| 1274 | private: |
| 1275 | QList<Path> m_importSourcePaths; |
| 1276 | QMap<QString, ImportScope> m_subImports; |
| 1277 | }; |
| 1278 | |
| 1279 | class BindingValue |
| 1280 | { |
| 1281 | public: |
| 1282 | BindingValue(); |
| 1283 | BindingValue(const QmlObject &o); |
| 1284 | BindingValue(const std::shared_ptr<ScriptExpression> &o); |
| 1285 | BindingValue(const QList<QmlObject> &l); |
| 1286 | ~BindingValue(); |
| 1287 | BindingValue(const BindingValue &o); |
| 1288 | BindingValue &operator=(const BindingValue &o); |
| 1289 | |
| 1290 | DomItem value(const DomItem &binding) const; |
| 1291 | void updatePathFromOwner(const Path &newPath); |
| 1292 | |
| 1293 | private: |
| 1294 | friend class Binding; |
| 1295 | void clearValue(); |
| 1296 | |
| 1297 | BindingValueKind kind; |
| 1298 | union { |
| 1299 | int dummy; |
| 1300 | QmlObject object; |
| 1301 | std::shared_ptr<ScriptExpression> scriptExpression; |
| 1302 | QList<QmlObject> array; |
| 1303 | }; |
| 1304 | }; |
| 1305 | |
| 1306 | } // end namespace Dom |
| 1307 | } // end namespace QQmlJS |
| 1308 | QT_END_NAMESPACE |
| 1309 | #endif // QQMLDOMELEMENTS_P_H |
| 1310 | |