OSDN Git Service

QmlJS: Support module apis defined by QML modules.
[qt-creator-jp/qt-creator-jp.git] / src / libs / qmljs / qmljsinterpreter.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
30 **
31 **************************************************************************/
32
33 #include "qmljsinterpreter.h"
34 #include "qmljsevaluate.h"
35 #include "qmljslink.h"
36 #include "qmljsbind.h"
37 #include "qmljsscopebuilder.h"
38 #include "qmljsscopechain.h"
39 #include "qmljsscopeastpath.h"
40 #include "qmljstypedescriptionreader.h"
41 #include "qmljsvalueowner.h"
42 #include "qmljscontext.h"
43 #include "parser/qmljsast_p.h"
44
45 #include <languageutils/fakemetaobject.h>
46 #include <utils/qtcassert.h>
47
48 #include <QtCore/QFile>
49 #include <QtCore/QDir>
50 #include <QtCore/QString>
51 #include <QtCore/QStringList>
52 #include <QtCore/QMetaObject>
53 #include <QtCore/QMetaProperty>
54 #include <QtCore/QXmlStreamReader>
55 #include <QtCore/QProcess>
56 #include <QtCore/QDebug>
57
58 #include <algorithm>
59
60 using namespace LanguageUtils;
61 using namespace QmlJS;
62 using namespace QmlJS::AST;
63
64 namespace {
65
66 class LookupMember: public MemberProcessor
67 {
68     QString _name;
69     const Value *_value;
70
71     bool process(const QString &name, const Value *value)
72     {
73         if (_value)
74             return false;
75
76         if (name == _name) {
77             _value = value;
78             return false;
79         }
80
81         return true;
82     }
83
84 public:
85     LookupMember(const QString &name)
86         : _name(name), _value(0) {}
87
88     const Value *value() const { return _value; }
89
90     virtual bool processProperty(const QString &name, const Value *value)
91     {
92         return process(name, value);
93     }
94
95     virtual bool processEnumerator(const QString &name, const Value *value)
96     {
97         return process(name, value);
98     }
99
100     virtual bool processSignal(const QString &name, const Value *value)
101     {
102         return process(name, value);
103     }
104
105     virtual bool processSlot(const QString &name, const Value *value)
106     {
107         return process(name, value);
108     }
109
110     virtual bool processGeneratedSlot(const QString &name, const Value *value)
111     {
112         return process(name, value);
113     }
114 };
115
116 class MetaFunction: public FunctionValue
117 {
118     FakeMetaMethod _method;
119
120 public:
121     MetaFunction(const FakeMetaMethod &method, ValueOwner *valueOwner)
122         : FunctionValue(valueOwner), _method(method)
123     {
124     }
125
126     virtual int argumentCount() const
127     {
128         return _method.parameterNames().size();
129     }
130
131     virtual QString argumentName(int index) const
132     {
133         if (index < _method.parameterNames().size())
134             return _method.parameterNames().at(index);
135
136         return FunctionValue::argumentName(index);
137     }
138
139     virtual bool isVariadic() const
140     {
141         return false;
142     }
143
144     virtual const Value *invoke(const Activation *) const
145     {
146         return valueOwner()->unknownValue();
147     }
148 };
149
150 } // end of anonymous namespace
151
152 CppComponentValue::CppComponentValue(FakeMetaObject::ConstPtr metaObject, const QString &className,
153                                const QString &packageName, const ComponentVersion &componentVersion,
154                                const ComponentVersion &importVersion, int metaObjectRevision,
155                                ValueOwner *valueOwner)
156     : ObjectValue(valueOwner),
157       _attachedType(0),
158       _metaObject(metaObject),
159       _moduleName(packageName),
160       _componentVersion(componentVersion),
161       _importVersion(importVersion),
162       _metaObjectRevision(metaObjectRevision)
163 {
164     setClassName(className);
165     int nEnums = metaObject->enumeratorCount();
166     for (int i = 0; i < nEnums; ++i) {
167         FakeMetaEnum fEnum = metaObject->enumerator(i);
168         _enums[fEnum.name()] = new QmlEnumValue(this, i);
169     }
170 }
171
172 CppComponentValue::~CppComponentValue()
173 {
174     delete _metaSignatures;
175     delete _signalScopes;
176 }
177
178 static QString generatedSlotName(const QString &base)
179 {
180     QString slotName = QLatin1String("on");
181     slotName += base.at(0).toUpper();
182     slotName += base.midRef(1);
183     return slotName;
184 }
185
186 const CppComponentValue *CppComponentValue::asCppComponentValue() const
187 {
188     return this;
189 }
190
191 void CppComponentValue::processMembers(MemberProcessor *processor) const
192 {
193     // process the meta enums
194     for (int index = _metaObject->enumeratorOffset(); index < _metaObject->enumeratorCount(); ++index) {
195         FakeMetaEnum e = _metaObject->enumerator(index);
196
197         for (int i = 0; i < e.keyCount(); ++i) {
198             processor->processEnumerator(e.key(i), valueOwner()->numberValue());
199         }
200     }
201
202     // all explicitly defined signal names
203     QSet<QString> explicitSignals;
204
205     // make MetaFunction instances lazily when first needed
206     QList<const Value *> *signatures = _metaSignatures;
207     if (!signatures) {
208         signatures = new QList<const Value *>;
209         signatures->reserve(_metaObject->methodCount());
210         for (int index = 0; index < _metaObject->methodCount(); ++index)
211             signatures->append(new MetaFunction(_metaObject->method(index), valueOwner()));
212         if (!_metaSignatures.testAndSetOrdered(0, signatures)) {
213             delete signatures;
214             signatures = _metaSignatures;
215         }
216     }
217
218     // process the meta methods
219     for (int index = 0; index < _metaObject->methodCount(); ++index) {
220         const FakeMetaMethod method = _metaObject->method(index);
221         if (_metaObjectRevision < method.revision())
222             continue;
223
224         const QString &methodName = _metaObject->method(index).methodName();
225         const Value *signature = signatures->at(index);
226
227         if (method.methodType() == FakeMetaMethod::Slot && method.access() == FakeMetaMethod::Public) {
228             processor->processSlot(methodName, signature);
229
230         } else if (method.methodType() == FakeMetaMethod::Signal && method.access() != FakeMetaMethod::Private) {
231             // process the signal
232             processor->processSignal(methodName, signature);
233             explicitSignals.insert(methodName);
234
235             // process the generated slot
236             const QString &slotName = generatedSlotName(methodName);
237             processor->processGeneratedSlot(slotName, signature);
238         }
239     }
240
241     // process the meta properties
242     for (int index = 0; index < _metaObject->propertyCount(); ++index) {
243         const FakeMetaProperty prop = _metaObject->property(index);
244         if (_metaObjectRevision < prop.revision())
245             continue;
246
247         const QString propertyName = prop.name();
248         processor->processProperty(propertyName, valueForCppName(prop.typeName()));
249
250         // every property always has a onXyzChanged slot, even if the NOTIFY
251         // signal has a different name
252         QString signalName = propertyName;
253         signalName += QLatin1String("Changed");
254         if (!explicitSignals.contains(signalName)) {
255             // process the generated slot
256             const QString &slotName = generatedSlotName(signalName);
257             processor->processGeneratedSlot(slotName, valueOwner()->unknownValue());
258         }
259     }
260
261     if (_attachedType)
262         _attachedType->processMembers(processor);
263
264     ObjectValue::processMembers(processor);
265 }
266
267 const Value *CppComponentValue::valueForCppName(const QString &typeName) const
268 {
269     const CppQmlTypes &cppTypes = valueOwner()->cppQmlTypes();
270
271     // check in the same package/version first
272     const CppComponentValue *objectValue = cppTypes.objectByQualifiedName(
273                 _moduleName, typeName, _importVersion);
274     if (objectValue)
275         return objectValue;
276
277     // fallback to plain cpp name
278     objectValue = cppTypes.objectByCppName(typeName);
279     if (objectValue)
280         return objectValue;
281
282     // try qml builtin type names
283     if (const Value *v = valueOwner()->defaultValueForBuiltinType(typeName)) {
284         if (!v->asUndefinedValue())
285             return v;
286     }
287
288     // map other C++ types
289     if (typeName == QLatin1String("QByteArray")
290             || typeName == QLatin1String("QString")) {
291         return valueOwner()->stringValue();
292     } else if (typeName == QLatin1String("QUrl")) {
293         return valueOwner()->urlValue();
294     } else if (typeName == QLatin1String("long")) {
295         return valueOwner()->intValue();
296     }  else if (typeName == QLatin1String("float")
297                 || typeName == QLatin1String("qreal")) {
298         return valueOwner()->realValue();
299     } else if (typeName == QLatin1String("QFont")) {
300         return valueOwner()->qmlFontObject();
301     } else if (typeName == QLatin1String("QPoint")
302             || typeName == QLatin1String("QPointF")
303             || typeName == QLatin1String("QVector2D")) {
304         return valueOwner()->qmlPointObject();
305     } else if (typeName == QLatin1String("QSize")
306             || typeName == QLatin1String("QSizeF")) {
307         return valueOwner()->qmlSizeObject();
308     } else if (typeName == QLatin1String("QRect")
309             || typeName == QLatin1String("QRectF")) {
310         return valueOwner()->qmlRectObject();
311     } else if (typeName == QLatin1String("QVector3D")) {
312         return valueOwner()->qmlVector3DObject();
313     } else if (typeName == QLatin1String("QColor")) {
314         return valueOwner()->colorValue();
315     } else if (typeName == QLatin1String("QDeclarativeAnchorLine")) {
316         return valueOwner()->anchorLineValue();
317     }
318
319     // might be an enum
320     const CppComponentValue *base = this;
321     const QStringList components = typeName.split(QLatin1String("::"));
322     if (components.size() == 2) {
323         base = valueOwner()->cppQmlTypes().objectByCppName(components.first());
324     }
325     if (base) {
326         if (const QmlEnumValue *value = base->getEnumValue(components.last()))
327             return value;
328     }
329
330     // may still be a cpp based value
331     return valueOwner()->unknownValue();
332 }
333
334 const CppComponentValue *CppComponentValue::prototype() const
335 {
336     Q_ASSERT(!_prototype || value_cast<CppComponentValue>(_prototype));
337     return static_cast<const CppComponentValue *>(_prototype);
338 }
339
340 const CppComponentValue *CppComponentValue::attachedType() const
341 {
342     return _attachedType;
343 }
344
345 void CppComponentValue::setAttachedType(CppComponentValue *value)
346 {
347     _attachedType = value;
348 }
349
350 FakeMetaObject::ConstPtr CppComponentValue::metaObject() const
351 {
352     return _metaObject;
353 }
354
355 QString CppComponentValue::moduleName() const
356 { return _moduleName; }
357
358 ComponentVersion CppComponentValue::componentVersion() const
359 { return _componentVersion; }
360
361 ComponentVersion CppComponentValue::importVersion() const
362 { return _importVersion; }
363
364 QString CppComponentValue::defaultPropertyName() const
365 { return _metaObject->defaultPropertyName(); }
366
367 QString CppComponentValue::propertyType(const QString &propertyName) const
368 {
369     for (const CppComponentValue *it = this; it; it = it->prototype()) {
370         FakeMetaObject::ConstPtr iter = it->_metaObject;
371         int propIdx = iter->propertyIndex(propertyName);
372         if (propIdx != -1) {
373             return iter->property(propIdx).typeName();
374         }
375     }
376     return QString();
377 }
378
379 bool CppComponentValue::isListProperty(const QString &propertyName) const
380 {
381     for (const CppComponentValue *it = this; it; it = it->prototype()) {
382         FakeMetaObject::ConstPtr iter = it->_metaObject;
383         int propIdx = iter->propertyIndex(propertyName);
384         if (propIdx != -1) {
385             return iter->property(propIdx).isList();
386         }
387     }
388     return false;
389 }
390
391 FakeMetaEnum CppComponentValue::getEnum(const QString &typeName, const CppComponentValue **foundInScope) const
392 {
393     for (const CppComponentValue *it = this; it; it = it->prototype()) {
394         FakeMetaObject::ConstPtr iter = it->_metaObject;
395         const int index = iter->enumeratorIndex(typeName);
396         if (index != -1) {
397             if (foundInScope)
398                 *foundInScope = it;
399             return iter->enumerator(index);
400         }
401     }
402     if (foundInScope)
403         *foundInScope = 0;
404     return FakeMetaEnum();
405 }
406
407 const QmlEnumValue *CppComponentValue::getEnumValue(const QString &typeName, const CppComponentValue **foundInScope) const
408 {
409     for (const CppComponentValue *it = this; it; it = it->prototype()) {
410         if (const QmlEnumValue *e = it->_enums.value(typeName)) {
411             if (foundInScope)
412                 *foundInScope = it;
413             return e;
414         }
415     }
416     if (foundInScope)
417         *foundInScope = 0;
418     return 0;
419 }
420
421 const ObjectValue *CppComponentValue::signalScope(const QString &signalName) const
422 {
423     QHash<QString, const ObjectValue *> *scopes = _signalScopes;
424     if (!scopes) {
425         scopes = new QHash<QString, const ObjectValue *>;
426         // usually not all methods are signals
427         scopes->reserve(_metaObject->methodCount() / 2);
428         for (int index = 0; index < _metaObject->methodCount(); ++index) {
429             const FakeMetaMethod &method = _metaObject->method(index);
430             if (method.methodType() != FakeMetaMethod::Signal || method.access() == FakeMetaMethod::Private)
431                 continue;
432
433             const QStringList &parameterNames = method.parameterNames();
434             const QStringList &parameterTypes = method.parameterTypes();
435             QTC_ASSERT(parameterNames.size() == parameterTypes.size(), continue);
436
437             ObjectValue *scope = valueOwner()->newObject(/*prototype=*/0);
438             for (int i = 0; i < parameterNames.size(); ++i) {
439                 const QString &name = parameterNames.at(i);
440                 const QString &type = parameterTypes.at(i);
441                 if (name.isEmpty())
442                     continue;
443                 scope->setMember(name, valueForCppName(type));
444             }
445             scopes->insert(generatedSlotName(method.methodName()), scope);
446         }
447         if (!_signalScopes.testAndSetOrdered(0, scopes)) {
448             delete _signalScopes;
449             scopes = _signalScopes;
450         }
451     }
452
453     return scopes->value(signalName);
454 }
455
456 bool CppComponentValue::isWritable(const QString &propertyName) const
457 {
458     for (const CppComponentValue *it = this; it; it = it->prototype()) {
459         FakeMetaObject::ConstPtr iter = it->_metaObject;
460         int propIdx = iter->propertyIndex(propertyName);
461         if (propIdx != -1) {
462             return iter->property(propIdx).isWritable();
463         }
464     }
465     return false;
466 }
467
468 bool CppComponentValue::isPointer(const QString &propertyName) const
469 {
470     for (const CppComponentValue *it = this; it; it = it->prototype()) {
471         FakeMetaObject::ConstPtr iter = it->_metaObject;
472         int propIdx = iter->propertyIndex(propertyName);
473         if (propIdx != -1) {
474             return iter->property(propIdx).isPointer();
475         }
476     }
477     return false;
478 }
479
480 bool CppComponentValue::hasLocalProperty(const QString &typeName) const
481 {
482     int idx = _metaObject->propertyIndex(typeName);
483     if (idx == -1)
484         return false;
485     return true;
486 }
487
488 bool CppComponentValue::hasProperty(const QString &propertyName) const
489 {
490     for (const CppComponentValue *it = this; it; it = it->prototype()) {
491         FakeMetaObject::ConstPtr iter = it->_metaObject;
492         int propIdx = iter->propertyIndex(propertyName);
493         if (propIdx != -1) {
494             return true;
495         }
496     }
497     return false;
498 }
499
500 bool CppComponentValue::isDerivedFrom(FakeMetaObject::ConstPtr base) const
501 {
502     for (const CppComponentValue *it = this; it; it = it->prototype()) {
503         FakeMetaObject::ConstPtr iter = it->_metaObject;
504         if (iter == base)
505             return true;
506     }
507     return false;
508 }
509
510 QmlEnumValue::QmlEnumValue(const CppComponentValue *owner, int enumIndex)
511     : _owner(owner)
512     , _enumIndex(enumIndex)
513 {
514     owner->valueOwner()->registerValue(this);
515 }
516
517 QmlEnumValue::~QmlEnumValue()
518 {
519 }
520
521 const QmlEnumValue *QmlEnumValue::asQmlEnumValue() const
522 {
523     return this;
524 }
525
526 QString QmlEnumValue::name() const
527 {
528     return _owner->metaObject()->enumerator(_enumIndex).name();
529 }
530
531 QStringList QmlEnumValue::keys() const
532 {
533     return _owner->metaObject()->enumerator(_enumIndex).keys();
534 }
535
536 const CppComponentValue *QmlEnumValue::owner() const
537 {
538     return _owner;
539 }
540
541 ////////////////////////////////////////////////////////////////////////////////
542 // ValueVisitor
543 ////////////////////////////////////////////////////////////////////////////////
544 ValueVisitor::ValueVisitor()
545 {
546 }
547
548 ValueVisitor::~ValueVisitor()
549 {
550 }
551
552 void ValueVisitor::visit(const NullValue *)
553 {
554 }
555
556 void ValueVisitor::visit(const UndefinedValue *)
557 {
558 }
559
560 void ValueVisitor::visit(const UnknownValue *)
561 {
562 }
563
564 void ValueVisitor::visit(const NumberValue *)
565 {
566 }
567
568 void ValueVisitor::visit(const BooleanValue *)
569 {
570 }
571
572 void ValueVisitor::visit(const StringValue *)
573 {
574 }
575
576 void ValueVisitor::visit(const ObjectValue *)
577 {
578 }
579
580 void ValueVisitor::visit(const FunctionValue *)
581 {
582 }
583
584 void ValueVisitor::visit(const Reference *)
585 {
586 }
587
588 void ValueVisitor::visit(const ColorValue *)
589 {
590 }
591
592 void ValueVisitor::visit(const AnchorLineValue *)
593 {
594 }
595
596 ////////////////////////////////////////////////////////////////////////////////
597 // Value
598 ////////////////////////////////////////////////////////////////////////////////
599 Value::Value()
600 {
601 }
602
603 Value::~Value()
604 {
605 }
606
607 bool Value::getSourceLocation(QString *, int *, int *) const
608 {
609     return false;
610 }
611
612 const NullValue *Value::asNullValue() const
613 {
614     return 0;
615 }
616
617 const UndefinedValue *Value::asUndefinedValue() const
618 {
619     return 0;
620 }
621
622 const UnknownValue *Value::asUnknownValue() const
623 {
624     return 0;
625 }
626
627 const NumberValue *Value::asNumberValue() const
628 {
629     return 0;
630 }
631
632 const IntValue *Value::asIntValue() const
633 {
634     return 0;
635 }
636
637 const RealValue *Value::asRealValue() const
638 {
639     return 0;
640 }
641
642 const BooleanValue *Value::asBooleanValue() const
643 {
644     return 0;
645 }
646
647 const StringValue *Value::asStringValue() const
648 {
649     return 0;
650 }
651
652 const UrlValue *Value::asUrlValue() const
653 {
654     return 0;
655 }
656
657 const ObjectValue *Value::asObjectValue() const
658 {
659     return 0;
660 }
661
662 const FunctionValue *Value::asFunctionValue() const
663 {
664     return 0;
665 }
666
667 const Reference *Value::asReference() const
668 {
669     return 0;
670 }
671
672 const ColorValue *Value::asColorValue() const
673 {
674     return 0;
675 }
676
677 const AnchorLineValue *Value::asAnchorLineValue() const
678 {
679     return 0;
680 }
681
682 const CppComponentValue *Value::asCppComponentValue() const
683 {
684     return 0;
685 }
686
687 const ASTObjectValue *Value::asAstObjectValue() const
688 {
689     return 0;
690 }
691
692 const QmlEnumValue *Value::asQmlEnumValue() const
693 {
694     return 0;
695 }
696
697 const QmlPrototypeReference *Value::asQmlPrototypeReference() const
698 {
699     return 0;
700 }
701
702 const ASTPropertyReference *Value::asAstPropertyReference() const
703 {
704     return 0;
705 }
706
707 const ASTSignal *Value::asAstSignal() const
708 {
709     return 0;
710 }
711
712 ////////////////////////////////////////////////////////////////////////////////
713 // Values
714 ////////////////////////////////////////////////////////////////////////////////
715 const NullValue *NullValue::asNullValue() const
716 {
717     return this;
718 }
719
720 void NullValue::accept(ValueVisitor *visitor) const
721 {
722     visitor->visit(this);
723 }
724
725 const UndefinedValue *UndefinedValue::asUndefinedValue() const
726 {
727     return this;
728 }
729
730 void UnknownValue::accept(ValueVisitor *visitor) const
731 {
732     visitor->visit(this);
733 }
734
735 const UnknownValue *UnknownValue::asUnknownValue() const
736 {
737     return this;
738 }
739
740 void UndefinedValue::accept(ValueVisitor *visitor) const
741 {
742     visitor->visit(this);
743 }
744 const NumberValue *NumberValue::asNumberValue() const
745 {
746     return this;
747 }
748
749 const RealValue *RealValue::asRealValue() const
750 {
751     return this;
752 }
753
754 const IntValue *IntValue::asIntValue() const
755 {
756     return this;
757 }
758
759 void NumberValue::accept(ValueVisitor *visitor) const
760 {
761     visitor->visit(this);
762 }
763
764 const BooleanValue *BooleanValue::asBooleanValue() const
765 {
766     return this;
767 }
768
769 void BooleanValue::accept(ValueVisitor *visitor) const
770 {
771     visitor->visit(this);
772 }
773
774 const StringValue *StringValue::asStringValue() const
775 {
776     return this;
777 }
778
779 const UrlValue *UrlValue::asUrlValue() const
780 {
781     return this;
782 }
783
784 void StringValue::accept(ValueVisitor *visitor) const
785 {
786     visitor->visit(this);
787 }
788
789 Reference::Reference(ValueOwner *valueOwner)
790     : _valueOwner(valueOwner)
791 {
792     _valueOwner->registerValue(this);
793 }
794
795 Reference::~Reference()
796 {
797 }
798
799 ValueOwner *Reference::valueOwner() const
800 {
801     return _valueOwner;
802 }
803
804 const Reference *Reference::asReference() const
805 {
806     return this;
807 }
808
809 void Reference::accept(ValueVisitor *visitor) const
810 {
811     visitor->visit(this);
812 }
813
814 const Value *Reference::value(ReferenceContext *) const
815 {
816     return _valueOwner->undefinedValue();
817 }
818
819 void ColorValue::accept(ValueVisitor *visitor) const
820 {
821     visitor->visit(this);
822 }
823
824 const ColorValue *ColorValue::asColorValue() const
825 {
826     return this;
827 }
828
829 void AnchorLineValue::accept(ValueVisitor *visitor) const
830 {
831     visitor->visit(this);
832 }
833
834 const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const
835 {
836     return this;
837 }
838
839 MemberProcessor::MemberProcessor()
840 {
841 }
842
843 MemberProcessor::~MemberProcessor()
844 {
845 }
846
847 bool MemberProcessor::processProperty(const QString &, const Value *)
848 {
849     return true;
850 }
851
852 bool MemberProcessor::processEnumerator(const QString &, const Value *)
853 {
854     return true;
855 }
856
857 bool MemberProcessor::processSignal(const QString &, const Value *)
858 {
859     return true;
860 }
861
862 bool MemberProcessor::processSlot(const QString &, const Value *)
863 {
864     return true;
865 }
866
867 bool MemberProcessor::processGeneratedSlot(const QString &, const Value *)
868 {
869     return true;
870 }
871
872 ObjectValue::ObjectValue(ValueOwner *valueOwner)
873     : _valueOwner(valueOwner),
874       _prototype(0)
875 {
876     valueOwner->registerValue(this);
877 }
878
879 ObjectValue::~ObjectValue()
880 {
881 }
882
883 ValueOwner *ObjectValue::valueOwner() const
884 {
885     return _valueOwner;
886 }
887
888 QString ObjectValue::className() const
889 {
890     return _className;
891 }
892
893 void ObjectValue::setClassName(const QString &className)
894 {
895     _className = className;
896 }
897
898 const Value *ObjectValue::prototype() const
899 {
900     return _prototype;
901 }
902
903 const ObjectValue *ObjectValue::prototype(const Context *context) const
904 {
905     const ObjectValue *prototypeObject = value_cast<ObjectValue>(_prototype);
906     if (! prototypeObject) {
907         if (const Reference *prototypeReference = value_cast<Reference>(_prototype)) {
908             prototypeObject = value_cast<ObjectValue>(context->lookupReference(prototypeReference));
909         }
910     }
911     return prototypeObject;
912 }
913
914 void ObjectValue::setPrototype(const Value *prototype)
915 {
916     _prototype = prototype;
917 }
918
919 void ObjectValue::setMember(const QString &name, const Value *value)
920 {
921     _members[name] = value;
922 }
923
924 void ObjectValue::removeMember(const QString &name)
925 {
926     _members.remove(name);
927 }
928
929 const ObjectValue *ObjectValue::asObjectValue() const
930 {
931     return this;
932 }
933
934 void ObjectValue::accept(ValueVisitor *visitor) const
935 {
936     visitor->visit(this);
937 }
938
939 bool ObjectValue::checkPrototype(const ObjectValue *, QSet<const ObjectValue *> *) const
940 {
941 #if 0
942     const int previousSize = processed->size();
943     processed->insert(this);
944
945     if (previousSize != processed->size()) {
946         if (this == proto)
947             return false;
948
949         if (prototype() && ! prototype()->checkPrototype(proto, processed))
950             return false;
951
952         return true;
953     }
954 #endif
955     return false;
956 }
957
958 void ObjectValue::processMembers(MemberProcessor *processor) const
959 {
960     QHashIterator<QString, const Value *> it(_members);
961
962     while (it.hasNext()) {
963         it.next();
964
965         if (! processor->processProperty(it.key(), it.value()))
966             break;
967     }
968 }
969
970 const Value *ObjectValue::lookupMember(const QString &name, const Context *context,
971                                        const ObjectValue **foundInObject,
972                                        bool examinePrototypes) const
973 {
974     if (const Value *m = _members.value(name)) {
975         if (foundInObject)
976             *foundInObject = this;
977         return m;
978     } else {
979         LookupMember slowLookup(name);
980         processMembers(&slowLookup);
981         if (slowLookup.value()) {
982             if (foundInObject)
983                 *foundInObject = this;
984             return slowLookup.value();
985         }
986     }
987
988     if (examinePrototypes && context) {
989         PrototypeIterator iter(this, context);
990         iter.next(); // skip this
991         while (iter.hasNext()) {
992             const ObjectValue *prototypeObject = iter.next();
993             if (const Value *m = prototypeObject->lookupMember(name, context, foundInObject, false))
994                 return m;
995         }
996     }
997
998     if (foundInObject)
999         *foundInObject = 0;
1000     return 0;
1001 }
1002
1003 PrototypeIterator::PrototypeIterator(const ObjectValue *start, const Context *context)
1004     : m_current(0)
1005     , m_next(start)
1006     , m_context(context)
1007     , m_error(NoError)
1008 {
1009     if (start)
1010         m_prototypes.reserve(10);
1011 }
1012
1013 PrototypeIterator::PrototypeIterator(const ObjectValue *start, const ContextPtr &context)
1014     : m_current(0)
1015     , m_next(start)
1016     , m_context(context.data())
1017     , m_error(NoError)
1018 {
1019     if (start)
1020         m_prototypes.reserve(10);
1021 }
1022
1023 bool PrototypeIterator::hasNext()
1024 {
1025     if (m_next)
1026         return true;
1027     if (!m_current)
1028         return false;
1029     const Value *proto = m_current->prototype();
1030     if (!proto)
1031         return false;
1032
1033     m_next = value_cast<ObjectValue>(proto);
1034     if (! m_next)
1035         m_next = value_cast<ObjectValue>(m_context->lookupReference(proto));
1036     if (!m_next) {
1037         m_error = ReferenceResolutionError;
1038         return false;
1039     }
1040     if (m_prototypes.contains(m_next)) {
1041         m_error = CycleError;
1042         m_next = 0;
1043         return false;
1044     }
1045     return true;
1046 }
1047
1048 const ObjectValue *PrototypeIterator::next()
1049 {
1050     if (hasNext()) {
1051         m_current = m_next;
1052         m_prototypes += m_next;
1053         m_next = 0;
1054         return m_current;
1055     }
1056     return 0;
1057 }
1058
1059 const ObjectValue *PrototypeIterator::peekNext()
1060 {
1061     if (hasNext()) {
1062         return m_next;
1063     }
1064     return 0;
1065 }
1066
1067 PrototypeIterator::Error PrototypeIterator::error() const
1068 {
1069     return m_error;
1070 }
1071
1072 QList<const ObjectValue *> PrototypeIterator::all()
1073 {
1074     while (hasNext())
1075         next();
1076     return m_prototypes;
1077 }
1078
1079 Activation::Activation(Context *parentContext)
1080     : _thisObject(0),
1081       _calledAsFunction(true),
1082       _parentContext(parentContext)
1083 {
1084 }
1085
1086 Activation::~Activation()
1087 {
1088 }
1089
1090 Context *Activation::parentContext() const
1091 {
1092     return _parentContext;
1093 }
1094
1095 Context *Activation::context() const
1096 {
1097     // ### FIXME: Real context for activations.
1098     return 0;
1099 }
1100
1101 bool Activation::calledAsConstructor() const
1102 {
1103     return ! _calledAsFunction;
1104 }
1105
1106 void Activation::setCalledAsConstructor(bool calledAsConstructor)
1107 {
1108     _calledAsFunction = ! calledAsConstructor;
1109 }
1110
1111 bool Activation::calledAsFunction() const
1112 {
1113     return _calledAsFunction;
1114 }
1115
1116 void Activation::setCalledAsFunction(bool calledAsFunction)
1117 {
1118     _calledAsFunction = calledAsFunction;
1119 }
1120
1121 ObjectValue *Activation::thisObject() const
1122 {
1123     return _thisObject;
1124 }
1125
1126 void Activation::setThisObject(ObjectValue *thisObject)
1127 {
1128     _thisObject = thisObject;
1129 }
1130
1131 ValueList Activation::arguments() const
1132 {
1133     return _arguments;
1134 }
1135
1136 void Activation::setArguments(const ValueList &arguments)
1137 {
1138     _arguments = arguments;
1139 }
1140
1141 FunctionValue::FunctionValue(ValueOwner *valueOwner)
1142     : ObjectValue(valueOwner)
1143 {
1144     setMember(QLatin1String("length"), valueOwner->numberValue());
1145 }
1146
1147 FunctionValue::~FunctionValue()
1148 {
1149 }
1150
1151 const Value *FunctionValue::construct(const ValueList &actuals) const
1152 {
1153     Activation activation;
1154     activation.setCalledAsConstructor(true);
1155     activation.setThisObject(valueOwner()->newObject());
1156     activation.setArguments(actuals);
1157     return invoke(&activation);
1158 }
1159
1160 const Value *FunctionValue::call(const ValueList &actuals) const
1161 {
1162     Activation activation;
1163     activation.setCalledAsFunction(true);
1164     activation.setThisObject(valueOwner()->globalObject()); // ### FIXME: it should be `null'
1165     activation.setArguments(actuals);
1166     return invoke(&activation);
1167 }
1168
1169 const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList &actuals) const
1170 {
1171     Activation activation;
1172     activation.setCalledAsFunction(true);
1173     activation.setThisObject(const_cast<ObjectValue *>(thisObject)); // ### FIXME: remove the const_cast
1174     activation.setArguments(actuals);
1175     return invoke(&activation);
1176 }
1177
1178 const Value *FunctionValue::returnValue() const
1179 {
1180     return valueOwner()->unknownValue();
1181 }
1182
1183 int FunctionValue::argumentCount() const
1184 {
1185     return 0;
1186 }
1187
1188 const Value *FunctionValue::argument(int) const
1189 {
1190     return valueOwner()->unknownValue();
1191 }
1192
1193 QString FunctionValue::argumentName(int index) const
1194 {
1195     return QString::fromLatin1("arg%1").arg(index + 1);
1196 }
1197
1198 bool FunctionValue::isVariadic() const
1199 {
1200     return true;
1201 }
1202
1203 const Value *FunctionValue::invoke(const Activation *activation) const
1204 {
1205     return activation->thisObject(); // ### FIXME: it should return undefined
1206 }
1207
1208 const FunctionValue *FunctionValue::asFunctionValue() const
1209 {
1210     return this;
1211 }
1212
1213 void FunctionValue::accept(ValueVisitor *visitor) const
1214 {
1215     visitor->visit(this);
1216 }
1217
1218 Function::Function(ValueOwner *valueOwner)
1219     : FunctionValue(valueOwner), _returnValue(0)
1220 {
1221     setClassName("Function");
1222 }
1223
1224 Function::~Function()
1225 {
1226 }
1227
1228 void Function::addArgument(const Value *argument, const QString &name)
1229 {
1230     if (!name.isEmpty()) {
1231         while (_argumentNames.size() < _arguments.size())
1232             _argumentNames.push_back(QString());
1233         _argumentNames.push_back(name);
1234     }
1235     _arguments.push_back(argument);
1236 }
1237
1238 const Value *Function::returnValue() const
1239 {
1240     return _returnValue;
1241 }
1242
1243 void Function::setReturnValue(const Value *returnValue)
1244 {
1245     _returnValue = returnValue;
1246 }
1247
1248 int Function::argumentCount() const
1249 {
1250     return _arguments.size();
1251 }
1252
1253 const Value *Function::argument(int index) const
1254 {
1255     return _arguments.at(index);
1256 }
1257
1258 QString Function::argumentName(int index) const
1259 {
1260     if (index < _argumentNames.size()) {
1261         const QString name = _argumentNames.at(index);
1262         if (!name.isEmpty())
1263             return _argumentNames.at(index);
1264     }
1265     return FunctionValue::argumentName(index);
1266 }
1267
1268 const Value *Function::invoke(const Activation *) const
1269 {
1270     return _returnValue;
1271 }
1272
1273 ////////////////////////////////////////////////////////////////////////////////
1274 // typing environment
1275 ////////////////////////////////////////////////////////////////////////////////
1276
1277 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::defaultLibraryObjects;
1278 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::defaultQtObjects;
1279
1280 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles, QStringList *errors, QStringList *warnings)
1281 {
1282     QHash<QString, FakeMetaObject::ConstPtr> newObjects;
1283
1284     foreach (const QFileInfo &qmlTypeFile, qmlTypeFiles) {
1285         QString error, warning;
1286         QFile file(qmlTypeFile.absoluteFilePath());
1287         if (file.open(QIODevice::ReadOnly)) {
1288             QByteArray contents = file.readAll();
1289             file.close();
1290
1291             parseQmlTypeDescriptions(contents, &newObjects, 0, &error, &warning);
1292         } else {
1293             error = file.errorString();
1294         }
1295         if (!error.isEmpty()) {
1296             errors->append(TypeDescriptionReader::tr(
1297                                "Errors while loading qmltypes from %1:\n%2").arg(
1298                                qmlTypeFile.absoluteFilePath(), error));
1299         }
1300         if (!warning.isEmpty()) {
1301             warnings->append(TypeDescriptionReader::tr(
1302                                  "Warnings while loading qmltypes from %1:\n%2").arg(
1303                                  qmlTypeFile.absoluteFilePath(), error));
1304         }
1305     }
1306
1307     return newObjects;
1308 }
1309
1310 void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml,
1311                                                  BuiltinObjects *newObjects,
1312                                                  QList<ModuleApiInfo> *newModuleApis,
1313                                                  QString *errorMessage,
1314                                                  QString *warningMessage)
1315 {
1316     errorMessage->clear();
1317     warningMessage->clear();
1318     TypeDescriptionReader reader(QString::fromUtf8(xml));
1319     if (!reader(newObjects, newModuleApis)) {
1320         if (reader.errorMessage().isEmpty()) {
1321             *errorMessage = QLatin1String("unknown error");
1322         } else {
1323             *errorMessage = reader.errorMessage();
1324         }
1325     }
1326     *warningMessage = reader.warningMessage();
1327 }
1328
1329 CppQmlTypes::CppQmlTypes(ValueOwner *valueOwner)
1330     : _valueOwner(valueOwner)
1331 {
1332 }
1333
1334 const QLatin1String CppQmlTypes::defaultPackage("<default>");
1335 const QLatin1String CppQmlTypes::cppPackage("<cpp>");
1336
1337 template <typename T>
1338 void CppQmlTypes::load(const T &fakeMetaObjects, const QString &overridePackage)
1339 {
1340     QList<CppComponentValue *> newCppTypes;
1341     foreach (const FakeMetaObject::ConstPtr &fmo, fakeMetaObjects) {
1342         foreach (const FakeMetaObject::Export &exp, fmo->exports()) {
1343             QString package = exp.package;
1344             if (package.isEmpty())
1345                 package = overridePackage;
1346             _fakeMetaObjectsByPackage[package].insert(fmo);
1347
1348             // make versionless cpp types directly
1349             // needed for access to property types that are not exported, like QDeclarativeAnchors
1350             if (exp.package == cppPackage) {
1351                 QTC_ASSERT(exp.version == ComponentVersion(), continue);
1352                 QTC_ASSERT(exp.type == fmo->className(), continue);
1353                 CppComponentValue *cppValue = new CppComponentValue(
1354                             fmo, fmo->className(), cppPackage, ComponentVersion(), ComponentVersion(),
1355                             ComponentVersion::MaxVersion, _valueOwner);
1356                 _objectsByQualifiedName[qualifiedName(cppPackage, fmo->className(), ComponentVersion())] = cppValue;
1357                 newCppTypes += cppValue;
1358             }
1359         }
1360     }
1361
1362     // set prototypes of cpp types
1363     foreach (CppComponentValue *object, newCppTypes) {
1364         const QString &protoCppName = object->metaObject()->superclassName();
1365         const CppComponentValue *proto = objectByCppName(protoCppName);
1366         if (proto)
1367             object->setPrototype(proto);
1368     }
1369 }
1370 // explicitly instantiate load for list and hash
1371 template void CppQmlTypes::load< QList<FakeMetaObject::ConstPtr> >(const QList<FakeMetaObject::ConstPtr> &, const QString &);
1372 template void CppQmlTypes::load< QHash<QString, FakeMetaObject::ConstPtr> >(const QHash<QString, FakeMetaObject::ConstPtr> &, const QString &);
1373
1374 QList<const CppComponentValue *> CppQmlTypes::createObjectsForImport(const QString &package, ComponentVersion version)
1375 {
1376     QList<const CppComponentValue *> exportedObjects;
1377     QList<const CppComponentValue *> newObjects;
1378
1379     // make new exported objects
1380     foreach (const FakeMetaObject::ConstPtr &fmo, _fakeMetaObjectsByPackage.value(package)) {
1381         // find the highest-version export
1382         FakeMetaObject::Export bestExport;
1383         foreach (const FakeMetaObject::Export &exp, fmo->exports()) {
1384             if (exp.package != package || (version.isValid() && exp.version > version))
1385                 continue;
1386             if (!bestExport.isValid() || exp.version > bestExport.version)
1387                 bestExport = exp;
1388         }
1389         if (!bestExport.isValid())
1390             continue;
1391
1392         // if it already exists, skip
1393         const QString key = qualifiedName(package, fmo->className(), version);
1394         if (_objectsByQualifiedName.contains(key))
1395             continue;
1396
1397         QString name = bestExport.type;
1398         bool exported = true;
1399         if (name.isEmpty()) {
1400             exported = false;
1401             name = fmo->className();
1402         }
1403
1404         CppComponentValue *newObject = new CppComponentValue(
1405                     fmo, name, package, bestExport.version, version,
1406                     bestExport.metaObjectRevision, _valueOwner);
1407
1408         // use package.cppname importversion as key
1409         _objectsByQualifiedName.insert(key, newObject);
1410         if (exported)
1411             exportedObjects += newObject;
1412         newObjects += newObject;
1413     }
1414
1415     // set their prototypes, creating them if necessary
1416     foreach (const CppComponentValue *cobject, newObjects) {
1417         CppComponentValue *object = const_cast<CppComponentValue *>(cobject);
1418         while (!object->prototype()) {
1419             const QString &protoCppName = object->metaObject()->superclassName();
1420             if (protoCppName.isEmpty())
1421                 break;
1422
1423             // if the prototype already exists, done
1424             const QString key = qualifiedName(object->moduleName(), protoCppName, version);
1425             if (const CppComponentValue *proto = _objectsByQualifiedName.value(key)) {
1426                 object->setPrototype(proto);
1427                 break;
1428             }
1429
1430             // get the fmo via the cpp name
1431             const CppComponentValue *cppProto = objectByCppName(protoCppName);
1432             if (!cppProto)
1433                 break;
1434             FakeMetaObject::ConstPtr protoFmo = cppProto->metaObject();
1435
1436             // make a new object
1437             CppComponentValue *proto = new CppComponentValue(
1438                         protoFmo, protoCppName, object->moduleName(), ComponentVersion(),
1439                         object->importVersion(), ComponentVersion::MaxVersion, _valueOwner);
1440             _objectsByQualifiedName.insert(key, proto);
1441             object->setPrototype(proto);
1442
1443             // maybe set prototype of prototype
1444             object = proto;
1445         }
1446     }
1447
1448     return exportedObjects;
1449 }
1450
1451 bool CppQmlTypes::hasModule(const QString &module) const
1452 {
1453     return _fakeMetaObjectsByPackage.contains(module);
1454 }
1455
1456 QString CppQmlTypes::qualifiedName(const QString &module, const QString &type, ComponentVersion version)
1457 {
1458     return QString("%1/%2 %3").arg(
1459                 module, type,
1460                 version.toString());
1461
1462 }
1463
1464 const CppComponentValue *CppQmlTypes::objectByQualifiedName(const QString &name) const
1465 {
1466     return _objectsByQualifiedName.value(name);
1467 }
1468
1469 const CppComponentValue *CppQmlTypes::objectByQualifiedName(const QString &package, const QString &type,
1470                                                          ComponentVersion version) const
1471 {
1472     return objectByQualifiedName(qualifiedName(package, type, version));
1473 }
1474
1475 const CppComponentValue *CppQmlTypes::objectByCppName(const QString &cppName) const
1476 {
1477     return objectByQualifiedName(qualifiedName(cppPackage, cppName, ComponentVersion()));
1478 }
1479
1480
1481 ConvertToNumber::ConvertToNumber(ValueOwner *valueOwner)
1482     : _valueOwner(valueOwner), _result(0)
1483 {
1484 }
1485
1486 const Value *ConvertToNumber::operator()(const Value *value)
1487 {
1488     const Value *previousValue = switchResult(0);
1489
1490     if (value)
1491         value->accept(this);
1492
1493     return switchResult(previousValue);
1494 }
1495
1496 const Value *ConvertToNumber::switchResult(const Value *value)
1497 {
1498     const Value *previousResult = _result;
1499     _result = value;
1500     return previousResult;
1501 }
1502
1503 void ConvertToNumber::visit(const NullValue *)
1504 {
1505     _result = _valueOwner->numberValue();
1506 }
1507
1508 void ConvertToNumber::visit(const UndefinedValue *)
1509 {
1510     _result = _valueOwner->numberValue();
1511 }
1512
1513 void ConvertToNumber::visit(const NumberValue *value)
1514 {
1515     _result = value;
1516 }
1517
1518 void ConvertToNumber::visit(const BooleanValue *)
1519 {
1520     _result = _valueOwner->numberValue();
1521 }
1522
1523 void ConvertToNumber::visit(const StringValue *)
1524 {
1525     _result = _valueOwner->numberValue();
1526 }
1527
1528 void ConvertToNumber::visit(const ObjectValue *object)
1529 {
1530     if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(object->lookupMember("valueOf", ContextPtr()))) {
1531         _result = value_cast<NumberValue>(valueOfMember->call(object)); // ### invoke convert-to-number?
1532     }
1533 }
1534
1535 void ConvertToNumber::visit(const FunctionValue *object)
1536 {
1537     if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(object->lookupMember("valueOf", ContextPtr()))) {
1538         _result = value_cast<NumberValue>(valueOfMember->call(object)); // ### invoke convert-to-number?
1539     }
1540 }
1541
1542 ConvertToString::ConvertToString(ValueOwner *valueOwner)
1543     : _valueOwner(valueOwner), _result(0)
1544 {
1545 }
1546
1547 const Value *ConvertToString::operator()(const Value *value)
1548 {
1549     const Value *previousValue = switchResult(0);
1550
1551     if (value)
1552         value->accept(this);
1553
1554     return switchResult(previousValue);
1555 }
1556
1557 const Value *ConvertToString::switchResult(const Value *value)
1558 {
1559     const Value *previousResult = _result;
1560     _result = value;
1561     return previousResult;
1562 }
1563
1564 void ConvertToString::visit(const NullValue *)
1565 {
1566     _result = _valueOwner->stringValue();
1567 }
1568
1569 void ConvertToString::visit(const UndefinedValue *)
1570 {
1571     _result = _valueOwner->stringValue();
1572 }
1573
1574 void ConvertToString::visit(const NumberValue *)
1575 {
1576     _result = _valueOwner->stringValue();
1577 }
1578
1579 void ConvertToString::visit(const BooleanValue *)
1580 {
1581     _result = _valueOwner->stringValue();
1582 }
1583
1584 void ConvertToString::visit(const StringValue *value)
1585 {
1586     _result = value;
1587 }
1588
1589 void ConvertToString::visit(const ObjectValue *object)
1590 {
1591     if (const FunctionValue *toStringMember = value_cast<FunctionValue>(object->lookupMember("toString", ContextPtr()))) {
1592         _result = value_cast<StringValue>(toStringMember->call(object)); // ### invoke convert-to-string?
1593     }
1594 }
1595
1596 void ConvertToString::visit(const FunctionValue *object)
1597 {
1598     if (const FunctionValue *toStringMember = value_cast<FunctionValue>(object->lookupMember("toString", ContextPtr()))) {
1599         _result = value_cast<StringValue>(toStringMember->call(object)); // ### invoke convert-to-string?
1600     }
1601 }
1602
1603 ConvertToObject::ConvertToObject(ValueOwner *valueOwner)
1604     : _valueOwner(valueOwner), _result(0)
1605 {
1606 }
1607
1608 const Value *ConvertToObject::operator()(const Value *value)
1609 {
1610     const Value *previousValue = switchResult(0);
1611
1612     if (value)
1613         value->accept(this);
1614
1615     return switchResult(previousValue);
1616 }
1617
1618 const Value *ConvertToObject::switchResult(const Value *value)
1619 {
1620     const Value *previousResult = _result;
1621     _result = value;
1622     return previousResult;
1623 }
1624
1625 void ConvertToObject::visit(const NullValue *value)
1626 {
1627     _result = value;
1628 }
1629
1630 void ConvertToObject::visit(const UndefinedValue *)
1631 {
1632     _result = _valueOwner->nullValue();
1633 }
1634
1635 void ConvertToObject::visit(const NumberValue *value)
1636 {
1637     ValueList actuals;
1638     actuals.append(value);
1639     _result = _valueOwner->numberCtor()->construct(actuals);
1640 }
1641
1642 void ConvertToObject::visit(const BooleanValue *value)
1643 {
1644     ValueList actuals;
1645     actuals.append(value);
1646     _result = _valueOwner->booleanCtor()->construct(actuals);
1647 }
1648
1649 void ConvertToObject::visit(const StringValue *value)
1650 {
1651     ValueList actuals;
1652     actuals.append(value);
1653     _result = _valueOwner->stringCtor()->construct(actuals);
1654 }
1655
1656 void ConvertToObject::visit(const ObjectValue *object)
1657 {
1658     _result = object;
1659 }
1660
1661 void ConvertToObject::visit(const FunctionValue *object)
1662 {
1663     _result = object;
1664 }
1665
1666 QString TypeId::operator()(const Value *value)
1667 {
1668     _result = QLatin1String("unknown");
1669
1670     if (value)
1671         value->accept(this);
1672
1673     return _result;
1674 }
1675
1676 void TypeId::visit(const NullValue *)
1677 {
1678     _result = QLatin1String("null");
1679 }
1680
1681 void TypeId::visit(const UndefinedValue *)
1682 {
1683     _result = QLatin1String("undefined");
1684 }
1685
1686 void TypeId::visit(const NumberValue *)
1687 {
1688     _result = QLatin1String("number");
1689 }
1690
1691 void TypeId::visit(const BooleanValue *)
1692 {
1693     _result = QLatin1String("boolean");
1694 }
1695
1696 void TypeId::visit(const StringValue *)
1697 {
1698     _result = QLatin1String("string");
1699 }
1700
1701 void TypeId::visit(const ObjectValue *object)
1702 {
1703     _result = object->className();
1704
1705     if (_result.isEmpty())
1706         _result = QLatin1String("object");
1707 }
1708
1709 void TypeId::visit(const FunctionValue *object)
1710 {
1711     _result = object->className();
1712
1713     if (_result.isEmpty())
1714         _result = QLatin1String("Function");
1715 }
1716
1717 void TypeId::visit(const ColorValue *)
1718 {
1719     _result = QLatin1String("string");
1720 }
1721
1722 void TypeId::visit(const AnchorLineValue *)
1723 {
1724     _result = QLatin1String("AnchorLine");
1725 }
1726
1727 ASTObjectValue::ASTObjectValue(UiQualifiedId *typeName,
1728                                UiObjectInitializer *initializer,
1729                                const Document *doc,
1730                                ValueOwner *valueOwner)
1731     : ObjectValue(valueOwner), _typeName(typeName), _initializer(initializer), _doc(doc), _defaultPropertyRef(0)
1732 {
1733     if (_initializer) {
1734         for (UiObjectMemberList *it = _initializer->members; it; it = it->next) {
1735             UiObjectMember *member = it->member;
1736             if (UiPublicMember *def = cast<UiPublicMember *>(member)) {
1737                 if (def->type == UiPublicMember::Property && !def->name.isEmpty() && !def->memberType.isEmpty()) {
1738                     ASTPropertyReference *ref = new ASTPropertyReference(def, _doc, valueOwner);
1739                     _properties.append(ref);
1740                     if (def->defaultToken.isValid())
1741                         _defaultPropertyRef = ref;
1742                 } else if (def->type == UiPublicMember::Signal && !def->name.isEmpty()) {
1743                     ASTSignal *ref = new ASTSignal(def, _doc, valueOwner);
1744                     _signals.append(ref);
1745                 }
1746             }
1747         }
1748     }
1749 }
1750
1751 ASTObjectValue::~ASTObjectValue()
1752 {
1753 }
1754
1755 const ASTObjectValue *ASTObjectValue::asAstObjectValue() const
1756 {
1757     return this;
1758 }
1759
1760 bool ASTObjectValue::getSourceLocation(QString *fileName, int *line, int *column) const
1761 {
1762     *fileName = _doc->fileName();
1763     *line = _typeName->identifierToken.startLine;
1764     *column = _typeName->identifierToken.startColumn;
1765     return true;
1766 }
1767
1768 void ASTObjectValue::processMembers(MemberProcessor *processor) const
1769 {
1770     foreach (ASTPropertyReference *ref, _properties) {
1771         processor->processProperty(ref->ast()->name.toString(), ref);
1772         // ### Should get a different value?
1773         processor->processGeneratedSlot(ref->onChangedSlotName(), ref);
1774     }
1775     foreach (ASTSignal *ref, _signals) {
1776         processor->processSignal(ref->ast()->name.toString(), ref);
1777         // ### Should get a different value?
1778         processor->processGeneratedSlot(ref->slotName(), ref);
1779     }
1780
1781     ObjectValue::processMembers(processor);
1782 }
1783
1784 QString ASTObjectValue::defaultPropertyName() const
1785 {
1786     if (_defaultPropertyRef) {
1787         UiPublicMember *prop = _defaultPropertyRef->ast();
1788         if (prop)
1789             return prop->name.toString();
1790     }
1791     return QString();
1792 }
1793
1794 UiObjectInitializer *ASTObjectValue::initializer() const
1795 {
1796     return _initializer;
1797 }
1798
1799 UiQualifiedId *ASTObjectValue::typeName() const
1800 {
1801     return _typeName;
1802 }
1803
1804 const Document *ASTObjectValue::document() const
1805 {
1806     return _doc;
1807 }
1808
1809 ASTVariableReference::ASTVariableReference(VariableDeclaration *ast, const Document *doc, ValueOwner *valueOwner)
1810     : Reference(valueOwner)
1811     , _ast(ast)
1812     , _doc(doc)
1813 {
1814 }
1815
1816 ASTVariableReference::~ASTVariableReference()
1817 {
1818 }
1819
1820 const Value *ASTVariableReference::value(ReferenceContext *referenceContext) const
1821 {
1822     // may be assigned to later
1823     if (!_ast->expression)
1824         return valueOwner()->unknownValue();
1825
1826     Document::Ptr doc = _doc->ptr();
1827     ScopeChain scopeChain(doc, referenceContext->context());
1828     ScopeBuilder builder(&scopeChain);
1829     builder.push(ScopeAstPath(doc)(_ast->expression->firstSourceLocation().begin()));
1830
1831     Evaluate evaluator(&scopeChain, referenceContext);
1832     return evaluator(_ast->expression);
1833 }
1834
1835 bool ASTVariableReference::getSourceLocation(QString *fileName, int *line, int *column) const
1836 {
1837     *fileName = _doc->fileName();
1838     *line = _ast->identifierToken.startLine;
1839     *column = _ast->identifierToken.startColumn;
1840     return true;
1841 }
1842
1843 ASTFunctionValue::ASTFunctionValue(FunctionExpression *ast, const Document *doc, ValueOwner *valueOwner)
1844     : FunctionValue(valueOwner), _ast(ast), _doc(doc)
1845 {
1846     setPrototype(valueOwner->functionPrototype());
1847
1848     for (FormalParameterList *it = ast->formals; it; it = it->next)
1849         _argumentNames.append(it->name.toString());
1850 }
1851
1852 ASTFunctionValue::~ASTFunctionValue()
1853 {
1854 }
1855
1856 FunctionExpression *ASTFunctionValue::ast() const
1857 {
1858     return _ast;
1859 }
1860
1861 int ASTFunctionValue::argumentCount() const
1862 {
1863     return _argumentNames.size();
1864 }
1865
1866 QString ASTFunctionValue::argumentName(int index) const
1867 {
1868     if (index < _argumentNames.size()) {
1869         const QString &name = _argumentNames.at(index);
1870         if (!name.isEmpty())
1871             return name;
1872     }
1873
1874     return FunctionValue::argumentName(index);
1875 }
1876
1877 bool ASTFunctionValue::getSourceLocation(QString *fileName, int *line, int *column) const
1878 {
1879     *fileName = _doc->fileName();
1880     *line = _ast->identifierToken.startLine;
1881     *column = _ast->identifierToken.startColumn;
1882     return true;
1883 }
1884
1885 QmlPrototypeReference::QmlPrototypeReference(UiQualifiedId *qmlTypeName, const Document *doc,
1886                                              ValueOwner *valueOwner)
1887     : Reference(valueOwner),
1888       _qmlTypeName(qmlTypeName),
1889       _doc(doc)
1890 {
1891 }
1892
1893 QmlPrototypeReference::~QmlPrototypeReference()
1894 {
1895 }
1896
1897 const QmlPrototypeReference *QmlPrototypeReference::asQmlPrototypeReference() const
1898 {
1899     return this;
1900 }
1901
1902 UiQualifiedId *QmlPrototypeReference::qmlTypeName() const
1903 {
1904     return _qmlTypeName;
1905 }
1906
1907 const Value *QmlPrototypeReference::value(ReferenceContext *referenceContext) const
1908 {
1909     return referenceContext->context()->lookupType(_doc, _qmlTypeName);
1910 }
1911
1912 ASTPropertyReference::ASTPropertyReference(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner)
1913     : Reference(valueOwner), _ast(ast), _doc(doc)
1914 {
1915     const QString &propertyName = ast->name.toString();
1916     _onChangedSlotName = generatedSlotName(propertyName);
1917     _onChangedSlotName += QLatin1String("Changed");
1918 }
1919
1920 ASTPropertyReference::~ASTPropertyReference()
1921 {
1922 }
1923
1924 const ASTPropertyReference *ASTPropertyReference::asAstPropertyReference() const
1925 {
1926     return this;
1927 }
1928
1929 bool ASTPropertyReference::getSourceLocation(QString *fileName, int *line, int *column) const
1930 {
1931     *fileName = _doc->fileName();
1932     *line = _ast->identifierToken.startLine;
1933     *column = _ast->identifierToken.startColumn;
1934     return true;
1935 }
1936
1937 const Value *ASTPropertyReference::value(ReferenceContext *referenceContext) const
1938 {
1939     if (_ast->statement
1940             && (_ast->memberType.isEmpty()
1941                 || _ast->memberType == QLatin1String("variant")
1942                 || _ast->memberType == QLatin1String("var")
1943                 || _ast->memberType == QLatin1String("alias"))) {
1944
1945         // Adjust the context for the current location - expensive!
1946         // ### Improve efficiency by caching the 'use chain' constructed in ScopeBuilder.
1947
1948         Document::Ptr doc = _doc->ptr();
1949         ScopeChain scopeChain(doc, referenceContext->context());
1950         ScopeBuilder builder(&scopeChain);
1951
1952         int offset = _ast->statement->firstSourceLocation().begin();
1953         builder.push(ScopeAstPath(doc)(offset));
1954
1955         Evaluate evaluator(&scopeChain, referenceContext);
1956         return evaluator(_ast->statement);
1957     }
1958
1959     return valueOwner()->defaultValueForBuiltinType(_ast->memberType.toString());
1960 }
1961
1962 ASTSignal::ASTSignal(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner)
1963     : FunctionValue(valueOwner), _ast(ast), _doc(doc)
1964 {
1965     const QString &signalName = ast->name.toString();
1966     _slotName = generatedSlotName(signalName);
1967
1968     ObjectValue *v = valueOwner->newObject(/*prototype=*/0);
1969     for (UiParameterList *it = ast->parameters; it; it = it->next) {
1970         if (!it->name.isEmpty())
1971             v->setMember(it->name.toString(), valueOwner->defaultValueForBuiltinType(it->type.toString()));
1972     }
1973     _bodyScope = v;
1974 }
1975
1976 ASTSignal::~ASTSignal()
1977 {
1978 }
1979
1980 const ASTSignal *ASTSignal::asAstSignal() const
1981 {
1982     return this;
1983 }
1984
1985 int ASTSignal::argumentCount() const
1986 {
1987     int count = 0;
1988     for (UiParameterList *it = _ast->parameters; it; it = it->next)
1989         ++count;
1990     return count;
1991 }
1992
1993 const Value *ASTSignal::argument(int index) const
1994 {
1995     UiParameterList *param = _ast->parameters;
1996     for (int i = 0; param && i < index; ++i)
1997         param = param->next;
1998     if (!param || param->type.isEmpty())
1999         return valueOwner()->unknownValue();
2000     return valueOwner()->defaultValueForBuiltinType(param->type.toString());
2001 }
2002
2003 QString ASTSignal::argumentName(int index) const
2004 {
2005     UiParameterList *param = _ast->parameters;
2006     for (int i = 0; param && i < index; ++i)
2007         param = param->next;
2008     if (!param || param->name.isEmpty())
2009         return FunctionValue::argumentName(index);
2010     return param->name.toString();
2011 }
2012
2013 bool ASTSignal::getSourceLocation(QString *fileName, int *line, int *column) const
2014 {
2015     *fileName = _doc->fileName();
2016     *line = _ast->identifierToken.startLine;
2017     *column = _ast->identifierToken.startColumn;
2018     return true;
2019 }
2020
2021
2022 ImportInfo::ImportInfo()
2023     : _type(InvalidImport)
2024     , _ast(0)
2025 {
2026 }
2027
2028 ImportInfo ImportInfo::moduleImport(QString uri, ComponentVersion version,
2029                                     const QString &as, UiImport *ast)
2030 {
2031     // treat Qt 4.7 as QtQuick 1.0
2032     if (uri == QLatin1String("Qt") && version == ComponentVersion(4, 7)) {
2033         uri = QLatin1String("QtQuick");
2034         version = ComponentVersion(1, 0);
2035     }
2036
2037     ImportInfo info;
2038     info._type = LibraryImport;
2039     info._name = uri;
2040     info._path = uri;
2041     info._path.replace(QLatin1Char('.'), QDir::separator());
2042     info._version = version;
2043     info._as = as;
2044     info._ast = ast;
2045     return info;
2046 }
2047
2048 ImportInfo ImportInfo::pathImport(const QString &docPath, const QString &path,
2049                                   ComponentVersion version, const QString &as, UiImport *ast)
2050 {
2051     ImportInfo info;
2052     info._name = path;
2053
2054     QFileInfo importFileInfo(path);
2055     if (!importFileInfo.isAbsolute()) {
2056         importFileInfo = QFileInfo(docPath + QDir::separator() + path);
2057     }
2058     info._path = importFileInfo.absoluteFilePath();
2059
2060     if (importFileInfo.isFile()) {
2061         info._type = FileImport;
2062     } else if (importFileInfo.isDir()) {
2063         info._type = DirectoryImport;
2064     } else {
2065         info._type = UnknownFileImport;
2066     }
2067
2068     info._version = version;
2069     info._as = as;
2070     info._ast = ast;
2071     return info;
2072 }
2073
2074 ImportInfo ImportInfo::invalidImport(UiImport *ast)
2075 {
2076     ImportInfo info;
2077     info._type = InvalidImport;
2078     info._ast = ast;
2079     return info;
2080 }
2081
2082 ImportInfo ImportInfo::implicitDirectoryImport(const QString &directory)
2083 {
2084     ImportInfo info;
2085     info._type = ImplicitDirectoryImport;
2086     info._path = directory;
2087     return info;
2088 }
2089
2090 bool ImportInfo::isValid() const
2091 {
2092     return _type != InvalidImport;
2093 }
2094
2095 ImportInfo::Type ImportInfo::type() const
2096 {
2097     return _type;
2098 }
2099
2100 QString ImportInfo::name() const
2101 {
2102     return _name;
2103 }
2104
2105 QString ImportInfo::path() const
2106 {
2107     return _path;
2108 }
2109
2110 QString ImportInfo::as() const
2111 {
2112     return _as;
2113 }
2114
2115 ComponentVersion ImportInfo::version() const
2116 {
2117     return _version;
2118 }
2119
2120 UiImport *ImportInfo::ast() const
2121 {
2122     return _ast;
2123 }
2124
2125 Import::Import()
2126     : object(0)
2127 {}
2128
2129 TypeScope::TypeScope(const Imports *imports, ValueOwner *valueOwner)
2130     : ObjectValue(valueOwner)
2131     , _imports(imports)
2132 {
2133 }
2134
2135 const Value *TypeScope::lookupMember(const QString &name, const Context *context,
2136                                            const ObjectValue **foundInObject, bool) const
2137 {
2138     QListIterator<Import> it(_imports->all());
2139     it.toBack();
2140     while (it.hasPrevious()) {
2141         const Import &i = it.previous();
2142         const ObjectValue *import = i.object;
2143         const ImportInfo &info = i.info;
2144
2145         // JS import has no types
2146         if (info.type() == ImportInfo::FileImport)
2147             continue;
2148
2149         if (!info.as().isEmpty()) {
2150             if (info.as() == name) {
2151                 if (foundInObject)
2152                     *foundInObject = this;
2153                 return import;
2154             }
2155             continue;
2156         }
2157
2158         if (const Value *v = import->lookupMember(name, context, foundInObject))
2159             return v;
2160     }
2161     if (foundInObject)
2162         *foundInObject = 0;
2163     return 0;
2164 }
2165
2166 void TypeScope::processMembers(MemberProcessor *processor) const
2167 {
2168     QListIterator<Import> it(_imports->all());
2169     it.toBack();
2170     while (it.hasPrevious()) {
2171         const Import &i = it.previous();
2172         const ObjectValue *import = i.object;
2173         const ImportInfo &info = i.info;
2174
2175         // JS import has no types
2176         if (info.type() == ImportInfo::FileImport)
2177             continue;
2178
2179         if (!info.as().isEmpty()) {
2180             processor->processProperty(info.as(), import);
2181         } else {
2182             import->processMembers(processor);
2183         }
2184     }
2185 }
2186
2187 JSImportScope::JSImportScope(const Imports *imports, ValueOwner *valueOwner)
2188     : ObjectValue(valueOwner)
2189     , _imports(imports)
2190 {
2191 }
2192
2193 const Value *JSImportScope::lookupMember(const QString &name, const Context *,
2194                                          const ObjectValue **foundInObject, bool) const
2195 {
2196     QListIterator<Import> it(_imports->all());
2197     it.toBack();
2198     while (it.hasPrevious()) {
2199         const Import &i = it.previous();
2200         const ObjectValue *import = i.object;
2201         const ImportInfo &info = i.info;
2202
2203         // JS imports are always: import "somefile.js" as Foo
2204         if (info.type() != ImportInfo::FileImport)
2205             continue;
2206
2207         if (info.as() == name) {
2208             if (foundInObject)
2209                 *foundInObject = this;
2210             return import;
2211         }
2212     }
2213     if (foundInObject)
2214         *foundInObject = 0;
2215     return 0;
2216 }
2217
2218 void JSImportScope::processMembers(MemberProcessor *processor) const
2219 {
2220     QListIterator<Import> it(_imports->all());
2221     it.toBack();
2222     while (it.hasPrevious()) {
2223         const Import &i = it.previous();
2224         const ObjectValue *import = i.object;
2225         const ImportInfo &info = i.info;
2226
2227         if (info.type() == ImportInfo::FileImport)
2228             processor->processProperty(info.as(), import);
2229     }
2230 }
2231
2232 Imports::Imports(ValueOwner *valueOwner)
2233     : _typeScope(new TypeScope(this, valueOwner))
2234     , _jsImportScope(new JSImportScope(this, valueOwner))
2235     , _importFailed(false)
2236 {}
2237
2238 void Imports::append(const Import &import)
2239 {
2240     // when doing lookup, imports with 'as' clause are looked at first
2241     if (!import.info.as().isEmpty()) {
2242         _imports.append(import);
2243     } else {
2244         // find first as-import and prepend
2245         for (int i = 0; i < _imports.size(); ++i) {
2246             if (!_imports.at(i).info.as().isEmpty()) {
2247                 _imports.insert(i, import);
2248                 return;
2249             }
2250         }
2251         // not found, append
2252         _imports.append(import);
2253     }
2254
2255     if (!import.valid)
2256         _importFailed = true;
2257 }
2258
2259 void Imports::setImportFailed()
2260 {
2261     _importFailed = true;
2262 }
2263
2264 ImportInfo Imports::info(const QString &name, const Context *context) const
2265 {
2266     QString firstId = name;
2267     int dotIdx = firstId.indexOf(QLatin1Char('.'));
2268     if (dotIdx != -1)
2269         firstId = firstId.left(dotIdx);
2270
2271     QListIterator<Import> it(_imports);
2272     it.toBack();
2273     while (it.hasPrevious()) {
2274         const Import &i = it.previous();
2275         const ObjectValue *import = i.object;
2276         const ImportInfo &info = i.info;
2277
2278         if (!info.as().isEmpty()) {
2279             if (info.as() == firstId)
2280                 return info;
2281             continue;
2282         }
2283
2284         if (info.type() == ImportInfo::FileImport) {
2285             if (import->className() == firstId)
2286                 return info;
2287         } else {
2288             if (import->lookupMember(firstId, context))
2289                 return info;
2290         }
2291     }
2292     return ImportInfo();
2293 }
2294
2295 QString Imports::nameForImportedObject(const ObjectValue *value, const Context *context) const
2296 {
2297     QListIterator<Import> it(_imports);
2298     it.toBack();
2299     while (it.hasPrevious()) {
2300         const Import &i = it.previous();
2301         const ObjectValue *import = i.object;
2302         const ImportInfo &info = i.info;
2303
2304         if (info.type() == ImportInfo::FileImport) {
2305             if (import == value)
2306                 return import->className();
2307         } else {
2308             const Value *v = import->lookupMember(value->className(), context);
2309             if (v == value) {
2310                 QString result = value->className();
2311                 if (!info.as().isEmpty()) {
2312                     result.prepend(QLatin1Char('.'));
2313                     result.prepend(info.as());
2314                 }
2315                 return result;
2316             }
2317         }
2318     }
2319     return QString();
2320 }
2321
2322 bool Imports::importFailed() const
2323 {
2324     return _importFailed;
2325 }
2326
2327 QList<Import> Imports::all() const
2328 {
2329     return _imports;
2330 }
2331
2332 const TypeScope *Imports::typeScope() const
2333 {
2334     return _typeScope;
2335 }
2336
2337 const JSImportScope *Imports::jsImportScope() const
2338 {
2339     return _jsImportScope;
2340 }
2341
2342 #ifdef QT_DEBUG
2343
2344 class MemberDumper: public MemberProcessor
2345 {
2346 public:
2347     MemberDumper() {}
2348
2349     virtual bool processProperty(const QString &name, const Value *)
2350     {
2351         qDebug() << "property: " << name;
2352         return true;
2353     }
2354
2355     virtual bool processEnumerator(const QString &name, const Value *)
2356     {
2357         qDebug() << "enumerator: " << name;
2358         return true;
2359     }
2360
2361     virtual bool processSignal(const QString &name, const Value *)
2362     {
2363         qDebug() << "signal: " << name;
2364         return true;
2365     }
2366
2367     virtual bool processSlot(const QString &name, const Value *)
2368     {
2369         qDebug() << "slot: " << name;
2370         return true;
2371     }
2372
2373     virtual bool processGeneratedSlot(const QString &name, const Value *)
2374     {
2375         qDebug() << "generated slot: " << name;
2376         return true;
2377     }
2378 };
2379
2380 void Imports::dump() const
2381 {
2382     qDebug() << "Imports contents, in search order:";
2383     QListIterator<Import> it(_imports);
2384     it.toBack();
2385     while (it.hasPrevious()) {
2386         const Import &i = it.previous();
2387         const ObjectValue *import = i.object;
2388         const ImportInfo &info = i.info;
2389
2390         qDebug() << "  " << info.path() << " " << info.version().toString() << " as " << info.as() << " : " << import;
2391         MemberDumper dumper;
2392         import->processMembers(&dumper);
2393     }
2394 }
2395
2396 #endif