| 1 | // Copyright (C) 2019 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
| 3 | |
| 4 | #ifndef QQMLJSSCOPE_P_H |
| 5 | #define QQMLJSSCOPE_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 | #include <qtqmlcompilerexports.h> |
| 18 | |
| 19 | #include "qqmljsmetatypes_p.h" |
| 20 | #include "qdeferredpointer_p.h" |
| 21 | #include "qqmljsannotation_p.h" |
| 22 | #include "qqmlsaconstants.h" |
| 23 | #include "qqmlsa_p.h" |
| 24 | |
| 25 | #include <QtQml/private/qqmljssourcelocation_p.h> |
| 26 | |
| 27 | #include <QtCore/qfileinfo.h> |
| 28 | #include <QtCore/qhash.h> |
| 29 | #include <QtCore/qset.h> |
| 30 | #include <QtCore/qstring.h> |
| 31 | #include <QtCore/qversionnumber.h> |
| 32 | #include "qqmlsaconstants.h" |
| 33 | |
| 34 | #include <optional> |
| 35 | |
| 36 | QT_BEGIN_NAMESPACE |
| 37 | |
| 38 | class QQmlJSImporter; |
| 39 | |
| 40 | namespace QQmlJS { |
| 41 | |
| 42 | class ConstPtrWrapperIterator |
| 43 | { |
| 44 | public: |
| 45 | using Ptr = QDeferredSharedPointer<QQmlJSScope>; |
| 46 | using ConstPtr = QDeferredSharedPointer<const QQmlJSScope>; |
| 47 | using iterator_category = std::forward_iterator_tag; |
| 48 | using difference_type = std::ptrdiff_t; |
| 49 | using value_type = ConstPtr; |
| 50 | using pointer = value_type *; |
| 51 | using reference = value_type &; |
| 52 | |
| 53 | ConstPtrWrapperIterator(QList<Ptr>::const_iterator iterator) : m_iterator(iterator) { } |
| 54 | |
| 55 | friend bool operator==(const ConstPtrWrapperIterator &a, const ConstPtrWrapperIterator &b) |
| 56 | { |
| 57 | return a.m_iterator == b.m_iterator; |
| 58 | } |
| 59 | friend bool operator!=(const ConstPtrWrapperIterator &a, const ConstPtrWrapperIterator &b) |
| 60 | { |
| 61 | return a.m_iterator != b.m_iterator; |
| 62 | } |
| 63 | |
| 64 | reference operator*() |
| 65 | { |
| 66 | if (!m_pointer) |
| 67 | m_pointer = *m_iterator; |
| 68 | return m_pointer; |
| 69 | } |
| 70 | pointer operator->() |
| 71 | { |
| 72 | if (!m_pointer) |
| 73 | m_pointer = *m_iterator; |
| 74 | return &m_pointer; |
| 75 | } |
| 76 | |
| 77 | ConstPtrWrapperIterator &operator++() |
| 78 | { |
| 79 | m_iterator++; |
| 80 | m_pointer = {}; |
| 81 | return *this; |
| 82 | } |
| 83 | ConstPtrWrapperIterator operator++(int) |
| 84 | { |
| 85 | auto before = *this; |
| 86 | ++(*this); |
| 87 | return before; |
| 88 | } |
| 89 | |
| 90 | private: |
| 91 | QList<Ptr>::const_iterator m_iterator; |
| 92 | ConstPtr m_pointer; |
| 93 | }; |
| 94 | |
| 95 | class Export { |
| 96 | public: |
| 97 | Export() = default; |
| 98 | Export(QString package, QString type, QTypeRevision version, QTypeRevision revision); |
| 99 | |
| 100 | bool isValid() const; |
| 101 | |
| 102 | QString package() const { return m_package; } |
| 103 | QString type() const { return m_type; } |
| 104 | QTypeRevision version() const { return m_version; } |
| 105 | QTypeRevision revision() const { return m_revision; } |
| 106 | |
| 107 | private: |
| 108 | QString m_package; |
| 109 | QString m_type; |
| 110 | QTypeRevision m_version; |
| 111 | QTypeRevision m_revision; |
| 112 | }; |
| 113 | |
| 114 | template<typename Pointer> |
| 115 | struct ExportedScope { |
| 116 | Pointer scope; |
| 117 | QList<Export> exports; |
| 118 | }; |
| 119 | |
| 120 | template<typename Pointer> |
| 121 | struct ImportedScope { |
| 122 | Pointer scope; |
| 123 | QTypeRevision revision; |
| 124 | }; |
| 125 | |
| 126 | struct ContextualTypes; |
| 127 | |
| 128 | } // namespace QQmlJS |
| 129 | |
| 130 | class Q_QMLCOMPILER_EXPORT QQmlJSScope |
| 131 | { |
| 132 | friend QQmlSA::Element; |
| 133 | |
| 134 | public: |
| 135 | explicit QQmlJSScope(const QString &internalName); |
| 136 | QQmlJSScope(QQmlJSScope &&) = default; |
| 137 | QQmlJSScope &operator=(QQmlJSScope &&) = default; |
| 138 | |
| 139 | using Ptr = QDeferredSharedPointer<QQmlJSScope>; |
| 140 | using WeakPtr = QDeferredWeakPointer<QQmlJSScope>; |
| 141 | using ConstPtr = QDeferredSharedPointer<const QQmlJSScope>; |
| 142 | using WeakConstPtr = QDeferredWeakPointer<const QQmlJSScope>; |
| 143 | |
| 144 | using AccessSemantics = QQmlSA::AccessSemantics; |
| 145 | using ScopeType = QQmlSA::ScopeType; |
| 146 | |
| 147 | using InlineComponentNameType = QString; |
| 148 | using RootDocumentNameType = std::monostate; // an empty type that has std::hash |
| 149 | /*! |
| 150 | * A Hashable type to differentiate document roots from different inline components. |
| 151 | */ |
| 152 | using InlineComponentOrDocumentRootName = |
| 153 | std::variant<InlineComponentNameType, RootDocumentNameType>; |
| 154 | |
| 155 | enum Flag { |
| 156 | Creatable = 0x1, |
| 157 | Composite = 0x2, |
| 158 | JavaScriptBuiltin = 0x4, |
| 159 | Singleton = 0x8, |
| 160 | Script = 0x10, |
| 161 | CustomParser = 0x20, |
| 162 | Array = 0x40, |
| 163 | InlineComponent = 0x80, |
| 164 | WrappedInImplicitComponent = 0x100, |
| 165 | HasBaseTypeError = 0x200, |
| 166 | ExtensionIsNamespace = 0x400, |
| 167 | IsListProperty = 0x800, |
| 168 | Structured = 0x1000, |
| 169 | ExtensionIsJavaScript = 0x2000, |
| 170 | EnforcesScopedEnums = 0x4000, |
| 171 | AssignedToUnknownProperty = 0x10000, |
| 172 | }; |
| 173 | Q_DECLARE_FLAGS(Flags, Flag) |
| 174 | Q_FLAGS(Flags); |
| 175 | |
| 176 | using Export = QQmlJS::Export; |
| 177 | template <typename Pointer> |
| 178 | using ImportedScope = QQmlJS::ImportedScope<Pointer>; |
| 179 | template <typename Pointer> |
| 180 | using ExportedScope = QQmlJS::ExportedScope<Pointer>; |
| 181 | |
| 182 | struct JavaScriptIdentifier |
| 183 | { |
| 184 | enum Kind { |
| 185 | Parameter, |
| 186 | FunctionScoped, |
| 187 | LexicalScoped, |
| 188 | Injected |
| 189 | }; |
| 190 | |
| 191 | Kind kind = FunctionScoped; |
| 192 | QQmlJS::SourceLocation location; |
| 193 | std::optional<QString> typeName; |
| 194 | bool isConst = false; |
| 195 | QQmlJSScope::WeakConstPtr scope = {}; |
| 196 | }; |
| 197 | |
| 198 | enum BindingTargetSpecifier { |
| 199 | SimplePropertyTarget, // e.g. `property int p: 42` |
| 200 | ListPropertyTarget, // e.g. `property list<Item> pList: [ Text {} ]` |
| 201 | UnnamedPropertyTarget // default property bindings, where property name is unspecified |
| 202 | }; |
| 203 | |
| 204 | template <typename Key, typename Value> |
| 205 | using QMultiHashRange = QPair<typename QMultiHash<Key, Value>::iterator, |
| 206 | typename QMultiHash<Key, Value>::iterator>; |
| 207 | |
| 208 | static QQmlJSScope::Ptr create() { return QSharedPointer<QQmlJSScope>(new QQmlJSScope); } |
| 209 | static QQmlJSScope::Ptr create(const QString &internalName); |
| 210 | static QQmlJSScope::Ptr clone(const QQmlJSScope::ConstPtr &origin); |
| 211 | |
| 212 | static QQmlJSScope::ConstPtr findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope); |
| 213 | |
| 214 | QQmlJSScope::Ptr parentScope(); |
| 215 | QQmlJSScope::ConstPtr parentScope() const; |
| 216 | static void reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope); |
| 217 | |
| 218 | void insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier); |
| 219 | QHash<QString, JavaScriptIdentifier> ownJSIdentifiers() const; |
| 220 | void insertPropertyIdentifier(const QQmlJSMetaProperty &prop); |
| 221 | |
| 222 | ScopeType scopeType() const { return m_scopeType; } |
| 223 | void setScopeType(ScopeType type) { m_scopeType = type; } |
| 224 | |
| 225 | void addOwnMethod(const QQmlJSMetaMethod &method) { m_methods.insert(key: method.methodName(), value: method); } |
| 226 | QMultiHashRange<QString, QQmlJSMetaMethod> mutableOwnMethodsRange(const QString &name) |
| 227 | { |
| 228 | return m_methods.equal_range(key: name); |
| 229 | } |
| 230 | QMultiHash<QString, QQmlJSMetaMethod> ownMethods() const { return m_methods; } |
| 231 | QList<QQmlJSMetaMethod> ownMethods(const QString &name) const { return m_methods.values(key: name); } |
| 232 | bool hasOwnMethod(const QString &name) const { return m_methods.contains(key: name); } |
| 233 | |
| 234 | bool hasMethod(const QString &name) const; |
| 235 | QHash<QString, QQmlJSMetaMethod> methods() const; |
| 236 | QList<QQmlJSMetaMethod> methods(const QString &name) const; |
| 237 | QList<QQmlJSMetaMethod> methods(const QString &name, QQmlJSMetaMethodType type) const; |
| 238 | |
| 239 | void addOwnEnumeration(const QQmlJSMetaEnum &enumeration) { m_enumerations.insert(key: enumeration.name(), value: enumeration); } |
| 240 | QHash<QString, QQmlJSMetaEnum> ownEnumerations() const { return m_enumerations; } |
| 241 | QQmlJSMetaEnum ownEnumeration(const QString &name) const { return m_enumerations.value(key: name); } |
| 242 | bool hasOwnEnumeration(const QString &name) const { return m_enumerations.contains(key: name); } |
| 243 | |
| 244 | bool hasEnumeration(const QString &name) const; |
| 245 | bool hasEnumerationKey(const QString &name) const; |
| 246 | bool hasOwnEnumerationKey(const QString &name) const; |
| 247 | QQmlJSMetaEnum enumeration(const QString &name) const; |
| 248 | QHash<QString, QQmlJSMetaEnum> enumerations() const; |
| 249 | |
| 250 | void setAnnotations(const QList<QQmlJSAnnotation> &annotation) { m_annotations = std::move(annotation); } |
| 251 | const QList<QQmlJSAnnotation> &annotations() const { return m_annotations; } |
| 252 | |
| 253 | QString filePath() const { return m_filePath; } |
| 254 | void setFilePath(const QString &file) { m_filePath = file; } |
| 255 | |
| 256 | // The name the type uses to refer to itself. Either C++ class name or base name of |
| 257 | // QML file. isComposite tells us if this is a C++ or a QML name. |
| 258 | QString internalName() const { return m_internalName; } |
| 259 | void setInternalName(const QString &internalName) { m_internalName = internalName; } |
| 260 | QString augmentedInternalName() const; |
| 261 | |
| 262 | // This returns a more user readable version of internalName / baseTypeName |
| 263 | static QString prettyName(QAnyStringView name); |
| 264 | |
| 265 | enum class IsComponentRoot : quint8 { No = 0, Yes, Maybe }; |
| 266 | IsComponentRoot componentRootStatus() const; |
| 267 | |
| 268 | void setAliases(const QStringList &aliases) { m_aliases = aliases; } |
| 269 | QStringList aliases() const { return m_aliases; } |
| 270 | |
| 271 | void setInterfaceNames(const QStringList& interfaces) { m_interfaceNames = interfaces; } |
| 272 | QStringList interfaceNames() const { return m_interfaceNames; } |
| 273 | |
| 274 | bool hasInterface(const QString &name) const; |
| 275 | bool hasOwnInterface(const QString &name) const { return m_interfaceNames.contains(str: name); } |
| 276 | |
| 277 | void setOwnDeferredNames(const QStringList &names) { m_ownDeferredNames = names; } |
| 278 | QStringList ownDeferredNames() const { return m_ownDeferredNames; } |
| 279 | void setOwnImmediateNames(const QStringList &names) { m_ownImmediateNames = names; } |
| 280 | QStringList ownImmediateNames() const { return m_ownImmediateNames; } |
| 281 | |
| 282 | bool isNameDeferred(const QString &name) const; |
| 283 | |
| 284 | // If isComposite(), this is the QML/JS name of the prototype. Otherwise it's the |
| 285 | // relevant base class (in the hierarchy starting from QObject) of a C++ type. |
| 286 | void setBaseTypeName(const QString &baseTypeName); |
| 287 | QString baseTypeName() const; |
| 288 | |
| 289 | QQmlJSScope::ConstPtr baseType() const { return m_baseType.scope; } |
| 290 | QTypeRevision baseTypeRevision() const { return m_baseType.revision; } |
| 291 | |
| 292 | QString moduleName() const; |
| 293 | QString ownModuleName() const { return m_moduleName; } |
| 294 | void setOwnModuleName(const QString &moduleName) { m_moduleName = moduleName; } |
| 295 | |
| 296 | void clearBaseType() { m_baseType = {}; } |
| 297 | void setBaseTypeError(const QString &baseTypeError); |
| 298 | QString baseTypeError() const; |
| 299 | |
| 300 | void addOwnProperty(const QQmlJSMetaProperty &prop) { m_properties.insert(key: prop.propertyName(), value: prop); } |
| 301 | QHash<QString, QQmlJSMetaProperty> ownProperties() const { return m_properties; } |
| 302 | QQmlJSMetaProperty ownProperty(const QString &name) const { return m_properties.value(key: name); } |
| 303 | bool hasOwnProperty(const QString &name) const { return m_properties.contains(key: name); } |
| 304 | |
| 305 | bool hasProperty(const QString &name) const; |
| 306 | QQmlJSMetaProperty property(const QString &name) const; |
| 307 | QHash<QString, QQmlJSMetaProperty> properties() const; |
| 308 | |
| 309 | void setPropertyLocallyRequired(const QString &name, bool isRequired); |
| 310 | bool isPropertyRequired(const QString &name) const; |
| 311 | bool isPropertyLocallyRequired(const QString &name) const; |
| 312 | |
| 313 | void addOwnPropertyBinding( |
| 314 | const QQmlJSMetaPropertyBinding &binding, |
| 315 | BindingTargetSpecifier specifier = BindingTargetSpecifier::SimplePropertyTarget); |
| 316 | QMultiHash<QString, QQmlJSMetaPropertyBinding> ownPropertyBindings() const; |
| 317 | QPair<QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator, |
| 318 | QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator> |
| 319 | ownPropertyBindings(const QString &name) const; |
| 320 | QList<QQmlJSMetaPropertyBinding> ownPropertyBindingsInQmlIROrder() const; |
| 321 | bool hasOwnPropertyBindings(const QString &name) const; |
| 322 | |
| 323 | bool hasPropertyBindings(const QString &name) const; |
| 324 | QList<QQmlJSMetaPropertyBinding> propertyBindings(const QString &name) const; |
| 325 | |
| 326 | struct AnnotatedScope; // defined later |
| 327 | static AnnotatedScope ownerOfProperty(const QQmlJSScope::ConstPtr &self, const QString &name); |
| 328 | |
| 329 | bool isResolved() const; |
| 330 | bool isFullyResolved() const; |
| 331 | |
| 332 | QString ownDefaultPropertyName() const { return m_defaultPropertyName; } |
| 333 | void setOwnDefaultPropertyName(const QString &name) { m_defaultPropertyName = name; } |
| 334 | QString defaultPropertyName() const; |
| 335 | |
| 336 | QString ownParentPropertyName() const { return m_parentPropertyName; } |
| 337 | void setOwnParentPropertyName(const QString &name) { m_parentPropertyName = name; } |
| 338 | QString parentPropertyName() const; |
| 339 | |
| 340 | QString ownAttachedTypeName() const { return m_attachedTypeName; } |
| 341 | void setOwnAttachedTypeName(const QString &name) { m_attachedTypeName = name; } |
| 342 | QQmlJSScope::ConstPtr ownAttachedType() const { return m_attachedType; } |
| 343 | |
| 344 | QString attachedTypeName() const; |
| 345 | QQmlJSScope::ConstPtr attachedType() const; |
| 346 | |
| 347 | QString extensionTypeName() const { return m_extensionTypeName; } |
| 348 | void setExtensionTypeName(const QString &name) { m_extensionTypeName = name; } |
| 349 | enum ExtensionKind { |
| 350 | NotExtension, |
| 351 | ExtensionType, |
| 352 | ExtensionJavaScript, |
| 353 | ExtensionNamespace, |
| 354 | }; |
| 355 | struct AnnotatedScope |
| 356 | { |
| 357 | QQmlJSScope::ConstPtr scope; |
| 358 | ExtensionKind extensionSpecifier = NotExtension; |
| 359 | }; |
| 360 | AnnotatedScope extensionType() const; |
| 361 | |
| 362 | QString valueTypeName() const { return m_valueTypeName; } |
| 363 | void setValueTypeName(const QString &name) { m_valueTypeName = name; } |
| 364 | QQmlJSScope::ConstPtr valueType() const { return m_valueType; } |
| 365 | QQmlJSScope::ConstPtr listType() const { return m_listType; } |
| 366 | QQmlJSScope::Ptr listType() { return m_listType; } |
| 367 | |
| 368 | void addOwnRuntimeFunctionIndex(QQmlJSMetaMethod::AbsoluteFunctionIndex index); |
| 369 | QQmlJSMetaMethod::AbsoluteFunctionIndex |
| 370 | ownRuntimeFunctionIndex(QQmlJSMetaMethod::RelativeFunctionIndex index) const; |
| 371 | |
| 372 | |
| 373 | /*! |
| 374 | * \internal |
| 375 | * |
| 376 | * Returns true for objects defined from Qml, and false for objects declared from C++. |
| 377 | */ |
| 378 | bool isComposite() const { return m_flags.testFlag(flag: Composite); } |
| 379 | void setIsComposite(bool v) { m_flags.setFlag(flag: Composite, on: v); } |
| 380 | |
| 381 | /*! |
| 382 | * \internal |
| 383 | * |
| 384 | * Returns true for JavaScript types, false for QML and C++ types. |
| 385 | */ |
| 386 | bool isJavaScriptBuiltin() const { return m_flags.testFlag(flag: JavaScriptBuiltin); } |
| 387 | void setIsJavaScriptBuiltin(bool v) { m_flags.setFlag(flag: JavaScriptBuiltin, on: v); } |
| 388 | |
| 389 | bool isScript() const { return m_flags.testFlag(flag: Script); } |
| 390 | void setIsScript(bool v) { m_flags.setFlag(flag: Script, on: v); } |
| 391 | |
| 392 | bool hasCustomParser() const { return m_flags.testFlag(flag: CustomParser); } |
| 393 | void setHasCustomParser(bool v) { m_flags.setFlag(flag: CustomParser, on: v); } |
| 394 | |
| 395 | bool isArrayScope() const { return m_flags.testFlag(flag: Array); } |
| 396 | void setIsArrayScope(bool v) { m_flags.setFlag(flag: Array, on: v); } |
| 397 | |
| 398 | bool isInlineComponent() const { return m_flags.testFlag(flag: InlineComponent); } |
| 399 | void setIsInlineComponent(bool v) { m_flags.setFlag(flag: InlineComponent, on: v); } |
| 400 | |
| 401 | bool isWrappedInImplicitComponent() const { return m_flags.testFlag(flag: WrappedInImplicitComponent); } |
| 402 | void setIsWrappedInImplicitComponent(bool v) { m_flags.setFlag(flag: WrappedInImplicitComponent, on: v); } |
| 403 | |
| 404 | bool isAssignedToUnknownProperty() const { return m_flags.testFlag(flag: AssignedToUnknownProperty); } |
| 405 | void setAssignedToUnknownProperty(bool v) { m_flags.setFlag(flag: AssignedToUnknownProperty, on: v); } |
| 406 | |
| 407 | bool extensionIsJavaScript() const { return m_flags.testFlag(flag: ExtensionIsJavaScript); } |
| 408 | void setExtensionIsJavaScript(bool v) { m_flags.setFlag(flag: ExtensionIsJavaScript, on: v); } |
| 409 | |
| 410 | bool extensionIsNamespace() const { return m_flags.testFlag(flag: ExtensionIsNamespace); } |
| 411 | void setExtensionIsNamespace(bool v) { m_flags.setFlag(flag: ExtensionIsNamespace, on: v); } |
| 412 | |
| 413 | bool isListProperty() const { return m_flags.testFlag(flag: IsListProperty); } |
| 414 | void setIsListProperty(bool v) { m_flags.setFlag(flag: IsListProperty, on: v); } |
| 415 | |
| 416 | bool isSingleton() const { return m_flags.testFlag(flag: Singleton); } |
| 417 | void setIsSingleton(bool v) { m_flags.setFlag(flag: Singleton, on: v); } |
| 418 | |
| 419 | bool enforcesScopedEnums() const; |
| 420 | void setEnforcesScopedEnumsFlag(bool v) { m_flags.setFlag(flag: EnforcesScopedEnums, on: v); } |
| 421 | |
| 422 | bool isCreatable() const; |
| 423 | void setCreatableFlag(bool v) { m_flags.setFlag(flag: Creatable, on: v); } |
| 424 | |
| 425 | bool isStructured() const; |
| 426 | void setStructuredFlag(bool v) { m_flags.setFlag(flag: Structured, on: v); } |
| 427 | |
| 428 | void setAccessSemantics(AccessSemantics semantics) { m_semantics = semantics; } |
| 429 | AccessSemantics accessSemantics() const { return m_semantics; } |
| 430 | bool isReferenceType() const { return m_semantics == QQmlJSScope::AccessSemantics::Reference; } |
| 431 | bool isValueType() const { return m_semantics == QQmlJSScope::AccessSemantics::Value; } |
| 432 | |
| 433 | std::optional<JavaScriptIdentifier> jsIdentifier(const QString &id) const; |
| 434 | std::optional<JavaScriptIdentifier> ownJSIdentifier(const QString &id) const; |
| 435 | |
| 436 | QQmlJS::ConstPtrWrapperIterator childScopesBegin() const { return m_childScopes.constBegin(); } |
| 437 | QQmlJS::ConstPtrWrapperIterator childScopesEnd() const { return m_childScopes.constEnd(); } |
| 438 | |
| 439 | void setInlineComponentName(const QString &inlineComponentName); |
| 440 | std::optional<QString> inlineComponentName() const; |
| 441 | InlineComponentOrDocumentRootName enclosingInlineComponentName() const; |
| 442 | |
| 443 | QVector<QQmlJSScope::Ptr> childScopes(); |
| 444 | |
| 445 | QVector<QQmlJSScope::ConstPtr> childScopes() const; |
| 446 | |
| 447 | static QTypeRevision resolveTypes( |
| 448 | const Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, |
| 449 | QSet<QString> *usedTypes = nullptr); |
| 450 | static void resolveNonEnumTypes( |
| 451 | const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, |
| 452 | QSet<QString> *usedTypes = nullptr); |
| 453 | static void resolveEnums( |
| 454 | const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, |
| 455 | QSet<QString> *usedTypes = nullptr); |
| 456 | static void resolveList( |
| 457 | const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType); |
| 458 | static void resolveGroup( |
| 459 | const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType, |
| 460 | const QQmlJS::ContextualTypes &contextualTypes, |
| 461 | QSet<QString> *usedTypes = nullptr); |
| 462 | |
| 463 | void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation); |
| 464 | QQmlJS::SourceLocation sourceLocation() const; |
| 465 | |
| 466 | static QQmlJSScope::ConstPtr nonCompositeBaseType(const QQmlJSScope::ConstPtr &type); |
| 467 | |
| 468 | static QTypeRevision |
| 469 | nonCompositeBaseRevision(const ImportedScope<QQmlJSScope::ConstPtr> &scope); |
| 470 | |
| 471 | bool isSameType(const QQmlJSScope::ConstPtr &otherScope) const; |
| 472 | bool inherits(const QQmlJSScope::ConstPtr &base) const; |
| 473 | bool canAssign(const QQmlJSScope::ConstPtr &derived) const; |
| 474 | |
| 475 | bool isInCustomParserParent() const; |
| 476 | |
| 477 | |
| 478 | static ImportedScope<QQmlJSScope::ConstPtr> findType(const QString &name, |
| 479 | const QQmlJS::ContextualTypes &contextualTypes, |
| 480 | QSet<QString> *usedTypes = nullptr); |
| 481 | |
| 482 | static QQmlSA::Element createQQmlSAElement(const ConstPtr &); |
| 483 | static QQmlSA::Element createQQmlSAElement(ConstPtr &&); |
| 484 | static const QQmlJSScope::ConstPtr &scope(const QQmlSA::Element &); |
| 485 | static constexpr qsizetype sizeofQQmlSAElement() { return QQmlSA::Element::sizeofElement; } |
| 486 | |
| 487 | private: |
| 488 | /*! \internal |
| 489 | |
| 490 | Minimal information about a QQmlJSMetaPropertyBinding that allows it to |
| 491 | be manipulated similarly to QmlIR::Binding. |
| 492 | */ |
| 493 | template <typename T> |
| 494 | friend class QTypeInfo; // so that we can Q_DECLARE_TYPEINFO QmlIRCompatibilityBindingData |
| 495 | struct QmlIRCompatibilityBindingData |
| 496 | { |
| 497 | QmlIRCompatibilityBindingData() = default; |
| 498 | QmlIRCompatibilityBindingData(const QString &name, quint32 offset) |
| 499 | : propertyName(name), sourceLocationOffset(offset) |
| 500 | { |
| 501 | } |
| 502 | QString propertyName; // bound property name |
| 503 | quint32 sourceLocationOffset = 0; // binding's source location offset |
| 504 | }; |
| 505 | |
| 506 | QQmlJSScope() = default; |
| 507 | QQmlJSScope(const QQmlJSScope &) = default; |
| 508 | QQmlJSScope &operator=(const QQmlJSScope &) = default; |
| 509 | static QTypeRevision resolveType( |
| 510 | const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes, |
| 511 | QSet<QString> *usedTypes); |
| 512 | static void updateChildScope( |
| 513 | const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self, |
| 514 | const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes); |
| 515 | |
| 516 | void addOwnPropertyBindingInQmlIROrder(const QQmlJSMetaPropertyBinding &binding, |
| 517 | BindingTargetSpecifier specifier); |
| 518 | bool hasEnforcesScopedEnumsFlag() const { return m_flags & EnforcesScopedEnums; } |
| 519 | bool hasCreatableFlag() const { return m_flags & Creatable; } |
| 520 | bool hasStructuredFlag() const { return m_flags & Structured; } |
| 521 | |
| 522 | QHash<QString, JavaScriptIdentifier> m_jsIdentifiers; |
| 523 | |
| 524 | QMultiHash<QString, QQmlJSMetaMethod> m_methods; |
| 525 | QHash<QString, QQmlJSMetaProperty> m_properties; |
| 526 | QMultiHash<QString, QQmlJSMetaPropertyBinding> m_propertyBindings; |
| 527 | |
| 528 | // a special QmlIR compatibility bindings array, ordered the same way as |
| 529 | // bindings in QmlIR::Object |
| 530 | QList<QmlIRCompatibilityBindingData> m_propertyBindingsArray; |
| 531 | |
| 532 | // same as QmlIR::Object::runtimeFunctionIndices |
| 533 | QList<QQmlJSMetaMethod::AbsoluteFunctionIndex> m_runtimeFunctionIndices; |
| 534 | |
| 535 | QHash<QString, QQmlJSMetaEnum> m_enumerations; |
| 536 | |
| 537 | QVector<QQmlJSAnnotation> m_annotations; |
| 538 | QVector<QQmlJSScope::Ptr> m_childScopes; |
| 539 | QQmlJSScope::WeakPtr m_parentScope; |
| 540 | |
| 541 | QString m_filePath; |
| 542 | QString m_internalName; |
| 543 | QString m_baseTypeNameOrError; |
| 544 | |
| 545 | // We only need the revision for the base type as inheritance is |
| 546 | // the only relation between two types where the revisions matter. |
| 547 | ImportedScope<QQmlJSScope::WeakConstPtr> m_baseType; |
| 548 | |
| 549 | ScopeType m_scopeType = ScopeType::QMLScope; |
| 550 | QStringList m_aliases; |
| 551 | QStringList m_interfaceNames; |
| 552 | QStringList m_ownDeferredNames; |
| 553 | QStringList m_ownImmediateNames; |
| 554 | |
| 555 | QString m_defaultPropertyName; |
| 556 | QString m_parentPropertyName; |
| 557 | /*! \internal |
| 558 | * The attached type name. |
| 559 | * This is an internal name, from a c++ type or a synthetic jsrootgen. |
| 560 | */ |
| 561 | QString m_attachedTypeName; |
| 562 | QStringList m_requiredPropertyNames; |
| 563 | QQmlJSScope::WeakConstPtr m_attachedType; |
| 564 | |
| 565 | /*! \internal |
| 566 | * The Value type name. |
| 567 | * This is an internal name, from a c++ type or a synthetic jsrootgen. |
| 568 | */ |
| 569 | QString m_valueTypeName; |
| 570 | QQmlJSScope::WeakConstPtr m_valueType; |
| 571 | QQmlJSScope::Ptr m_listType; |
| 572 | |
| 573 | /*! |
| 574 | The extension is provided as either a type (QML_{NAMESPACE_}EXTENDED) or as a |
| 575 | namespace (QML_EXTENDED_NAMESPACE). |
| 576 | The bool HasExtensionNamespace helps differentiating both cases, as namespaces |
| 577 | have a more limited lookup capaility. |
| 578 | This is an internal name, from a c++ type or a synthetic jsrootgen. |
| 579 | */ |
| 580 | QString m_extensionTypeName; |
| 581 | QQmlJSScope::WeakConstPtr m_extensionType; |
| 582 | |
| 583 | Flags m_flags = Creatable; // all types are marked as creatable by default. |
| 584 | AccessSemantics m_semantics = AccessSemantics::Reference; |
| 585 | |
| 586 | QQmlJS::SourceLocation m_sourceLocation; |
| 587 | |
| 588 | QString m_moduleName; |
| 589 | |
| 590 | std::optional<QString> m_inlineComponentName; |
| 591 | }; |
| 592 | |
| 593 | inline QQmlJSScope::Ptr QQmlJSScope::parentScope() |
| 594 | { |
| 595 | return m_parentScope.toStrongRef(); |
| 596 | } |
| 597 | |
| 598 | inline QQmlJSScope::ConstPtr QQmlJSScope::parentScope() const |
| 599 | { |
| 600 | QT_WARNING_PUSH |
| 601 | #if defined(Q_CC_GNU_ONLY) && Q_CC_GNU < 1400 && Q_CC_GNU >= 1200 |
| 602 | QT_WARNING_DISABLE_GCC("-Wuse-after-free" ) |
| 603 | #endif |
| 604 | return QQmlJSScope::WeakConstPtr(m_parentScope).toStrongRef(); |
| 605 | QT_WARNING_POP |
| 606 | } |
| 607 | |
| 608 | inline QMultiHash<QString, QQmlJSMetaPropertyBinding> QQmlJSScope::ownPropertyBindings() const |
| 609 | { |
| 610 | return m_propertyBindings; |
| 611 | } |
| 612 | |
| 613 | inline QPair<QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator, QMultiHash<QString, QQmlJSMetaPropertyBinding>::const_iterator> QQmlJSScope::ownPropertyBindings(const QString &name) const |
| 614 | { |
| 615 | return m_propertyBindings.equal_range(key: name); |
| 616 | } |
| 617 | |
| 618 | inline bool QQmlJSScope::hasOwnPropertyBindings(const QString &name) const |
| 619 | { |
| 620 | return m_propertyBindings.contains(key: name); |
| 621 | } |
| 622 | |
| 623 | inline QQmlJSMetaMethod::AbsoluteFunctionIndex QQmlJSScope::ownRuntimeFunctionIndex(QQmlJSMetaMethod::RelativeFunctionIndex index) const |
| 624 | { |
| 625 | const int i = static_cast<int>(index); |
| 626 | Q_ASSERT(i >= 0); |
| 627 | Q_ASSERT(i < int(m_runtimeFunctionIndices.size())); |
| 628 | return m_runtimeFunctionIndices[i]; |
| 629 | } |
| 630 | |
| 631 | inline void QQmlJSScope::setInlineComponentName(const QString &inlineComponentName) |
| 632 | { |
| 633 | Q_ASSERT(isInlineComponent()); |
| 634 | m_inlineComponentName = inlineComponentName; |
| 635 | } |
| 636 | |
| 637 | inline QVector<QQmlJSScope::Ptr> QQmlJSScope::childScopes() |
| 638 | { |
| 639 | return m_childScopes; |
| 640 | } |
| 641 | |
| 642 | inline void QQmlJSScope::setSourceLocation(const QQmlJS::SourceLocation &sourceLocation) |
| 643 | { |
| 644 | m_sourceLocation = sourceLocation; |
| 645 | } |
| 646 | |
| 647 | inline QQmlJS::SourceLocation QQmlJSScope::sourceLocation() const |
| 648 | { |
| 649 | return m_sourceLocation; |
| 650 | } |
| 651 | |
| 652 | inline QQmlJSScope::ConstPtr QQmlJSScope::nonCompositeBaseType(const ConstPtr &type) |
| 653 | { |
| 654 | for (QQmlJSScope::ConstPtr base = type; base; base = base->baseType()) { |
| 655 | if (!base->isComposite()) |
| 656 | return base; |
| 657 | } |
| 658 | return {}; |
| 659 | } |
| 660 | |
| 661 | Q_DECLARE_TYPEINFO(QQmlJSScope::QmlIRCompatibilityBindingData, Q_RELOCATABLE_TYPE); |
| 662 | |
| 663 | template<> |
| 664 | class Q_QMLCOMPILER_EXPORT QDeferredFactory<QQmlJSScope> |
| 665 | { |
| 666 | public: |
| 667 | using TypeReader = std::function<QList<QQmlJS::DiagnosticMessage>( |
| 668 | QQmlJSImporter *importer, const QString &filePath, |
| 669 | const QSharedPointer<QQmlJSScope> &scopeToPopulate)>; |
| 670 | QDeferredFactory() = default; |
| 671 | |
| 672 | QDeferredFactory(QQmlJSImporter *importer, const QString &filePath, |
| 673 | const TypeReader &typeReader = {}); |
| 674 | |
| 675 | bool isValid() const |
| 676 | { |
| 677 | return !m_filePath.isEmpty() && m_importer != nullptr; |
| 678 | } |
| 679 | |
| 680 | QString internalName() const |
| 681 | { |
| 682 | return QFileInfo(m_filePath).baseName(); |
| 683 | } |
| 684 | |
| 685 | QString filePath() const { return m_filePath; } |
| 686 | |
| 687 | QQmlJSImporter* importer() const { return m_importer; } |
| 688 | |
| 689 | void setIsSingleton(bool isSingleton) |
| 690 | { |
| 691 | m_isSingleton = isSingleton; |
| 692 | } |
| 693 | |
| 694 | void setModuleName(const QString &moduleName) { m_moduleName = moduleName; } |
| 695 | |
| 696 | private: |
| 697 | friend class QDeferredSharedPointer<QQmlJSScope>; |
| 698 | friend class QDeferredSharedPointer<const QQmlJSScope>; |
| 699 | friend class QDeferredWeakPointer<QQmlJSScope>; |
| 700 | friend class QDeferredWeakPointer<const QQmlJSScope>; |
| 701 | |
| 702 | // Should only be called when lazy-loading the type in a deferred pointer. |
| 703 | void populate(const QSharedPointer<QQmlJSScope> &scope) const; |
| 704 | |
| 705 | QString m_filePath; |
| 706 | QQmlJSImporter *m_importer = nullptr; |
| 707 | bool m_isSingleton = false; |
| 708 | QString m_moduleName; |
| 709 | TypeReader m_typeReader; |
| 710 | }; |
| 711 | |
| 712 | using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>; |
| 713 | using QQmlJSImportedScope = QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>; |
| 714 | |
| 715 | QT_END_NAMESPACE |
| 716 | |
| 717 | #endif // QQMLJSSCOPE_P_H |
| 718 | |