1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
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.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
31 **************************************************************************/
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"
45 #include <languageutils/fakemetaobject.h>
46 #include <utils/qtcassert.h>
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>
60 using namespace LanguageUtils;
61 using namespace QmlJS;
62 using namespace QmlJS::AST;
66 class LookupMember: public MemberProcessor
71 bool process(const QString &name, const Value *value)
85 LookupMember(const QString &name)
86 : _name(name), _value(0) {}
88 const Value *value() const { return _value; }
90 virtual bool processProperty(const QString &name, const Value *value)
92 return process(name, value);
95 virtual bool processEnumerator(const QString &name, const Value *value)
97 return process(name, value);
100 virtual bool processSignal(const QString &name, const Value *value)
102 return process(name, value);
105 virtual bool processSlot(const QString &name, const Value *value)
107 return process(name, value);
110 virtual bool processGeneratedSlot(const QString &name, const Value *value)
112 return process(name, value);
116 class MetaFunction: public FunctionValue
118 FakeMetaMethod _method;
121 MetaFunction(const FakeMetaMethod &method, ValueOwner *valueOwner)
122 : FunctionValue(valueOwner), _method(method)
126 virtual int argumentCount() const
128 return _method.parameterNames().size();
131 virtual QString argumentName(int index) const
133 if (index < _method.parameterNames().size())
134 return _method.parameterNames().at(index);
136 return FunctionValue::argumentName(index);
139 virtual bool isVariadic() const
144 virtual const Value *invoke(const Activation *) const
146 return valueOwner()->unknownValue();
150 } // end of anonymous namespace
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),
158 _metaObject(metaObject),
159 _moduleName(packageName),
160 _componentVersion(componentVersion),
161 _importVersion(importVersion),
162 _metaObjectRevision(metaObjectRevision)
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);
172 CppComponentValue::~CppComponentValue()
174 delete _metaSignatures;
175 delete _signalScopes;
178 static QString generatedSlotName(const QString &base)
180 QString slotName = QLatin1String("on");
181 slotName += base.at(0).toUpper();
182 slotName += base.midRef(1);
186 const CppComponentValue *CppComponentValue::asCppComponentValue() const
191 void CppComponentValue::processMembers(MemberProcessor *processor) const
193 // process the meta enums
194 for (int index = _metaObject->enumeratorOffset(); index < _metaObject->enumeratorCount(); ++index) {
195 FakeMetaEnum e = _metaObject->enumerator(index);
197 for (int i = 0; i < e.keyCount(); ++i) {
198 processor->processEnumerator(e.key(i), valueOwner()->numberValue());
202 // all explicitly defined signal names
203 QSet<QString> explicitSignals;
205 // make MetaFunction instances lazily when first needed
206 QList<const Value *> *signatures = _metaSignatures;
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)) {
214 signatures = _metaSignatures;
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())
224 const QString &methodName = _metaObject->method(index).methodName();
225 const Value *signature = signatures->at(index);
227 if (method.methodType() == FakeMetaMethod::Slot && method.access() == FakeMetaMethod::Public) {
228 processor->processSlot(methodName, signature);
230 } else if (method.methodType() == FakeMetaMethod::Signal && method.access() != FakeMetaMethod::Private) {
231 // process the signal
232 processor->processSignal(methodName, signature);
233 explicitSignals.insert(methodName);
235 // process the generated slot
236 const QString &slotName = generatedSlotName(methodName);
237 processor->processGeneratedSlot(slotName, signature);
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())
247 const QString propertyName = prop.name();
248 processor->processProperty(propertyName, valueForCppName(prop.typeName()));
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());
262 _attachedType->processMembers(processor);
264 ObjectValue::processMembers(processor);
267 const Value *CppComponentValue::valueForCppName(const QString &typeName) const
269 const CppQmlTypes &cppTypes = valueOwner()->cppQmlTypes();
271 // check in the same package/version first
272 const CppComponentValue *objectValue = cppTypes.objectByQualifiedName(
273 _moduleName, typeName, _importVersion);
277 // fallback to plain cpp name
278 objectValue = cppTypes.objectByCppName(typeName);
282 // try qml builtin type names
283 if (const Value *v = valueOwner()->defaultValueForBuiltinType(typeName)) {
284 if (!v->asUndefinedValue())
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();
320 const CppComponentValue *base = this;
321 const QStringList components = typeName.split(QLatin1String("::"));
322 if (components.size() == 2) {
323 base = valueOwner()->cppQmlTypes().objectByCppName(components.first());
326 if (const QmlEnumValue *value = base->getEnumValue(components.last()))
330 // may still be a cpp based value
331 return valueOwner()->unknownValue();
334 const CppComponentValue *CppComponentValue::prototype() const
336 Q_ASSERT(!_prototype || value_cast<CppComponentValue>(_prototype));
337 return static_cast<const CppComponentValue *>(_prototype);
340 const CppComponentValue *CppComponentValue::attachedType() const
342 return _attachedType;
345 void CppComponentValue::setAttachedType(CppComponentValue *value)
347 _attachedType = value;
350 FakeMetaObject::ConstPtr CppComponentValue::metaObject() const
355 QString CppComponentValue::moduleName() const
356 { return _moduleName; }
358 ComponentVersion CppComponentValue::componentVersion() const
359 { return _componentVersion; }
361 ComponentVersion CppComponentValue::importVersion() const
362 { return _importVersion; }
364 QString CppComponentValue::defaultPropertyName() const
365 { return _metaObject->defaultPropertyName(); }
367 QString CppComponentValue::propertyType(const QString &propertyName) const
369 for (const CppComponentValue *it = this; it; it = it->prototype()) {
370 FakeMetaObject::ConstPtr iter = it->_metaObject;
371 int propIdx = iter->propertyIndex(propertyName);
373 return iter->property(propIdx).typeName();
379 bool CppComponentValue::isListProperty(const QString &propertyName) const
381 for (const CppComponentValue *it = this; it; it = it->prototype()) {
382 FakeMetaObject::ConstPtr iter = it->_metaObject;
383 int propIdx = iter->propertyIndex(propertyName);
385 return iter->property(propIdx).isList();
391 FakeMetaEnum CppComponentValue::getEnum(const QString &typeName, const CppComponentValue **foundInScope) const
393 for (const CppComponentValue *it = this; it; it = it->prototype()) {
394 FakeMetaObject::ConstPtr iter = it->_metaObject;
395 const int index = iter->enumeratorIndex(typeName);
399 return iter->enumerator(index);
404 return FakeMetaEnum();
407 const QmlEnumValue *CppComponentValue::getEnumValue(const QString &typeName, const CppComponentValue **foundInScope) const
409 for (const CppComponentValue *it = this; it; it = it->prototype()) {
410 if (const QmlEnumValue *e = it->_enums.value(typeName)) {
421 const ObjectValue *CppComponentValue::signalScope(const QString &signalName) const
423 QHash<QString, const ObjectValue *> *scopes = _signalScopes;
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)
433 const QStringList ¶meterNames = method.parameterNames();
434 const QStringList ¶meterTypes = method.parameterTypes();
435 QTC_ASSERT(parameterNames.size() == parameterTypes.size(), continue);
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);
443 scope->setMember(name, valueForCppName(type));
445 scopes->insert(generatedSlotName(method.methodName()), scope);
447 if (!_signalScopes.testAndSetOrdered(0, scopes)) {
448 delete _signalScopes;
449 scopes = _signalScopes;
453 return scopes->value(signalName);
456 bool CppComponentValue::isWritable(const QString &propertyName) const
458 for (const CppComponentValue *it = this; it; it = it->prototype()) {
459 FakeMetaObject::ConstPtr iter = it->_metaObject;
460 int propIdx = iter->propertyIndex(propertyName);
462 return iter->property(propIdx).isWritable();
468 bool CppComponentValue::isPointer(const QString &propertyName) const
470 for (const CppComponentValue *it = this; it; it = it->prototype()) {
471 FakeMetaObject::ConstPtr iter = it->_metaObject;
472 int propIdx = iter->propertyIndex(propertyName);
474 return iter->property(propIdx).isPointer();
480 bool CppComponentValue::hasLocalProperty(const QString &typeName) const
482 int idx = _metaObject->propertyIndex(typeName);
488 bool CppComponentValue::hasProperty(const QString &propertyName) const
490 for (const CppComponentValue *it = this; it; it = it->prototype()) {
491 FakeMetaObject::ConstPtr iter = it->_metaObject;
492 int propIdx = iter->propertyIndex(propertyName);
500 bool CppComponentValue::isDerivedFrom(FakeMetaObject::ConstPtr base) const
502 for (const CppComponentValue *it = this; it; it = it->prototype()) {
503 FakeMetaObject::ConstPtr iter = it->_metaObject;
510 QmlEnumValue::QmlEnumValue(const CppComponentValue *owner, int enumIndex)
512 , _enumIndex(enumIndex)
514 owner->valueOwner()->registerValue(this);
517 QmlEnumValue::~QmlEnumValue()
521 const QmlEnumValue *QmlEnumValue::asQmlEnumValue() const
526 QString QmlEnumValue::name() const
528 return _owner->metaObject()->enumerator(_enumIndex).name();
531 QStringList QmlEnumValue::keys() const
533 return _owner->metaObject()->enumerator(_enumIndex).keys();
536 const CppComponentValue *QmlEnumValue::owner() const
541 ////////////////////////////////////////////////////////////////////////////////
543 ////////////////////////////////////////////////////////////////////////////////
544 ValueVisitor::ValueVisitor()
548 ValueVisitor::~ValueVisitor()
552 void ValueVisitor::visit(const NullValue *)
556 void ValueVisitor::visit(const UndefinedValue *)
560 void ValueVisitor::visit(const UnknownValue *)
564 void ValueVisitor::visit(const NumberValue *)
568 void ValueVisitor::visit(const BooleanValue *)
572 void ValueVisitor::visit(const StringValue *)
576 void ValueVisitor::visit(const ObjectValue *)
580 void ValueVisitor::visit(const FunctionValue *)
584 void ValueVisitor::visit(const Reference *)
588 void ValueVisitor::visit(const ColorValue *)
592 void ValueVisitor::visit(const AnchorLineValue *)
596 ////////////////////////////////////////////////////////////////////////////////
598 ////////////////////////////////////////////////////////////////////////////////
607 bool Value::getSourceLocation(QString *, int *, int *) const
612 const NullValue *Value::asNullValue() const
617 const UndefinedValue *Value::asUndefinedValue() const
622 const UnknownValue *Value::asUnknownValue() const
627 const NumberValue *Value::asNumberValue() const
632 const IntValue *Value::asIntValue() const
637 const RealValue *Value::asRealValue() const
642 const BooleanValue *Value::asBooleanValue() const
647 const StringValue *Value::asStringValue() const
652 const UrlValue *Value::asUrlValue() const
657 const ObjectValue *Value::asObjectValue() const
662 const FunctionValue *Value::asFunctionValue() const
667 const Reference *Value::asReference() const
672 const ColorValue *Value::asColorValue() const
677 const AnchorLineValue *Value::asAnchorLineValue() const
682 const CppComponentValue *Value::asCppComponentValue() const
687 const ASTObjectValue *Value::asAstObjectValue() const
692 const QmlEnumValue *Value::asQmlEnumValue() const
697 const QmlPrototypeReference *Value::asQmlPrototypeReference() const
702 const ASTPropertyReference *Value::asAstPropertyReference() const
707 const ASTSignal *Value::asAstSignal() const
712 ////////////////////////////////////////////////////////////////////////////////
714 ////////////////////////////////////////////////////////////////////////////////
715 const NullValue *NullValue::asNullValue() const
720 void NullValue::accept(ValueVisitor *visitor) const
722 visitor->visit(this);
725 const UndefinedValue *UndefinedValue::asUndefinedValue() const
730 void UnknownValue::accept(ValueVisitor *visitor) const
732 visitor->visit(this);
735 const UnknownValue *UnknownValue::asUnknownValue() const
740 void UndefinedValue::accept(ValueVisitor *visitor) const
742 visitor->visit(this);
744 const NumberValue *NumberValue::asNumberValue() const
749 const RealValue *RealValue::asRealValue() const
754 const IntValue *IntValue::asIntValue() const
759 void NumberValue::accept(ValueVisitor *visitor) const
761 visitor->visit(this);
764 const BooleanValue *BooleanValue::asBooleanValue() const
769 void BooleanValue::accept(ValueVisitor *visitor) const
771 visitor->visit(this);
774 const StringValue *StringValue::asStringValue() const
779 const UrlValue *UrlValue::asUrlValue() const
784 void StringValue::accept(ValueVisitor *visitor) const
786 visitor->visit(this);
789 Reference::Reference(ValueOwner *valueOwner)
790 : _valueOwner(valueOwner)
792 _valueOwner->registerValue(this);
795 Reference::~Reference()
799 ValueOwner *Reference::valueOwner() const
804 const Reference *Reference::asReference() const
809 void Reference::accept(ValueVisitor *visitor) const
811 visitor->visit(this);
814 const Value *Reference::value(ReferenceContext *) const
816 return _valueOwner->undefinedValue();
819 void ColorValue::accept(ValueVisitor *visitor) const
821 visitor->visit(this);
824 const ColorValue *ColorValue::asColorValue() const
829 void AnchorLineValue::accept(ValueVisitor *visitor) const
831 visitor->visit(this);
834 const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const
839 MemberProcessor::MemberProcessor()
843 MemberProcessor::~MemberProcessor()
847 bool MemberProcessor::processProperty(const QString &, const Value *)
852 bool MemberProcessor::processEnumerator(const QString &, const Value *)
857 bool MemberProcessor::processSignal(const QString &, const Value *)
862 bool MemberProcessor::processSlot(const QString &, const Value *)
867 bool MemberProcessor::processGeneratedSlot(const QString &, const Value *)
872 ObjectValue::ObjectValue(ValueOwner *valueOwner)
873 : _valueOwner(valueOwner),
876 valueOwner->registerValue(this);
879 ObjectValue::~ObjectValue()
883 ValueOwner *ObjectValue::valueOwner() const
888 QString ObjectValue::className() const
893 void ObjectValue::setClassName(const QString &className)
895 _className = className;
898 const Value *ObjectValue::prototype() const
903 const ObjectValue *ObjectValue::prototype(const Context *context) const
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));
911 return prototypeObject;
914 void ObjectValue::setPrototype(const Value *prototype)
916 _prototype = prototype;
919 void ObjectValue::setMember(const QString &name, const Value *value)
921 _members[name] = value;
924 void ObjectValue::removeMember(const QString &name)
926 _members.remove(name);
929 const ObjectValue *ObjectValue::asObjectValue() const
934 void ObjectValue::accept(ValueVisitor *visitor) const
936 visitor->visit(this);
939 bool ObjectValue::checkPrototype(const ObjectValue *, QSet<const ObjectValue *> *) const
942 const int previousSize = processed->size();
943 processed->insert(this);
945 if (previousSize != processed->size()) {
949 if (prototype() && ! prototype()->checkPrototype(proto, processed))
958 void ObjectValue::processMembers(MemberProcessor *processor) const
960 QHashIterator<QString, const Value *> it(_members);
962 while (it.hasNext()) {
965 if (! processor->processProperty(it.key(), it.value()))
970 const Value *ObjectValue::lookupMember(const QString &name, const Context *context,
971 const ObjectValue **foundInObject,
972 bool examinePrototypes) const
974 if (const Value *m = _members.value(name)) {
976 *foundInObject = this;
979 LookupMember slowLookup(name);
980 processMembers(&slowLookup);
981 if (slowLookup.value()) {
983 *foundInObject = this;
984 return slowLookup.value();
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))
1003 PrototypeIterator::PrototypeIterator(const ObjectValue *start, const Context *context)
1006 , m_context(context)
1010 m_prototypes.reserve(10);
1013 PrototypeIterator::PrototypeIterator(const ObjectValue *start, const ContextPtr &context)
1016 , m_context(context.data())
1020 m_prototypes.reserve(10);
1023 bool PrototypeIterator::hasNext()
1029 const Value *proto = m_current->prototype();
1033 m_next = value_cast<ObjectValue>(proto);
1035 m_next = value_cast<ObjectValue>(m_context->lookupReference(proto));
1037 m_error = ReferenceResolutionError;
1040 if (m_prototypes.contains(m_next)) {
1041 m_error = CycleError;
1048 const ObjectValue *PrototypeIterator::next()
1052 m_prototypes += m_next;
1059 const ObjectValue *PrototypeIterator::peekNext()
1067 PrototypeIterator::Error PrototypeIterator::error() const
1072 QList<const ObjectValue *> PrototypeIterator::all()
1076 return m_prototypes;
1079 Activation::Activation(Context *parentContext)
1081 _calledAsFunction(true),
1082 _parentContext(parentContext)
1086 Activation::~Activation()
1090 Context *Activation::parentContext() const
1092 return _parentContext;
1095 Context *Activation::context() const
1097 // ### FIXME: Real context for activations.
1101 bool Activation::calledAsConstructor() const
1103 return ! _calledAsFunction;
1106 void Activation::setCalledAsConstructor(bool calledAsConstructor)
1108 _calledAsFunction = ! calledAsConstructor;
1111 bool Activation::calledAsFunction() const
1113 return _calledAsFunction;
1116 void Activation::setCalledAsFunction(bool calledAsFunction)
1118 _calledAsFunction = calledAsFunction;
1121 ObjectValue *Activation::thisObject() const
1126 void Activation::setThisObject(ObjectValue *thisObject)
1128 _thisObject = thisObject;
1131 ValueList Activation::arguments() const
1136 void Activation::setArguments(const ValueList &arguments)
1138 _arguments = arguments;
1141 FunctionValue::FunctionValue(ValueOwner *valueOwner)
1142 : ObjectValue(valueOwner)
1144 setMember(QLatin1String("length"), valueOwner->numberValue());
1147 FunctionValue::~FunctionValue()
1151 const Value *FunctionValue::construct(const ValueList &actuals) const
1153 Activation activation;
1154 activation.setCalledAsConstructor(true);
1155 activation.setThisObject(valueOwner()->newObject());
1156 activation.setArguments(actuals);
1157 return invoke(&activation);
1160 const Value *FunctionValue::call(const ValueList &actuals) const
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);
1169 const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList &actuals) const
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);
1178 const Value *FunctionValue::returnValue() const
1180 return valueOwner()->unknownValue();
1183 int FunctionValue::argumentCount() const
1188 const Value *FunctionValue::argument(int) const
1190 return valueOwner()->unknownValue();
1193 QString FunctionValue::argumentName(int index) const
1195 return QString::fromLatin1("arg%1").arg(index + 1);
1198 bool FunctionValue::isVariadic() const
1203 const Value *FunctionValue::invoke(const Activation *activation) const
1205 return activation->thisObject(); // ### FIXME: it should return undefined
1208 const FunctionValue *FunctionValue::asFunctionValue() const
1213 void FunctionValue::accept(ValueVisitor *visitor) const
1215 visitor->visit(this);
1218 Function::Function(ValueOwner *valueOwner)
1219 : FunctionValue(valueOwner), _returnValue(0)
1221 setClassName("Function");
1224 Function::~Function()
1228 void Function::addArgument(const Value *argument, const QString &name)
1230 if (!name.isEmpty()) {
1231 while (_argumentNames.size() < _arguments.size())
1232 _argumentNames.push_back(QString());
1233 _argumentNames.push_back(name);
1235 _arguments.push_back(argument);
1238 const Value *Function::returnValue() const
1240 return _returnValue;
1243 void Function::setReturnValue(const Value *returnValue)
1245 _returnValue = returnValue;
1248 int Function::argumentCount() const
1250 return _arguments.size();
1253 const Value *Function::argument(int index) const
1255 return _arguments.at(index);
1258 QString Function::argumentName(int index) const
1260 if (index < _argumentNames.size()) {
1261 const QString name = _argumentNames.at(index);
1262 if (!name.isEmpty())
1263 return _argumentNames.at(index);
1265 return FunctionValue::argumentName(index);
1268 const Value *Function::invoke(const Activation *) const
1270 return _returnValue;
1273 ////////////////////////////////////////////////////////////////////////////////
1274 // typing environment
1275 ////////////////////////////////////////////////////////////////////////////////
1277 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::defaultLibraryObjects;
1278 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::defaultQtObjects;
1280 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles, QStringList *errors, QStringList *warnings)
1282 QHash<QString, FakeMetaObject::ConstPtr> newObjects;
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();
1291 parseQmlTypeDescriptions(contents, &newObjects, 0, &error, &warning);
1293 error = file.errorString();
1295 if (!error.isEmpty()) {
1296 errors->append(TypeDescriptionReader::tr(
1297 "Errors while loading qmltypes from %1:\n%2").arg(
1298 qmlTypeFile.absoluteFilePath(), error));
1300 if (!warning.isEmpty()) {
1301 warnings->append(TypeDescriptionReader::tr(
1302 "Warnings while loading qmltypes from %1:\n%2").arg(
1303 qmlTypeFile.absoluteFilePath(), error));
1310 void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml,
1311 BuiltinObjects *newObjects,
1312 QList<ModuleApiInfo> *newModuleApis,
1313 QString *errorMessage,
1314 QString *warningMessage)
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");
1323 *errorMessage = reader.errorMessage();
1326 *warningMessage = reader.warningMessage();
1329 CppQmlTypes::CppQmlTypes(ValueOwner *valueOwner)
1330 : _valueOwner(valueOwner)
1334 const QLatin1String CppQmlTypes::defaultPackage("<default>");
1335 const QLatin1String CppQmlTypes::cppPackage("<cpp>");
1337 template <typename T>
1338 void CppQmlTypes::load(const T &fakeMetaObjects, const QString &overridePackage)
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);
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;
1362 // set prototypes of cpp types
1363 foreach (CppComponentValue *object, newCppTypes) {
1364 const QString &protoCppName = object->metaObject()->superclassName();
1365 const CppComponentValue *proto = objectByCppName(protoCppName);
1367 object->setPrototype(proto);
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 &);
1374 QList<const CppComponentValue *> CppQmlTypes::createObjectsForImport(const QString &package, ComponentVersion version)
1376 QList<const CppComponentValue *> exportedObjects;
1377 QList<const CppComponentValue *> newObjects;
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))
1386 if (!bestExport.isValid() || exp.version > bestExport.version)
1389 if (!bestExport.isValid())
1392 // if it already exists, skip
1393 const QString key = qualifiedName(package, fmo->className(), version);
1394 if (_objectsByQualifiedName.contains(key))
1397 QString name = bestExport.type;
1398 bool exported = true;
1399 if (name.isEmpty()) {
1401 name = fmo->className();
1404 CppComponentValue *newObject = new CppComponentValue(
1405 fmo, name, package, bestExport.version, version,
1406 bestExport.metaObjectRevision, _valueOwner);
1408 // use package.cppname importversion as key
1409 _objectsByQualifiedName.insert(key, newObject);
1411 exportedObjects += newObject;
1412 newObjects += newObject;
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())
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);
1430 // get the fmo via the cpp name
1431 const CppComponentValue *cppProto = objectByCppName(protoCppName);
1434 FakeMetaObject::ConstPtr protoFmo = cppProto->metaObject();
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);
1443 // maybe set prototype of prototype
1448 return exportedObjects;
1451 bool CppQmlTypes::hasModule(const QString &module) const
1453 return _fakeMetaObjectsByPackage.contains(module);
1456 QString CppQmlTypes::qualifiedName(const QString &module, const QString &type, ComponentVersion version)
1458 return QString("%1/%2 %3").arg(
1460 version.toString());
1464 const CppComponentValue *CppQmlTypes::objectByQualifiedName(const QString &name) const
1466 return _objectsByQualifiedName.value(name);
1469 const CppComponentValue *CppQmlTypes::objectByQualifiedName(const QString &package, const QString &type,
1470 ComponentVersion version) const
1472 return objectByQualifiedName(qualifiedName(package, type, version));
1475 const CppComponentValue *CppQmlTypes::objectByCppName(const QString &cppName) const
1477 return objectByQualifiedName(qualifiedName(cppPackage, cppName, ComponentVersion()));
1481 ConvertToNumber::ConvertToNumber(ValueOwner *valueOwner)
1482 : _valueOwner(valueOwner), _result(0)
1486 const Value *ConvertToNumber::operator()(const Value *value)
1488 const Value *previousValue = switchResult(0);
1491 value->accept(this);
1493 return switchResult(previousValue);
1496 const Value *ConvertToNumber::switchResult(const Value *value)
1498 const Value *previousResult = _result;
1500 return previousResult;
1503 void ConvertToNumber::visit(const NullValue *)
1505 _result = _valueOwner->numberValue();
1508 void ConvertToNumber::visit(const UndefinedValue *)
1510 _result = _valueOwner->numberValue();
1513 void ConvertToNumber::visit(const NumberValue *value)
1518 void ConvertToNumber::visit(const BooleanValue *)
1520 _result = _valueOwner->numberValue();
1523 void ConvertToNumber::visit(const StringValue *)
1525 _result = _valueOwner->numberValue();
1528 void ConvertToNumber::visit(const ObjectValue *object)
1530 if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(object->lookupMember("valueOf", ContextPtr()))) {
1531 _result = value_cast<NumberValue>(valueOfMember->call(object)); // ### invoke convert-to-number?
1535 void ConvertToNumber::visit(const FunctionValue *object)
1537 if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(object->lookupMember("valueOf", ContextPtr()))) {
1538 _result = value_cast<NumberValue>(valueOfMember->call(object)); // ### invoke convert-to-number?
1542 ConvertToString::ConvertToString(ValueOwner *valueOwner)
1543 : _valueOwner(valueOwner), _result(0)
1547 const Value *ConvertToString::operator()(const Value *value)
1549 const Value *previousValue = switchResult(0);
1552 value->accept(this);
1554 return switchResult(previousValue);
1557 const Value *ConvertToString::switchResult(const Value *value)
1559 const Value *previousResult = _result;
1561 return previousResult;
1564 void ConvertToString::visit(const NullValue *)
1566 _result = _valueOwner->stringValue();
1569 void ConvertToString::visit(const UndefinedValue *)
1571 _result = _valueOwner->stringValue();
1574 void ConvertToString::visit(const NumberValue *)
1576 _result = _valueOwner->stringValue();
1579 void ConvertToString::visit(const BooleanValue *)
1581 _result = _valueOwner->stringValue();
1584 void ConvertToString::visit(const StringValue *value)
1589 void ConvertToString::visit(const ObjectValue *object)
1591 if (const FunctionValue *toStringMember = value_cast<FunctionValue>(object->lookupMember("toString", ContextPtr()))) {
1592 _result = value_cast<StringValue>(toStringMember->call(object)); // ### invoke convert-to-string?
1596 void ConvertToString::visit(const FunctionValue *object)
1598 if (const FunctionValue *toStringMember = value_cast<FunctionValue>(object->lookupMember("toString", ContextPtr()))) {
1599 _result = value_cast<StringValue>(toStringMember->call(object)); // ### invoke convert-to-string?
1603 ConvertToObject::ConvertToObject(ValueOwner *valueOwner)
1604 : _valueOwner(valueOwner), _result(0)
1608 const Value *ConvertToObject::operator()(const Value *value)
1610 const Value *previousValue = switchResult(0);
1613 value->accept(this);
1615 return switchResult(previousValue);
1618 const Value *ConvertToObject::switchResult(const Value *value)
1620 const Value *previousResult = _result;
1622 return previousResult;
1625 void ConvertToObject::visit(const NullValue *value)
1630 void ConvertToObject::visit(const UndefinedValue *)
1632 _result = _valueOwner->nullValue();
1635 void ConvertToObject::visit(const NumberValue *value)
1638 actuals.append(value);
1639 _result = _valueOwner->numberCtor()->construct(actuals);
1642 void ConvertToObject::visit(const BooleanValue *value)
1645 actuals.append(value);
1646 _result = _valueOwner->booleanCtor()->construct(actuals);
1649 void ConvertToObject::visit(const StringValue *value)
1652 actuals.append(value);
1653 _result = _valueOwner->stringCtor()->construct(actuals);
1656 void ConvertToObject::visit(const ObjectValue *object)
1661 void ConvertToObject::visit(const FunctionValue *object)
1666 QString TypeId::operator()(const Value *value)
1668 _result = QLatin1String("unknown");
1671 value->accept(this);
1676 void TypeId::visit(const NullValue *)
1678 _result = QLatin1String("null");
1681 void TypeId::visit(const UndefinedValue *)
1683 _result = QLatin1String("undefined");
1686 void TypeId::visit(const NumberValue *)
1688 _result = QLatin1String("number");
1691 void TypeId::visit(const BooleanValue *)
1693 _result = QLatin1String("boolean");
1696 void TypeId::visit(const StringValue *)
1698 _result = QLatin1String("string");
1701 void TypeId::visit(const ObjectValue *object)
1703 _result = object->className();
1705 if (_result.isEmpty())
1706 _result = QLatin1String("object");
1709 void TypeId::visit(const FunctionValue *object)
1711 _result = object->className();
1713 if (_result.isEmpty())
1714 _result = QLatin1String("Function");
1717 void TypeId::visit(const ColorValue *)
1719 _result = QLatin1String("string");
1722 void TypeId::visit(const AnchorLineValue *)
1724 _result = QLatin1String("AnchorLine");
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)
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);
1751 ASTObjectValue::~ASTObjectValue()
1755 const ASTObjectValue *ASTObjectValue::asAstObjectValue() const
1760 bool ASTObjectValue::getSourceLocation(QString *fileName, int *line, int *column) const
1762 *fileName = _doc->fileName();
1763 *line = _typeName->identifierToken.startLine;
1764 *column = _typeName->identifierToken.startColumn;
1768 void ASTObjectValue::processMembers(MemberProcessor *processor) const
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);
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);
1781 ObjectValue::processMembers(processor);
1784 QString ASTObjectValue::defaultPropertyName() const
1786 if (_defaultPropertyRef) {
1787 UiPublicMember *prop = _defaultPropertyRef->ast();
1789 return prop->name.toString();
1794 UiObjectInitializer *ASTObjectValue::initializer() const
1796 return _initializer;
1799 UiQualifiedId *ASTObjectValue::typeName() const
1804 const Document *ASTObjectValue::document() const
1809 ASTVariableReference::ASTVariableReference(VariableDeclaration *ast, const Document *doc, ValueOwner *valueOwner)
1810 : Reference(valueOwner)
1816 ASTVariableReference::~ASTVariableReference()
1820 const Value *ASTVariableReference::value(ReferenceContext *referenceContext) const
1822 // may be assigned to later
1823 if (!_ast->expression)
1824 return valueOwner()->unknownValue();
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()));
1831 Evaluate evaluator(&scopeChain, referenceContext);
1832 return evaluator(_ast->expression);
1835 bool ASTVariableReference::getSourceLocation(QString *fileName, int *line, int *column) const
1837 *fileName = _doc->fileName();
1838 *line = _ast->identifierToken.startLine;
1839 *column = _ast->identifierToken.startColumn;
1843 ASTFunctionValue::ASTFunctionValue(FunctionExpression *ast, const Document *doc, ValueOwner *valueOwner)
1844 : FunctionValue(valueOwner), _ast(ast), _doc(doc)
1846 setPrototype(valueOwner->functionPrototype());
1848 for (FormalParameterList *it = ast->formals; it; it = it->next)
1849 _argumentNames.append(it->name.toString());
1852 ASTFunctionValue::~ASTFunctionValue()
1856 FunctionExpression *ASTFunctionValue::ast() const
1861 int ASTFunctionValue::argumentCount() const
1863 return _argumentNames.size();
1866 QString ASTFunctionValue::argumentName(int index) const
1868 if (index < _argumentNames.size()) {
1869 const QString &name = _argumentNames.at(index);
1870 if (!name.isEmpty())
1874 return FunctionValue::argumentName(index);
1877 bool ASTFunctionValue::getSourceLocation(QString *fileName, int *line, int *column) const
1879 *fileName = _doc->fileName();
1880 *line = _ast->identifierToken.startLine;
1881 *column = _ast->identifierToken.startColumn;
1885 QmlPrototypeReference::QmlPrototypeReference(UiQualifiedId *qmlTypeName, const Document *doc,
1886 ValueOwner *valueOwner)
1887 : Reference(valueOwner),
1888 _qmlTypeName(qmlTypeName),
1893 QmlPrototypeReference::~QmlPrototypeReference()
1897 const QmlPrototypeReference *QmlPrototypeReference::asQmlPrototypeReference() const
1902 UiQualifiedId *QmlPrototypeReference::qmlTypeName() const
1904 return _qmlTypeName;
1907 const Value *QmlPrototypeReference::value(ReferenceContext *referenceContext) const
1909 return referenceContext->context()->lookupType(_doc, _qmlTypeName);
1912 ASTPropertyReference::ASTPropertyReference(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner)
1913 : Reference(valueOwner), _ast(ast), _doc(doc)
1915 const QString &propertyName = ast->name.toString();
1916 _onChangedSlotName = generatedSlotName(propertyName);
1917 _onChangedSlotName += QLatin1String("Changed");
1920 ASTPropertyReference::~ASTPropertyReference()
1924 const ASTPropertyReference *ASTPropertyReference::asAstPropertyReference() const
1929 bool ASTPropertyReference::getSourceLocation(QString *fileName, int *line, int *column) const
1931 *fileName = _doc->fileName();
1932 *line = _ast->identifierToken.startLine;
1933 *column = _ast->identifierToken.startColumn;
1937 const Value *ASTPropertyReference::value(ReferenceContext *referenceContext) const
1940 && (_ast->memberType.isEmpty()
1941 || _ast->memberType == QLatin1String("variant")
1942 || _ast->memberType == QLatin1String("var")
1943 || _ast->memberType == QLatin1String("alias"))) {
1945 // Adjust the context for the current location - expensive!
1946 // ### Improve efficiency by caching the 'use chain' constructed in ScopeBuilder.
1948 Document::Ptr doc = _doc->ptr();
1949 ScopeChain scopeChain(doc, referenceContext->context());
1950 ScopeBuilder builder(&scopeChain);
1952 int offset = _ast->statement->firstSourceLocation().begin();
1953 builder.push(ScopeAstPath(doc)(offset));
1955 Evaluate evaluator(&scopeChain, referenceContext);
1956 return evaluator(_ast->statement);
1959 return valueOwner()->defaultValueForBuiltinType(_ast->memberType.toString());
1962 ASTSignal::ASTSignal(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner)
1963 : FunctionValue(valueOwner), _ast(ast), _doc(doc)
1965 const QString &signalName = ast->name.toString();
1966 _slotName = generatedSlotName(signalName);
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()));
1976 ASTSignal::~ASTSignal()
1980 const ASTSignal *ASTSignal::asAstSignal() const
1985 int ASTSignal::argumentCount() const
1988 for (UiParameterList *it = _ast->parameters; it; it = it->next)
1993 const Value *ASTSignal::argument(int index) const
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());
2003 QString ASTSignal::argumentName(int index) const
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();
2013 bool ASTSignal::getSourceLocation(QString *fileName, int *line, int *column) const
2015 *fileName = _doc->fileName();
2016 *line = _ast->identifierToken.startLine;
2017 *column = _ast->identifierToken.startColumn;
2022 ImportInfo::ImportInfo()
2023 : _type(InvalidImport)
2028 ImportInfo ImportInfo::moduleImport(QString uri, ComponentVersion version,
2029 const QString &as, UiImport *ast)
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);
2038 info._type = LibraryImport;
2041 info._path.replace(QLatin1Char('.'), QDir::separator());
2042 info._version = version;
2048 ImportInfo ImportInfo::pathImport(const QString &docPath, const QString &path,
2049 ComponentVersion version, const QString &as, UiImport *ast)
2054 QFileInfo importFileInfo(path);
2055 if (!importFileInfo.isAbsolute()) {
2056 importFileInfo = QFileInfo(docPath + QDir::separator() + path);
2058 info._path = importFileInfo.absoluteFilePath();
2060 if (importFileInfo.isFile()) {
2061 info._type = FileImport;
2062 } else if (importFileInfo.isDir()) {
2063 info._type = DirectoryImport;
2065 info._type = UnknownFileImport;
2068 info._version = version;
2074 ImportInfo ImportInfo::invalidImport(UiImport *ast)
2077 info._type = InvalidImport;
2082 ImportInfo ImportInfo::implicitDirectoryImport(const QString &directory)
2085 info._type = ImplicitDirectoryImport;
2086 info._path = directory;
2090 bool ImportInfo::isValid() const
2092 return _type != InvalidImport;
2095 ImportInfo::Type ImportInfo::type() const
2100 QString ImportInfo::name() const
2105 QString ImportInfo::path() const
2110 QString ImportInfo::as() const
2115 ComponentVersion ImportInfo::version() const
2120 UiImport *ImportInfo::ast() const
2129 TypeScope::TypeScope(const Imports *imports, ValueOwner *valueOwner)
2130 : ObjectValue(valueOwner)
2135 const Value *TypeScope::lookupMember(const QString &name, const Context *context,
2136 const ObjectValue **foundInObject, bool) const
2138 QListIterator<Import> it(_imports->all());
2140 while (it.hasPrevious()) {
2141 const Import &i = it.previous();
2142 const ObjectValue *import = i.object;
2143 const ImportInfo &info = i.info;
2145 // JS import has no types
2146 if (info.type() == ImportInfo::FileImport)
2149 if (!info.as().isEmpty()) {
2150 if (info.as() == name) {
2152 *foundInObject = this;
2158 if (const Value *v = import->lookupMember(name, context, foundInObject))
2166 void TypeScope::processMembers(MemberProcessor *processor) const
2168 QListIterator<Import> it(_imports->all());
2170 while (it.hasPrevious()) {
2171 const Import &i = it.previous();
2172 const ObjectValue *import = i.object;
2173 const ImportInfo &info = i.info;
2175 // JS import has no types
2176 if (info.type() == ImportInfo::FileImport)
2179 if (!info.as().isEmpty()) {
2180 processor->processProperty(info.as(), import);
2182 import->processMembers(processor);
2187 JSImportScope::JSImportScope(const Imports *imports, ValueOwner *valueOwner)
2188 : ObjectValue(valueOwner)
2193 const Value *JSImportScope::lookupMember(const QString &name, const Context *,
2194 const ObjectValue **foundInObject, bool) const
2196 QListIterator<Import> it(_imports->all());
2198 while (it.hasPrevious()) {
2199 const Import &i = it.previous();
2200 const ObjectValue *import = i.object;
2201 const ImportInfo &info = i.info;
2203 // JS imports are always: import "somefile.js" as Foo
2204 if (info.type() != ImportInfo::FileImport)
2207 if (info.as() == name) {
2209 *foundInObject = this;
2218 void JSImportScope::processMembers(MemberProcessor *processor) const
2220 QListIterator<Import> it(_imports->all());
2222 while (it.hasPrevious()) {
2223 const Import &i = it.previous();
2224 const ObjectValue *import = i.object;
2225 const ImportInfo &info = i.info;
2227 if (info.type() == ImportInfo::FileImport)
2228 processor->processProperty(info.as(), import);
2232 Imports::Imports(ValueOwner *valueOwner)
2233 : _typeScope(new TypeScope(this, valueOwner))
2234 , _jsImportScope(new JSImportScope(this, valueOwner))
2235 , _importFailed(false)
2238 void Imports::append(const Import &import)
2240 // when doing lookup, imports with 'as' clause are looked at first
2241 if (!import.info.as().isEmpty()) {
2242 _imports.append(import);
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);
2251 // not found, append
2252 _imports.append(import);
2256 _importFailed = true;
2259 void Imports::setImportFailed()
2261 _importFailed = true;
2264 ImportInfo Imports::info(const QString &name, const Context *context) const
2266 QString firstId = name;
2267 int dotIdx = firstId.indexOf(QLatin1Char('.'));
2269 firstId = firstId.left(dotIdx);
2271 QListIterator<Import> it(_imports);
2273 while (it.hasPrevious()) {
2274 const Import &i = it.previous();
2275 const ObjectValue *import = i.object;
2276 const ImportInfo &info = i.info;
2278 if (!info.as().isEmpty()) {
2279 if (info.as() == firstId)
2284 if (info.type() == ImportInfo::FileImport) {
2285 if (import->className() == firstId)
2288 if (import->lookupMember(firstId, context))
2292 return ImportInfo();
2295 QString Imports::nameForImportedObject(const ObjectValue *value, const Context *context) const
2297 QListIterator<Import> it(_imports);
2299 while (it.hasPrevious()) {
2300 const Import &i = it.previous();
2301 const ObjectValue *import = i.object;
2302 const ImportInfo &info = i.info;
2304 if (info.type() == ImportInfo::FileImport) {
2305 if (import == value)
2306 return import->className();
2308 const Value *v = import->lookupMember(value->className(), context);
2310 QString result = value->className();
2311 if (!info.as().isEmpty()) {
2312 result.prepend(QLatin1Char('.'));
2313 result.prepend(info.as());
2322 bool Imports::importFailed() const
2324 return _importFailed;
2327 QList<Import> Imports::all() const
2332 const TypeScope *Imports::typeScope() const
2337 const JSImportScope *Imports::jsImportScope() const
2339 return _jsImportScope;
2344 class MemberDumper: public MemberProcessor
2349 virtual bool processProperty(const QString &name, const Value *)
2351 qDebug() << "property: " << name;
2355 virtual bool processEnumerator(const QString &name, const Value *)
2357 qDebug() << "enumerator: " << name;
2361 virtual bool processSignal(const QString &name, const Value *)
2363 qDebug() << "signal: " << name;
2367 virtual bool processSlot(const QString &name, const Value *)
2369 qDebug() << "slot: " << name;
2373 virtual bool processGeneratedSlot(const QString &name, const Value *)
2375 qDebug() << "generated slot: " << name;
2380 void Imports::dump() const
2382 qDebug() << "Imports contents, in search order:";
2383 QListIterator<Import> it(_imports);
2385 while (it.hasPrevious()) {
2386 const Import &i = it.previous();
2387 const ObjectValue *import = i.object;
2388 const ImportInfo &info = i.info;
2390 qDebug() << " " << info.path() << " " << info.version().toString() << " as " << info.as() << " : " << import;
2391 MemberDumper dumper;
2392 import->processMembers(&dumper);