1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #pragma once
27 
28 #include <qmljs/qmljs_global.h>
29 #include <qmljs/qmljsconstants.h>
30 #include <qmljs/qmljsimportdependencies.h>
31 #include <qmljs/parser/qmljsastfwd_p.h>
32 
33 #include <languageutils/fakemetaobject.h>
34 
35 #include <QFileInfoList>
36 #include <QHash>
37 #include <QList>
38 #include <QSet>
39 #include <QSharedPointer>
40 #include <QString>
41 
42 namespace QmlJS {
43 ////////////////////////////////////////////////////////////////////////////////
44 // Forward declarations
45 ////////////////////////////////////////////////////////////////////////////////
46 class ASTFunctionValue;
47 class ASTObjectValue;
48 class ASTPropertyReference;
49 class ASTSignal;
50 class ASTVariableReference;
51 class AnchorLineValue;
52 class BooleanValue;
53 class ColorValue;
54 class Context;
55 class CppComponentValue;
56 class Document;
57 class Function;
58 class FunctionValue;
59 class Imports;
60 class IntValue;
61 class JSImportScope;
62 class NameId;
63 class NullValue;
64 class NumberValue;
65 class ModuleApiInfo;
66 class ObjectValue;
67 class QmlEnumValue;
68 class QmlPrototypeReference;
69 class RealValue;
70 class Reference;
71 class ReferenceContext;
72 class StringValue;
73 class TypeScope;
74 class UndefinedValue;
75 class UnknownValue;
76 class UrlValue;
77 class Value;
78 class ValueOwner;
79 class MetaFunction;
80 typedef QSharedPointer<const Context> ContextPtr;
81 
82 namespace Internal {
83 class QtObjectPrototypeReference;
84 } // namespace Internal
85 
86 typedef QList<const Value *> ValueList;
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 // Value visitor
90 ////////////////////////////////////////////////////////////////////////////////
91 class QMLJS_EXPORT ValueVisitor
92 {
93 public:
94     ValueVisitor();
95     virtual ~ValueVisitor();
96 
97     virtual void visit(const NullValue *);
98     virtual void visit(const UndefinedValue *);
99     virtual void visit(const UnknownValue *);
100     virtual void visit(const NumberValue *);
101     virtual void visit(const BooleanValue *);
102     virtual void visit(const StringValue *);
103     virtual void visit(const ObjectValue *);
104     virtual void visit(const FunctionValue *);
105     virtual void visit(const Reference *);
106     virtual void visit(const ColorValue *);
107     virtual void visit(const AnchorLineValue *);
108 };
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 // QML/JS value
112 ////////////////////////////////////////////////////////////////////////////////
113 class QMLJS_EXPORT Value
114 {
115     Value(const Value &other);
116     void operator = (const Value &other);
117 
118 public:
119     Value();
120     virtual ~Value();
121 
122     virtual const NullValue *asNullValue() const;
123     virtual const UndefinedValue *asUndefinedValue() const;
124     virtual const UnknownValue *asUnknownValue() const;
125     virtual const NumberValue *asNumberValue() const;
126     virtual const IntValue *asIntValue() const;
127     virtual const RealValue *asRealValue() const;
128     virtual const BooleanValue *asBooleanValue() const;
129     virtual const StringValue *asStringValue() const;
130     virtual const UrlValue *asUrlValue() const;
131     virtual const ObjectValue *asObjectValue() const;
132     virtual const FunctionValue *asFunctionValue() const;
133     virtual const Reference *asReference() const;
134     virtual const ColorValue *asColorValue() const;
135     virtual const AnchorLineValue *asAnchorLineValue() const;
136     virtual const CppComponentValue *asCppComponentValue() const;
137     virtual const ASTObjectValue *asAstObjectValue() const;
138     virtual const QmlEnumValue *asQmlEnumValue() const;
139     virtual const QmlPrototypeReference *asQmlPrototypeReference() const;
140     virtual const ASTPropertyReference *asAstPropertyReference() const;
141     virtual const ASTVariableReference *asAstVariableReference() const;
142     virtual const Internal::QtObjectPrototypeReference *asQtObjectPrototypeReference() const;
143     virtual const ASTSignal *asAstSignal() const;
144     virtual const ASTFunctionValue *asAstFunctionValue() const;
145     virtual const Function *asFunction() const;
146     virtual const MetaFunction *asMetaFunction() const;
147     virtual const JSImportScope *asJSImportScope() const;
148     virtual const TypeScope *asTypeScope() const;
149 
150     virtual void accept(ValueVisitor *) const = 0;
151 
152     virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
153 };
154 
value_cast(const Value *)155 template <typename RetTy> const RetTy *value_cast(const Value *)
156 {
157     // Produce a good error message if a specialization is missing.
158     RetTy::ERROR_MissingValueCastSpecialization();
159     return 0;
160 }
161 
value_cast(const Value * v)162 template <> Q_INLINE_TEMPLATE const NullValue *value_cast(const Value *v)
163 {
164     if (v) return v->asNullValue();
165     else   return nullptr;
166 }
167 
value_cast(const Value * v)168 template <> Q_INLINE_TEMPLATE const UndefinedValue *value_cast(const Value *v)
169 {
170     if (v) return v->asUndefinedValue();
171     else   return nullptr;
172 }
173 
value_cast(const Value * v)174 template <> Q_INLINE_TEMPLATE const UnknownValue *value_cast(const Value *v)
175 {
176     if (v) return v->asUnknownValue();
177     else   return nullptr;
178 }
179 
value_cast(const Value * v)180 template <> Q_INLINE_TEMPLATE const NumberValue *value_cast(const Value *v)
181 {
182     if (v) return v->asNumberValue();
183     else   return nullptr;
184 }
185 
value_cast(const Value * v)186 template <> Q_INLINE_TEMPLATE const IntValue *value_cast(const Value *v)
187 {
188     if (v) return v->asIntValue();
189     else   return nullptr;
190 }
191 
value_cast(const Value * v)192 template <> Q_INLINE_TEMPLATE const RealValue *value_cast(const Value *v)
193 {
194     if (v) return v->asRealValue();
195     else   return nullptr;
196 }
197 
value_cast(const Value * v)198 template <> Q_INLINE_TEMPLATE const BooleanValue *value_cast(const Value *v)
199 {
200     if (v) return v->asBooleanValue();
201     else   return nullptr;
202 }
203 
value_cast(const Value * v)204 template <> Q_INLINE_TEMPLATE const StringValue *value_cast(const Value *v)
205 {
206     if (v) return v->asStringValue();
207     else   return nullptr;
208 }
209 
value_cast(const Value * v)210 template <> Q_INLINE_TEMPLATE const UrlValue *value_cast(const Value *v)
211 {
212     if (v) return v->asUrlValue();
213     else   return nullptr;
214 }
215 
value_cast(const Value * v)216 template <> Q_INLINE_TEMPLATE const ObjectValue *value_cast(const Value *v)
217 {
218     if (v) return v->asObjectValue();
219     else   return nullptr;
220 }
221 
value_cast(const Value * v)222 template <> Q_INLINE_TEMPLATE const ASTFunctionValue *value_cast(const Value *v)
223 {
224     if (v) return v->asAstFunctionValue();
225     else   return nullptr;
226 }
227 
value_cast(const Value * v)228 template <> Q_INLINE_TEMPLATE const FunctionValue *value_cast(const Value *v)
229 {
230     if (v) return v->asFunctionValue();
231     else   return nullptr;
232 }
233 
value_cast(const Value * v)234 template <> Q_INLINE_TEMPLATE const Reference *value_cast(const Value *v)
235 {
236     if (v) return v->asReference();
237     else   return nullptr;
238 }
239 
value_cast(const Value * v)240 template <> Q_INLINE_TEMPLATE const ColorValue *value_cast(const Value *v)
241 {
242     if (v) return v->asColorValue();
243     else   return nullptr;
244 }
245 
value_cast(const Value * v)246 template <> Q_INLINE_TEMPLATE const AnchorLineValue *value_cast(const Value *v)
247 {
248     if (v) return v->asAnchorLineValue();
249     else   return nullptr;
250 }
251 
value_cast(const Value * v)252 template <> Q_INLINE_TEMPLATE const CppComponentValue *value_cast(const Value *v)
253 {
254     if (v) return v->asCppComponentValue();
255     else   return nullptr;
256 }
257 
value_cast(const Value * v)258 template <> Q_INLINE_TEMPLATE const ASTObjectValue *value_cast(const Value *v)
259 {
260     if (v) return v->asAstObjectValue();
261     else   return nullptr;
262 }
263 
value_cast(const Value * v)264 template <> Q_INLINE_TEMPLATE const QmlEnumValue *value_cast(const Value *v)
265 {
266     if (v) return v->asQmlEnumValue();
267     else   return nullptr;
268 }
269 
value_cast(const Value * v)270 template <> Q_INLINE_TEMPLATE const QmlPrototypeReference *value_cast(const Value *v)
271 {
272     if (v) return v->asQmlPrototypeReference();
273     else   return nullptr;
274 }
275 
value_cast(const Value * v)276 template <> Q_INLINE_TEMPLATE const ASTPropertyReference *value_cast(const Value *v)
277 {
278     if (v) return v->asAstPropertyReference();
279     else   return nullptr;
280 }
281 
value_cast(const Value * v)282 template <> Q_INLINE_TEMPLATE const Internal::QtObjectPrototypeReference *value_cast(const Value *v)
283 {
284     if (v) return v->asQtObjectPrototypeReference();
285     else   return nullptr;
286 }
287 
value_cast(const Value * v)288 template <> Q_INLINE_TEMPLATE const ASTVariableReference *value_cast(const Value *v)
289 {
290     if (v) return v->asAstVariableReference();
291     else   return nullptr;
292 }
293 
value_cast(const Value * v)294 template <> Q_INLINE_TEMPLATE const Function *value_cast(const Value *v)
295 {
296     if (v) return v->asFunction();
297     else   return nullptr;
298 }
299 
value_cast(const Value * v)300 template <> Q_INLINE_TEMPLATE const MetaFunction *value_cast(const Value *v)
301 {
302     if (v) return v->asMetaFunction();
303     else   return nullptr;
304 }
305 
value_cast(const Value * v)306 template <> Q_INLINE_TEMPLATE const JSImportScope *value_cast(const Value *v)
307 {
308     if (v) return v->asJSImportScope();
309     else   return nullptr;
310 }
311 
value_cast(const Value * v)312 template <> Q_INLINE_TEMPLATE const TypeScope *value_cast(const Value *v)
313 {
314     if (v) return v->asTypeScope();
315     else   return nullptr;
316 }
317 
value_cast(const Value * v)318 template <> Q_INLINE_TEMPLATE const ASTSignal *value_cast(const Value *v)
319 {
320     if (v) return v->asAstSignal();
321     else   return nullptr;
322 }
323 
324 ////////////////////////////////////////////////////////////////////////////////
325 // Value nodes
326 ////////////////////////////////////////////////////////////////////////////////
327 class QMLJS_EXPORT NullValue: public Value
328 {
329 public:
330     const NullValue *asNullValue() const override;
331     void accept(ValueVisitor *visitor) const override;
332 };
333 
334 class QMLJS_EXPORT UndefinedValue: public Value
335 {
336 public:
337     const UndefinedValue *asUndefinedValue() const override;
338     void accept(ValueVisitor *visitor) const override;
339 };
340 
341 class QMLJS_EXPORT UnknownValue: public Value
342 {
343 public:
344     const UnknownValue *asUnknownValue() const override;
345     void accept(ValueVisitor *) const override;
346 };
347 
348 class QMLJS_EXPORT NumberValue: public Value
349 {
350 public:
351     const NumberValue *asNumberValue() const override;
352     void accept(ValueVisitor *visitor) const override;
353 };
354 
355 class QMLJS_EXPORT RealValue: public NumberValue
356 {
357 public:
358     const RealValue *asRealValue() const override;
359 };
360 
361 class QMLJS_EXPORT IntValue: public NumberValue
362 {
363 public:
364     const IntValue *asIntValue() const override;
365 };
366 
367 class QMLJS_EXPORT BooleanValue: public Value
368 {
369 public:
370     const BooleanValue *asBooleanValue() const override;
371     void accept(ValueVisitor *visitor) const override;
372 };
373 
374 class QMLJS_EXPORT StringValue: public Value
375 {
376 public:
377     const StringValue *asStringValue() const override;
378     void accept(ValueVisitor *visitor) const override;
379 };
380 
381 class QMLJS_EXPORT UrlValue: public StringValue
382 {
383 public:
384     const UrlValue *asUrlValue() const override;
385 };
386 
387 class PropertyInfo {
388 public:
389     enum PropertyFlag {
390         Readable    = 1,
391         Writeable   = 2,
392         ListType    = 4,
393         PointerType= 8,
394         ValueType  = 16,
395         PointerOrValue = PointerType|ValueType,
396         Default     = Readable|Writeable|PointerOrValue
397     };
398 
399     PropertyInfo(uint flags = Default);
400     uint flags;
isPointer()401     bool isPointer() const {
402         return (flags & PointerOrValue) == PointerType;
403     }
isValue()404     bool isValue() const {
405         return (flags & PointerOrValue) == ValueType;
406     }
canBePointer()407     bool canBePointer() const {
408         return (flags & PointerType) != 0;
409     }
canBeValue()410     bool canBeValue() const {
411         return (flags & ValueType) != 0;
412     }
isReadable()413     bool isReadable() const {
414         return (flags & Readable) != 0;
415     }
isWriteable()416     bool isWriteable() const {
417         return (flags & Writeable) != 0;
418     }
isList()419     bool isList() const {
420         return (flags & ListType) != 0;
421     }
422     QString toString() const;
423 };
424 
425 class QMLJS_EXPORT MemberProcessor
426 {
427     MemberProcessor(const MemberProcessor &other);
428     void operator = (const MemberProcessor &other);
429 
430 public:
431     MemberProcessor();
432     virtual ~MemberProcessor();
433 
434     // Returns false to stop the processor.
435     virtual bool processProperty(const QString &name, const Value *value,
436                                  const PropertyInfo &propertyInfo);
437     virtual bool processEnumerator(const QString &name, const Value *value);
438     virtual bool processSignal(const QString &name, const Value *value);
439     virtual bool processSlot(const QString &name, const Value *value);
440     virtual bool processGeneratedSlot(const QString &name, const Value *value);
441 };
442 
443 class QMLJS_EXPORT Reference: public Value
444 {
445 public:
446     Reference(ValueOwner *valueOwner);
447     ~Reference();
448 
449     ValueOwner *valueOwner() const;
450 
451     // Value interface
452     const Reference *asReference() const override;
453     void accept(ValueVisitor *) const override;
454 
455 private:
456     virtual const Value *value(ReferenceContext *referenceContext) const;
457 
458     ValueOwner *m_valueOwner;
459     friend class ReferenceContext;
460 };
461 
462 class QMLJS_EXPORT ColorValue: public Value
463 {
464 public:
465     // Value interface
466     const ColorValue *asColorValue() const override;
467     void accept(ValueVisitor *) const override;
468 };
469 
470 class QMLJS_EXPORT AnchorLineValue: public Value
471 {
472 public:
473     // Value interface
474     const AnchorLineValue *asAnchorLineValue() const override;
475     void accept(ValueVisitor *) const override;
476 };
477 
478 class QMLJS_EXPORT PropertyData {
479 public:
480     const Value *value;
481     PropertyInfo propertyInfo;
482     PropertyData(const Value *value = nullptr,
483                  PropertyInfo propertyInfo = PropertyInfo(PropertyInfo::Default))
value(value)484         : value(value), propertyInfo(propertyInfo)
485     { }
486 };
487 
488 class QMLJS_EXPORT ObjectValue: public Value
489 {
490 public:
491     ObjectValue(ValueOwner *valueOwner, const QString &originId = QString());
492     ~ObjectValue();
493 
494     ValueOwner *valueOwner() const;
495 
496     QString className() const;
497     void setClassName(const QString &className);
498 
499     // may return a reference, prototypes may form a cycle: use PrototypeIterator!
500     const Value *prototype() const;
501     // prototypes may form a cycle: use PrototypeIterator!
502     const ObjectValue *prototype(const Context *context) const;
prototype(const ContextPtr & context)503     const ObjectValue *prototype(const ContextPtr &context) const
504     { return prototype(context.data()); }
505     void setPrototype(const Value *prototype);
506 
507     virtual void processMembers(MemberProcessor *processor) const;
508 
509     virtual void setMember(const QString &name, const Value *value);
510     virtual void setMember(QStringView name, const Value *value);
511     virtual void setPropertyInfo(const QString &name, const PropertyInfo &propertyInfo);
512     virtual void removeMember(const QString &name);
513 
514     virtual const Value *lookupMember(const QString &name, const Context *context,
515                                       const ObjectValue **foundInObject = nullptr,
516                                       bool examinePrototypes = true) const;
517     virtual const Value *lookupMember(const QString &name, const ContextPtr &context,
518                               const ObjectValue **foundInObject = nullptr,
519                               bool examinePrototypes = true) const
520     { return lookupMember(name, context.data(), foundInObject, examinePrototypes); }
521 
522     // Value interface
523     const ObjectValue *asObjectValue() const override;
524     void accept(ValueVisitor *visitor) const override;
originId()525     QString originId() const
526     { return m_originId; }
527 
528 private:
529     ValueOwner *m_valueOwner;
530     QHash<QString, PropertyData> m_members;
531     QString m_className;
532     QString m_originId;
533 
534 protected:
535     const Value *_prototype;
536 };
537 
538 class QMLJS_EXPORT PrototypeIterator
539 {
540 public:
541     enum Error
542     {
543         NoError,
544         ReferenceResolutionError,
545         CycleError
546     };
547 
548     PrototypeIterator(const ObjectValue *start, const Context *context);
549     PrototypeIterator(const ObjectValue *start, const ContextPtr &context);
550 
551     bool hasNext();
552     const ObjectValue *peekNext();
553     const ObjectValue *next();
554     Error error() const;
555 
556     QList<const ObjectValue *> all();
557 
558 private:
559     const ObjectValue *m_current;
560     const ObjectValue *m_next;
561     QList<const ObjectValue *> m_prototypes;
562     const Context *m_context;
563     Error m_error;
564 };
565 
566 class QMLJS_EXPORT QmlEnumValue: public NumberValue
567 {
568 public:
569     QmlEnumValue(const CppComponentValue *owner, int index);
570     ~QmlEnumValue();
571 
572     const QmlEnumValue *asQmlEnumValue() const override;
573 
574     QString name() const;
575     QStringList keys() const;
576     const CppComponentValue *owner() const;
577 
578 private:
579     const CppComponentValue *m_owner;
580     int m_enumIndex;
581 };
582 
583 
584 // A ObjectValue based on a FakeMetaObject.
585 // May only have other CppComponentValue as ancestors.
586 class QMLJS_EXPORT CppComponentValue: public ObjectValue
587 {
588 public:
589     CppComponentValue(LanguageUtils::FakeMetaObject::ConstPtr metaObject, const QString &className,
590                    const QString &moduleName, const LanguageUtils::ComponentVersion &componentVersion,
591                    const LanguageUtils::ComponentVersion &importVersion, int metaObjectRevision,
592                    ValueOwner *valueOwner, const QString &originId);
593     ~CppComponentValue();
594 
595     const CppComponentValue *asCppComponentValue() const override;
596 
597     void processMembers(MemberProcessor *processor) const override;
598     const Value *valueForCppName(const QString &typeName) const;
599 
600     using ObjectValue::prototype;
601     const CppComponentValue *prototype() const;
602     QList<const CppComponentValue *> prototypes() const;
603 
604     LanguageUtils::FakeMetaObject::ConstPtr metaObject() const;
605 
606     QString moduleName() const;
607     LanguageUtils::ComponentVersion componentVersion() const;
608     LanguageUtils::ComponentVersion importVersion() const;
609 
610     QString defaultPropertyName() const;
611     QString propertyType(const QString &propertyName) const;
612     bool isListProperty(const QString &name) const;
613     bool isWritable(const QString &propertyName) const;
614     bool isPointer(const QString &propertyName) const;
615     bool hasLocalProperty(const QString &typeName) const;
616     bool hasProperty(const QString &typeName) const;
617 
618     LanguageUtils::FakeMetaEnum getEnum(const QString &typeName, const CppComponentValue **foundInScope = nullptr) const;
619     const QmlEnumValue *getEnumValue(const QString &typeName, const CppComponentValue **foundInScope = nullptr) const;
620 
621     const ObjectValue *signalScope(const QString &signalName) const;
622 protected:
623     bool isDerivedFrom(LanguageUtils::FakeMetaObject::ConstPtr base) const;
624 
625 private:
626     LanguageUtils::FakeMetaObject::ConstPtr m_metaObject;
627     const QString m_moduleName;
628     // _componentVersion is the version of the export
629     // _importVersion is the version it's imported as, used to find correct prototypes
630     // needed in cases when B 1.0 has A 1.1 as prototype when imported as 1.1
631     const LanguageUtils::ComponentVersion m_componentVersion;
632     const LanguageUtils::ComponentVersion m_importVersion;
633     mutable QAtomicPointer< QList<const Value *> > m_metaSignatures;
634     mutable QAtomicPointer< QHash<QString, const ObjectValue *> > m_signalScopes;
635     QHash<QString, const QmlEnumValue * > m_enums;
636     int m_metaObjectRevision;
637 };
638 
639 class QMLJS_EXPORT FunctionValue: public ObjectValue
640 {
641 public:
642     FunctionValue(ValueOwner *valueOwner);
643     ~FunctionValue();
644 
645     virtual const Value *returnValue() const;
646 
647     // Access to the names of arguments
648     // Named arguments can be optional (usually known for builtins only)
649     virtual int namedArgumentCount() const;
650     virtual QString argumentName(int index) const;
651 
652     // The number of optional named arguments
653     // Example: JSON.stringify(value[, replacer[, space]])
654     //          has namedArgumentCount = 3
655     //          and optionalNamedArgumentCount = 2
656     virtual int optionalNamedArgumentCount() const;
657 
658     // Whether the function accepts an unlimited number of arguments
659     // after the named ones. Defaults to false.
660     // Example: Math.max(...)
661     virtual bool isVariadic() const;
662 
663     virtual const Value *argument(int index) const;
664 
665     // Value interface
666     const FunctionValue *asFunctionValue() const override;
667     void accept(ValueVisitor *visitor) const override;
668 };
669 
670 class QMLJS_EXPORT Function: public FunctionValue
671 {
672 public:
673     Function(ValueOwner *valueOwner);
674     ~Function();
675 
676     void addArgument(const Value *argument, const QString &name = QString());
677     void setReturnValue(const Value *returnValue);
678     void setVariadic(bool variadic);
679     void setOptionalNamedArgumentCount(int count);
680 
681     // FunctionValue interface
682     const Value *returnValue() const override;
683     int namedArgumentCount() const override;
684     int optionalNamedArgumentCount() const override;
685     const Value *argument(int index) const override;
686     QString argumentName(int index) const override;
687     bool isVariadic() const override;
688     const Function *asFunction() const override;
689 
690 private:
691     ValueList m_arguments;
692     QStringList m_argumentNames;
693     const Value *m_returnValue;
694     int m_optionalNamedArgumentCount;
695     bool m_isVariadic;
696 };
697 
698 
699 ////////////////////////////////////////////////////////////////////////////////
700 // typing environment
701 ////////////////////////////////////////////////////////////////////////////////
702 
703 class QMLJS_EXPORT CppQmlTypesLoader
704 {
705 public:
706     typedef QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> BuiltinObjects;
707 
708     /** Loads a set of qmltypes files into the builtin objects list
709         and returns errors and warnings
710     */
711     static BuiltinObjects loadQmlTypes(const QFileInfoList &qmltypesFiles,
712                              QStringList *errors, QStringList *warnings);
713 
714     static BuiltinObjects defaultQtObjects;
715     static BuiltinObjects defaultLibraryObjects;
716 
717     // parses the contents of a qmltypes file and fills the newObjects map
718     static void parseQmlTypeDescriptions(const QByteArray &contents,
719                                          BuiltinObjects *newObjects,
720                                          QList<ModuleApiInfo> *newModuleApis,
721                                          QStringList *newDependencies,
722                                          QString *errorMessage,
723                                          QString *warningMessage,
724                                          const QString &fileName);
725 };
726 
727 class QMLJS_EXPORT FakeMetaObjectWithOrigin
728 {
729 public:
730     LanguageUtils::FakeMetaObject::ConstPtr fakeMetaObject;
731     QString originId;
732     FakeMetaObjectWithOrigin(LanguageUtils::FakeMetaObject::ConstPtr fakeMetaObject,
733                              const QString &originId);
734     bool operator ==(const FakeMetaObjectWithOrigin &o) const;
735 };
736 
737 QMLJS_EXPORT uint qHash(const FakeMetaObjectWithOrigin &fmoo);
738 
739 class QMLJS_EXPORT CppQmlTypes
740 {
741 public:
742     CppQmlTypes(ValueOwner *valueOwner);
743 
744     // package name for objects that should be always available
745     static const QLatin1String defaultPackage;
746     // package name for objects with their raw cpp name
747     static const QLatin1String cppPackage;
748 
749     template <typename T>
750     void load(const QString &originId, const T &fakeMetaObjects, const QString &overridePackage = QString());
751 
752     QList<const CppComponentValue *> createObjectsForImport(const QString &package, LanguageUtils::ComponentVersion version);
753     bool hasModule(const QString &module) const;
754 
755     static QString qualifiedName(const QString &module, const QString &type,
756                                  LanguageUtils::ComponentVersion version);
757     const CppComponentValue *objectByQualifiedName(const QString &fullyQualifiedName) const;
758     const CppComponentValue *objectByQualifiedName(
759             const QString &package, const QString &type,
760             LanguageUtils::ComponentVersion version) const;
761     const CppComponentValue *objectByCppName(const QString &cppName) const;
762 
763     void setCppContextProperties(const ObjectValue *contextProperties);
764     const ObjectValue *cppContextProperties() const;
765 
766 private:
767     // "Package.CppName ImportVersion" ->  CppComponentValue
768     QHash<QString, const CppComponentValue *> m_objectsByQualifiedName;
769     QHash<QString, QSet<FakeMetaObjectWithOrigin> > m_fakeMetaObjectsByPackage;
770     const ObjectValue *m_cppContextProperties;
771     ValueOwner *m_valueOwner;
772 };
773 
774 class ConvertToNumber: protected ValueVisitor // ECMAScript ToInt()
775 {
776 public:
777     ConvertToNumber(ValueOwner *valueOwner);
778 
779     const Value *operator()(const Value *value);
780 
781 protected:
782     const Value *switchResult(const Value *value);
783 
784     void visit(const NullValue *) override;
785     void visit(const UndefinedValue *) override;
786     void visit(const NumberValue *) override;
787     void visit(const BooleanValue *) override;
788     void visit(const StringValue *) override;
789     void visit(const ObjectValue *) override;
790     void visit(const FunctionValue *) override;
791 
792 private:
793     ValueOwner *m_valueOwner;
794     const Value *m_result;
795 };
796 
797 class ConvertToString: protected ValueVisitor // ECMAScript ToString
798 {
799 public:
800     ConvertToString(ValueOwner *valueOwner);
801 
802     const Value *operator()(const Value *value);
803 
804 protected:
805     const Value *switchResult(const Value *value);
806 
807     void visit(const NullValue *) override;
808     void visit(const UndefinedValue *) override;
809     void visit(const NumberValue *) override;
810     void visit(const BooleanValue *) override;
811     void visit(const StringValue *) override;
812     void visit(const ObjectValue *) override;
813     void visit(const FunctionValue *) override;
814 
815 private:
816     ValueOwner *m_valueOwner;
817     const Value *m_result;
818 };
819 
820 class ConvertToObject: protected ValueVisitor // ECMAScript ToObject
821 {
822 public:
823     ConvertToObject(ValueOwner *valueOwner);
824 
825     const Value *operator()(const Value *value);
826 
827 protected:
828     const Value *switchResult(const Value *value);
829 
830     void visit(const NullValue *) override;
831     void visit(const UndefinedValue *) override;
832     void visit(const NumberValue *) override;
833     void visit(const BooleanValue *) override;
834     void visit(const StringValue *) override;
835     void visit(const ObjectValue *) override;
836     void visit(const FunctionValue *) override;
837 
838 private:
839     ValueOwner *m_valueOwner;
840     const Value *m_result;
841 };
842 
843 class QMLJS_EXPORT TypeId: protected ValueVisitor
844 {
845     QString _result;
846 
847 public:
848     QString operator()(const Value *value);
849 
850 protected:
851     void visit(const NullValue *) override;
852     void visit(const UndefinedValue *) override;
853     void visit(const NumberValue *) override;
854     void visit(const BooleanValue *) override;
855     void visit(const StringValue *) override;
856     void visit(const ObjectValue *object) override;
857     void visit(const FunctionValue *object) override;
858     void visit(const ColorValue *) override;
859     void visit(const AnchorLineValue *) override;
860 };
861 
862 // internal
863 class QMLJS_EXPORT QmlPrototypeReference: public Reference
864 {
865 public:
866     QmlPrototypeReference(AST::UiQualifiedId *qmlTypeName, const Document *doc, ValueOwner *valueOwner);
867     ~QmlPrototypeReference();
868 
869     const QmlPrototypeReference *asQmlPrototypeReference() const override;
870 
871     AST::UiQualifiedId *qmlTypeName() const;
872     const Document *document() const;
873 
874 private:
875     const Value *value(ReferenceContext *referenceContext) const override;
876 
877     AST::UiQualifiedId *m_qmlTypeName;
878     const Document *m_doc;
879 };
880 
881 class QMLJS_EXPORT ASTVariableReference: public Reference
882 {
883     AST::PatternElement *m_ast;
884     const Document *m_doc;
885 
886 public:
887     ASTVariableReference(AST::PatternElement *ast, const Document *doc, ValueOwner *valueOwner);
888     ~ASTVariableReference();
889     const ASTVariableReference *asAstVariableReference() const override;
890     const AST::PatternElement *ast() const;
891 private:
892     const Value *value(ReferenceContext *referenceContext) const override;
893     bool getSourceLocation(QString *fileName, int *line, int *column) const override;
894 };
895 
896 class QMLJS_EXPORT ASTFunctionValue: public FunctionValue
897 {
898     AST::FunctionExpression *m_ast;
899     const Document *m_doc;
900     QList<QString> m_argumentNames;
901     bool m_isVariadic;
902 
903 public:
904     ASTFunctionValue(AST::FunctionExpression *ast, const Document *doc, ValueOwner *valueOwner);
905     ~ASTFunctionValue();
906 
907     AST::FunctionExpression *ast() const;
908 
909     int namedArgumentCount() const override;
910     QString argumentName(int index) const override;
911     bool isVariadic() const override;
912     const ASTFunctionValue *asAstFunctionValue() const override;
913 
914     bool getSourceLocation(QString *fileName, int *line, int *column) const override;
915 };
916 
917 class QMLJS_EXPORT ASTPropertyReference: public Reference
918 {
919     AST::UiPublicMember *m_ast;
920     const Document *m_doc;
921     QString m_onChangedSlotName;
922 
923 public:
924     ASTPropertyReference(AST::UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner);
925     ~ASTPropertyReference();
926 
927     const ASTPropertyReference *asAstPropertyReference() const override;
928 
ast()929     AST::UiPublicMember *ast() const { return m_ast; }
onChangedSlotName()930     QString onChangedSlotName() const { return m_onChangedSlotName; }
931 
932     bool getSourceLocation(QString *fileName, int *line, int *column) const override;
933 
934 private:
935     const Value *value(ReferenceContext *referenceContext) const override;
936 };
937 
938 class QMLJS_EXPORT ASTSignal: public FunctionValue
939 {
940     AST::UiPublicMember *m_ast;
941     const Document *m_doc;
942     QString m_slotName;
943     const ObjectValue *m_bodyScope;
944 
945 public:
946     ASTSignal(AST::UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner);
947     ~ASTSignal();
948 
949     const ASTSignal *asAstSignal() const override;
950 
ast()951     AST::UiPublicMember *ast() const { return m_ast; }
slotName()952     QString slotName() const { return m_slotName; }
bodyScope()953     const ObjectValue *bodyScope() const { return m_bodyScope; }
954 
955     // FunctionValue interface
956     int namedArgumentCount() const override;
957     const Value *argument(int index) const override;
958     QString argumentName(int index) const override;
959 
960     // Value interface
961     bool getSourceLocation(QString *fileName, int *line, int *column) const override;
962 };
963 
964 class QMLJS_EXPORT ASTObjectValue: public ObjectValue
965 {
966     AST::UiQualifiedId *m_typeName;
967     AST::UiObjectInitializer *m_initializer;
968     const Document *m_doc;
969     QList<ASTPropertyReference *> m_properties;
970     QList<ASTSignal *> m_signals;
971     ASTPropertyReference *m_defaultPropertyRef;
972 
973 public:
974     ASTObjectValue(AST::UiQualifiedId *typeName,
975                    AST::UiObjectInitializer *initializer,
976                    const Document *doc,
977                    ValueOwner *valueOwner);
978     ~ASTObjectValue();
979 
980     const ASTObjectValue *asAstObjectValue() const override;
981 
982     bool getSourceLocation(QString *fileName, int *line, int *column) const override;
983     void processMembers(MemberProcessor *processor) const override;
984 
985     QString defaultPropertyName() const;
986 
987     AST::UiObjectInitializer *initializer() const;
988     AST::UiQualifiedId *typeName() const;
989     const Document *document() const;
990 };
991 
992 class QMLJS_EXPORT ImportInfo
993 {
994 public:
995     ImportInfo();
996 
997     static ImportInfo moduleImport(QString uri, LanguageUtils::ComponentVersion version,
998                                    const QString &as, AST::UiImport *ast = nullptr);
999     static ImportInfo pathImport(const QString &docPath, const QString &path,
1000                                  LanguageUtils::ComponentVersion version,
1001                                  const QString &as, AST::UiImport *ast = nullptr);
1002     static ImportInfo invalidImport(AST::UiImport *ast = nullptr);
1003     static ImportInfo implicitDirectoryImport(const QString &directory);
1004     static ImportInfo qrcDirectoryImport(const QString &directory);
1005 
1006     bool isValid() const;
1007     ImportType::Enum type() const;
1008 
1009     // LibraryImport: uri with ',' separator
1010     // Other: non-absolute path
1011     QString name() const;
1012 
1013     // LibraryImport: uri with '/' separator
1014     // Other: absoluteFilePath
1015     QString path() const;
1016 
1017     // null if the import has no 'as', otherwise the target id
1018     QString as() const;
1019 
1020     LanguageUtils::ComponentVersion version() const;
1021     AST::UiImport *ast() const;
1022 
1023 private:
1024     ImportType::Enum m_type;
1025     LanguageUtils::ComponentVersion m_version;
1026     QString m_name;
1027     QString m_path;
1028     QString m_as;
1029     AST::UiImport *m_ast;
1030 };
1031 
1032 class QMLJS_EXPORT Import {
1033 public:
1034     Import();
1035     Import(const Import &other);
1036     Import &operator=(const Import &other);
1037 
1038     // const!
1039     ObjectValue *object;
1040     ImportInfo info;
1041     DependencyInfo::ConstPtr deps;
1042     // uri imports: path to library, else empty
1043     QString libraryPath;
1044     // whether the import succeeded
1045     bool valid;
1046     mutable bool used;
1047 };
1048 
1049 class Imports;
1050 
1051 class QMLJS_EXPORT TypeScope: public ObjectValue
1052 {
1053 public:
1054     TypeScope(const Imports *imports, ValueOwner *valueOwner);
1055 
1056     virtual const Value *lookupMember(const QString &name, const Context *context,
1057                                       const ObjectValue **foundInObject = nullptr,
1058                                       bool examinePrototypes = true) const override;
1059     void processMembers(MemberProcessor *processor) const override;
1060     const TypeScope *asTypeScope() const override;
1061 private:
1062     const Imports *m_imports;
1063 };
1064 
1065 class QMLJS_EXPORT JSImportScope: public ObjectValue
1066 {
1067 public:
1068     JSImportScope(const Imports *imports, ValueOwner *valueOwner);
1069 
1070     virtual const Value *lookupMember(const QString &name, const Context *context,
1071                                       const ObjectValue **foundInObject = nullptr,
1072                                       bool examinePrototypes = true) const override;
1073     void processMembers(MemberProcessor *processor) const override;
1074     const JSImportScope *asJSImportScope() const override;
1075 private:
1076     const Imports *m_imports;
1077 };
1078 
1079 class QMLJS_EXPORT Imports
1080 {
1081 public:
1082     Imports(ValueOwner *valueOwner);
1083 
1084     void append(const Import &import);
1085     void setImportFailed();
1086 
1087     ImportInfo info(const QString &name, const Context *context) const;
1088     QString nameForImportedObject(const ObjectValue *value, const Context *context) const;
1089     bool importFailed() const;
1090 
1091     const QList<Import> &all() const;
1092     const ObjectValue *aliased(const QString &name) const;
1093 
1094     const TypeScope *typeScope() const;
1095     const JSImportScope *jsImportScope() const;
1096 
1097     const ObjectValue *resolveAliasAndMarkUsed(const QString &name) const;
1098 
1099 #ifdef QT_DEBUG
1100     void dump() const;
1101 #endif
1102 
1103 private:
1104     // holds imports in the order they appeared,
1105     // lookup order is back to front
1106     QList<Import> m_imports;
1107     QHash<QString, ObjectValue *> m_aliased;
1108     TypeScope *m_typeScope;
1109     JSImportScope *m_jsImportScope;
1110     bool m_importFailed;
1111 };
1112 
1113 class QMLJS_EXPORT MetaFunction: public FunctionValue
1114 {
1115     LanguageUtils::FakeMetaMethod m_method;
1116 
1117 public:
1118     MetaFunction(const LanguageUtils::FakeMetaMethod &method, ValueOwner *valueOwner);
1119 
1120     int namedArgumentCount() const override;
1121     QString argumentName(int index) const override;
1122     bool isVariadic() const override;
1123     const MetaFunction *asMetaFunction() const override;
1124     const LanguageUtils::FakeMetaMethod &fakeMetaMethod() const;
1125 };
1126 
1127 class QMLJS_EXPORT CustomImportsProvider : public QObject
1128 {
1129     Q_OBJECT
1130 public:
1131     explicit CustomImportsProvider(QObject *parent = nullptr);
1132     virtual ~CustomImportsProvider();
1133 
1134     static const QList<CustomImportsProvider *> allProviders();
1135 
1136     virtual QList<Import> imports(ValueOwner *valueOwner, const Document *context) const = 0;
1137 };
1138 
1139 } // namespace QmlJS
1140