1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "parser/qmljsast_p.h"
27 #include "qmljsconstants.h"
28 #include "qmljscontext.h"
29 #include "qmljsevaluate.h"
30 #include "qmljsinterpreter.h"
31 #include "qmljsmodelmanagerinterface.h"
32 #include "qmljsscopeastpath.h"
33 #include "qmljsscopebuilder.h"
34 #include "qmljsscopechain.h"
35 #include "qmljstypedescriptionreader.h"
36 #include "qmljsvalueowner.h"
37
38 #include <utils/qtcassert.h>
39
40 #include <QApplication>
41 #include <QDir>
42 #include <QFile>
43 #include <QString>
44 #include <QStringList>
45
46 using namespace LanguageUtils;
47 using namespace QmlJS;
48 using namespace QmlJS::AST;
49
50 /*!
51 \class QmlJS::Value
52 \brief The Value class is an abstract base class for the result of a
53 JS expression.
54 \sa Evaluate ValueOwner ValueVisitor
55
56 A Value represents a category of JavaScript values, such as number
57 (NumberValue), string (StringValue) or functions with a
58 specific signature (FunctionValue). It can also represent internal
59 categories such as "a QML component instantiation defined in a file"
60 (ASTObjectValue), "a QML component defined in C++"
61 (CppComponentValue) or "no specific information is available"
62 (UnknownValue).
63
64 The Value class itself provides accept() for admitting
65 \l{ValueVisitor}s and a do-nothing getSourceLocation().
66
67 Value instances should be cast to a derived type either through the
68 asXXX() helper functions such as asNumberValue() or via the
69 value_cast() template function.
70
71 Values are the result of many operations in the QmlJS code model:
72 \list
73 \li \l{Evaluate}
74 \li Context::lookupType() and Context::lookupReference()
75 \li ScopeChain::lookup()
76 \li ObjectValue::lookupMember()
77 \endlist
78 */
79
80 namespace {
81
82 class LookupMember: public MemberProcessor
83 {
84 QString m_name;
85 const Value *m_value;
86
process(const QString & name,const Value * value)87 bool process(const QString &name, const Value *value)
88 {
89 if (m_value)
90 return false;
91
92 if (name == m_name) {
93 m_value = value;
94 return false;
95 }
96
97 return true;
98 }
99
100 public:
LookupMember(const QString & name)101 LookupMember(const QString &name)
102 : m_name(name), m_value(0) {}
103
value() const104 const Value *value() const { return m_value; }
105
processProperty(const QString & name,const Value * value,const PropertyInfo &)106 bool processProperty(const QString &name, const Value *value, const PropertyInfo &) override
107 {
108 return process(name, value);
109 }
110
processEnumerator(const QString & name,const Value * value)111 bool processEnumerator(const QString &name, const Value *value) override
112 {
113 return process(name, value);
114 }
115
processSignal(const QString & name,const Value * value)116 bool processSignal(const QString &name, const Value *value) override
117 {
118 return process(name, value);
119 }
120
processSlot(const QString & name,const Value * value)121 bool processSlot(const QString &name, const Value *value) override
122 {
123 return process(name, value);
124 }
125
processGeneratedSlot(const QString & name,const Value * value)126 bool processGeneratedSlot(const QString &name, const Value *value) override
127 {
128 return process(name, value);
129 }
130 };
131
132 } // end of anonymous namespace
133
134 namespace QmlJS {
135
MetaFunction(const FakeMetaMethod & method,ValueOwner * valueOwner)136 MetaFunction::MetaFunction(const FakeMetaMethod &method, ValueOwner *valueOwner)
137 : FunctionValue(valueOwner), m_method(method)
138 {
139 }
140
namedArgumentCount() const141 int MetaFunction::namedArgumentCount() const
142 {
143 return m_method.parameterNames().size();
144 }
145
argumentName(int index) const146 QString MetaFunction::argumentName(int index) const
147 {
148 if (index < m_method.parameterNames().size())
149 return m_method.parameterNames().at(index);
150
151 return FunctionValue::argumentName(index);
152 }
153
isVariadic() const154 bool MetaFunction::isVariadic() const
155 {
156 return false;
157 }
asMetaFunction() const158 const MetaFunction *MetaFunction::asMetaFunction() const
159 {
160 return this;
161 }
fakeMetaMethod() const162 const FakeMetaMethod &MetaFunction::fakeMetaMethod() const
163 {
164 return m_method;
165 }
166
FakeMetaObjectWithOrigin(FakeMetaObject::ConstPtr fakeMetaObject,const QString & originId)167 FakeMetaObjectWithOrigin::FakeMetaObjectWithOrigin(FakeMetaObject::ConstPtr fakeMetaObject, const QString &originId)
168 : fakeMetaObject(fakeMetaObject)
169 , originId(originId)
170 { }
171
operator ==(const FakeMetaObjectWithOrigin & o) const172 bool FakeMetaObjectWithOrigin::operator ==(const FakeMetaObjectWithOrigin &o) const
173 {
174 return fakeMetaObject == o.fakeMetaObject;
175 }
176
qHash(const FakeMetaObjectWithOrigin & fmoo)177 uint qHash(const FakeMetaObjectWithOrigin &fmoo)
178 {
179 return qHash(fmoo.fakeMetaObject);
180 }
181
PropertyInfo(uint flags)182 PropertyInfo::PropertyInfo(uint flags)
183 : flags(flags)
184 { }
185
toString() const186 QString PropertyInfo::toString() const
187 {
188 QStringList list;
189 if (isReadable())
190 list.append("Readable");
191
192 if (isWriteable())
193 list.append("Writeable");
194
195 if (isList())
196 list.append("ListType");
197
198 if (canBePointer())
199 list.append("Pointer");
200
201 if (canBeValue())
202 list.append("Value");
203
204 return list.join('|');
205 }
206
207 static QList<CustomImportsProvider *> g_customImportProviders;
208
CustomImportsProvider(QObject * parent)209 CustomImportsProvider::CustomImportsProvider(QObject *parent)
210 : QObject(parent)
211 {
212 g_customImportProviders.append(this);
213 }
214
~CustomImportsProvider()215 CustomImportsProvider::~CustomImportsProvider()
216 {
217 g_customImportProviders.removeOne(this);
218 }
219
allProviders()220 const QList<CustomImportsProvider *> CustomImportsProvider::allProviders()
221 {
222 return g_customImportProviders;
223 }
224
225 } // namespace QmlJS
226
CppComponentValue(FakeMetaObject::ConstPtr metaObject,const QString & className,const QString & packageName,const ComponentVersion & componentVersion,const ComponentVersion & importVersion,int metaObjectRevision,ValueOwner * valueOwner,const QString & originId)227 CppComponentValue::CppComponentValue(FakeMetaObject::ConstPtr metaObject, const QString &className,
228 const QString &packageName, const ComponentVersion &componentVersion,
229 const ComponentVersion &importVersion, int metaObjectRevision,
230 ValueOwner *valueOwner, const QString &originId)
231 : ObjectValue(valueOwner, originId),
232 m_metaObject(metaObject),
233 m_moduleName(packageName),
234 m_componentVersion(componentVersion),
235 m_importVersion(importVersion),
236 m_metaObjectRevision(metaObjectRevision)
237 {
238 setClassName(className);
239 int nEnums = metaObject->enumeratorCount();
240 for (int i = 0; i < nEnums; ++i) {
241 FakeMetaEnum fEnum = metaObject->enumerator(i);
242 m_enums[fEnum.name()] = new QmlEnumValue(this, i);
243 }
244 }
245
~CppComponentValue()246 CppComponentValue::~CppComponentValue()
247 {
248 delete m_metaSignatures.load();
249 delete m_signalScopes.load();
250 }
251
generatedSlotName(const QString & base)252 static QString generatedSlotName(const QString &base)
253 {
254 QString slotName = QLatin1String("on");
255 int firstChar=0;
256 while (firstChar < base.size()) {
257 QChar c = base.at(firstChar);
258 slotName += c.toUpper();
259 ++firstChar;
260 if (c != QLatin1Char('_'))
261 break;
262 }
263 slotName += base.midRef(firstChar);
264 return slotName;
265 }
266
asCppComponentValue() const267 const CppComponentValue *CppComponentValue::asCppComponentValue() const
268 {
269 return this;
270 }
271
processMembers(MemberProcessor * processor) const272 void CppComponentValue::processMembers(MemberProcessor *processor) const
273 {
274 // process the meta enums
275 for (int index = m_metaObject->enumeratorOffset(); index < m_metaObject->enumeratorCount(); ++index) {
276 FakeMetaEnum e = m_metaObject->enumerator(index);
277
278 for (int i = 0; i < e.keyCount(); ++i) {
279 processor->processEnumerator(e.key(i), valueOwner()->numberValue());
280 }
281 }
282
283 // all explicitly defined signal names
284 QSet<QString> explicitSignals;
285
286 // make MetaFunction instances lazily when first needed
287 QList<const Value *> *signatures = m_metaSignatures.load();
288 if (!signatures) {
289 signatures = new QList<const Value *>;
290 signatures->reserve(m_metaObject->methodCount());
291 for (int index = 0; index < m_metaObject->methodCount(); ++index)
292 signatures->append(new MetaFunction(m_metaObject->method(index), valueOwner()));
293 if (!m_metaSignatures.testAndSetOrdered(0, signatures)) {
294 delete signatures;
295 signatures = m_metaSignatures.load();
296 }
297 }
298
299 // process the meta methods
300 for (int index = 0; index < m_metaObject->methodCount(); ++index) {
301 const FakeMetaMethod method = m_metaObject->method(index);
302 if (m_metaObjectRevision < method.revision())
303 continue;
304
305 const QString &methodName = m_metaObject->method(index).methodName();
306 const Value *signature = signatures->at(index);
307
308 if (method.methodType() == FakeMetaMethod::Slot && method.access() == FakeMetaMethod::Public) {
309 processor->processSlot(methodName, signature);
310
311 } else if (method.methodType() == FakeMetaMethod::Signal && method.access() != FakeMetaMethod::Private) {
312 // process the signal
313 processor->processSignal(methodName, signature);
314 explicitSignals.insert(methodName);
315
316 // process the generated slot
317 const QString &slotName = generatedSlotName(methodName);
318 processor->processGeneratedSlot(slotName, signature);
319 }
320 }
321
322 // process the meta properties
323 for (int index = 0; index < m_metaObject->propertyCount(); ++index) {
324 const FakeMetaProperty prop = m_metaObject->property(index);
325 if (m_metaObjectRevision < prop.revision())
326 continue;
327
328 const QString propertyName = prop.name();
329 uint propertyFlags = PropertyInfo::Readable;
330 if (isWritable(propertyName))
331 propertyFlags |= PropertyInfo::Writeable;
332 if (isListProperty(propertyName))
333 propertyFlags |= PropertyInfo::ListType;
334 if (isPointer(propertyName))
335 propertyFlags |= PropertyInfo::PointerType;
336 else
337 propertyFlags |= PropertyInfo::ValueType;
338 processor->processProperty(propertyName, valueForCppName(prop.typeName()),
339 PropertyInfo(propertyFlags));
340
341 // every property always has a onXyzChanged slot, even if the NOTIFY
342 // signal has a different name
343 QString signalName = propertyName;
344 signalName += QLatin1String("Changed");
345 if (!explicitSignals.contains(signalName)) {
346 // process the generated slot
347 const QString &slotName = generatedSlotName(signalName);
348 processor->processGeneratedSlot(slotName, valueOwner()->unknownValue());
349 }
350 }
351
352 // look into attached types
353 const QString &attachedTypeName = m_metaObject->attachedTypeName();
354 if (!attachedTypeName.isEmpty()) {
355 const CppComponentValue *attachedType = valueOwner()->cppQmlTypes().objectByCppName(attachedTypeName);
356 if (attachedType && attachedType != this) // ### only weak protection against infinite loops
357 attachedType->processMembers(processor);
358 }
359
360 ObjectValue::processMembers(processor);
361 }
362
valueForCppName(const QString & typeName) const363 const Value *CppComponentValue::valueForCppName(const QString &typeName) const
364 {
365 const CppQmlTypes &cppTypes = valueOwner()->cppQmlTypes();
366
367 // check in the same package/version first
368 const CppComponentValue *objectValue = cppTypes.objectByQualifiedName(
369 m_moduleName, typeName, m_importVersion);
370 if (objectValue)
371 return objectValue;
372
373 // fallback to plain cpp name
374 objectValue = cppTypes.objectByCppName(typeName);
375 if (objectValue)
376 return objectValue;
377
378 // try qml builtin type names
379 if (const Value *v = valueOwner()->defaultValueForBuiltinType(typeName)) {
380 if (!v->asUndefinedValue())
381 return v;
382 }
383
384 // map other C++ types
385 if (typeName == QLatin1String("QByteArray")
386 || typeName == QLatin1String("QString")) {
387 return valueOwner()->stringValue();
388 } else if (typeName == QLatin1String("QUrl")) {
389 return valueOwner()->urlValue();
390 } else if (typeName == QLatin1String("long")) {
391 return valueOwner()->intValue();
392 } else if (typeName == QLatin1String("float")
393 || typeName == QLatin1String("qreal")) {
394 return valueOwner()->realValue();
395 } else if (typeName == QLatin1String("QFont")) {
396 return valueOwner()->qmlFontObject();
397 } else if (typeName == QLatin1String("QPoint")
398 || typeName == QLatin1String("QPointF")
399 || typeName == QLatin1String("QVector2D")) {
400 return valueOwner()->qmlPointObject();
401 } else if (typeName == QLatin1String("QSize")
402 || typeName == QLatin1String("QSizeF")) {
403 return valueOwner()->qmlSizeObject();
404 } else if (typeName == QLatin1String("QRect")
405 || typeName == QLatin1String("QRectF")) {
406 return valueOwner()->qmlRectObject();
407 } else if (typeName == QLatin1String("QVector3D")) {
408 return valueOwner()->qmlVector3DObject();
409 } else if (typeName == QLatin1String("QColor")) {
410 return valueOwner()->colorValue();
411 } else if (typeName == QLatin1String("QDeclarativeAnchorLine")) {
412 return valueOwner()->anchorLineValue();
413 }
414
415 // might be an enum
416 const CppComponentValue *base = this;
417 const QStringList components = typeName.split(QLatin1String("::"));
418 if (components.size() == 2)
419 base = valueOwner()->cppQmlTypes().objectByCppName(components.first());
420 if (base) {
421 if (const QmlEnumValue *value = base->getEnumValue(components.last()))
422 return value;
423 }
424
425 // may still be a cpp based value
426 return valueOwner()->unknownValue();
427 }
428
prototype() const429 const CppComponentValue *CppComponentValue::prototype() const
430 {
431 Q_ASSERT(!_prototype || value_cast<CppComponentValue>(_prototype));
432 return static_cast<const CppComponentValue *>(_prototype);
433 }
434
435 /*!
436 Returns a list started by this object and followed by all its prototypes.
437
438 Use this function rather than calling prototype() in a loop, as it avoids
439 cycles.
440 */
prototypes() const441 QList<const CppComponentValue *> CppComponentValue::prototypes() const
442 {
443 QList<const CppComponentValue *> protos;
444 for (const CppComponentValue *it = this; it; it = it->prototype()) {
445 if (protos.contains(it))
446 break;
447 protos += it;
448 }
449 return protos;
450 }
451
metaObject() const452 FakeMetaObject::ConstPtr CppComponentValue::metaObject() const
453 {
454 return m_metaObject;
455 }
456
moduleName() const457 QString CppComponentValue::moduleName() const
458 { return m_moduleName; }
459
componentVersion() const460 ComponentVersion CppComponentValue::componentVersion() const
461 { return m_componentVersion; }
462
importVersion() const463 ComponentVersion CppComponentValue::importVersion() const
464 { return m_importVersion; }
465
defaultPropertyName() const466 QString CppComponentValue::defaultPropertyName() const
467 { return m_metaObject->defaultPropertyName(); }
468
propertyType(const QString & propertyName) const469 QString CppComponentValue::propertyType(const QString &propertyName) const
470 {
471 foreach (const CppComponentValue *it, prototypes()) {
472 FakeMetaObject::ConstPtr iter = it->m_metaObject;
473 int propIdx = iter->propertyIndex(propertyName);
474 if (propIdx != -1)
475 return iter->property(propIdx).typeName();
476 }
477 return QString();
478 }
479
isListProperty(const QString & propertyName) const480 bool CppComponentValue::isListProperty(const QString &propertyName) const
481 {
482 foreach (const CppComponentValue *it, prototypes()) {
483 FakeMetaObject::ConstPtr iter = it->m_metaObject;
484 int propIdx = iter->propertyIndex(propertyName);
485 if (propIdx != -1)
486 return iter->property(propIdx).isList();
487 }
488 return false;
489 }
490
getEnum(const QString & typeName,const CppComponentValue ** foundInScope) const491 FakeMetaEnum CppComponentValue::getEnum(const QString &typeName, const CppComponentValue **foundInScope) const
492 {
493 foreach (const CppComponentValue *it, prototypes()) {
494 FakeMetaObject::ConstPtr iter = it->m_metaObject;
495 const int index = iter->enumeratorIndex(typeName);
496 if (index != -1) {
497 if (foundInScope)
498 *foundInScope = it;
499 return iter->enumerator(index);
500 }
501 }
502 if (foundInScope)
503 *foundInScope = 0;
504 return FakeMetaEnum();
505 }
506
getEnumValue(const QString & typeName,const CppComponentValue ** foundInScope) const507 const QmlEnumValue *CppComponentValue::getEnumValue(const QString &typeName, const CppComponentValue **foundInScope) const
508 {
509 foreach (const CppComponentValue *it, prototypes()) {
510 if (const QmlEnumValue *e = it->m_enums.value(typeName)) {
511 if (foundInScope)
512 *foundInScope = it;
513 return e;
514 }
515 }
516 if (foundInScope)
517 *foundInScope = 0;
518 return 0;
519 }
520
signalScope(const QString & signalName) const521 const ObjectValue *CppComponentValue::signalScope(const QString &signalName) const
522 {
523 QHash<QString, const ObjectValue *> *scopes = m_signalScopes.load();
524 if (!scopes) {
525 scopes = new QHash<QString, const ObjectValue *>;
526 // usually not all methods are signals
527 scopes->reserve(m_metaObject->methodCount() / 2);
528 for (int index = 0; index < m_metaObject->methodCount(); ++index) {
529 const FakeMetaMethod &method = m_metaObject->method(index);
530 if (method.methodType() != FakeMetaMethod::Signal || method.access() == FakeMetaMethod::Private)
531 continue;
532
533 const QStringList ¶meterNames = method.parameterNames();
534 const QStringList ¶meterTypes = method.parameterTypes();
535 QTC_ASSERT(parameterNames.size() == parameterTypes.size(), continue);
536
537 ObjectValue *scope = valueOwner()->newObject(/*prototype=*/0);
538 for (int i = 0; i < parameterNames.size(); ++i) {
539 const QString &name = parameterNames.at(i);
540 const QString &type = parameterTypes.at(i);
541 if (name.isEmpty())
542 continue;
543 scope->setMember(name, valueForCppName(type));
544 }
545 scopes->insert(generatedSlotName(method.methodName()), scope);
546 }
547 if (!m_signalScopes.testAndSetOrdered(0, scopes)) {
548 delete scopes;
549 scopes = m_signalScopes.load();
550 }
551 }
552
553 return scopes->value(signalName);
554 }
555
isWritable(const QString & propertyName) const556 bool CppComponentValue::isWritable(const QString &propertyName) const
557 {
558 foreach (const CppComponentValue *it, prototypes()) {
559 FakeMetaObject::ConstPtr iter = it->m_metaObject;
560 int propIdx = iter->propertyIndex(propertyName);
561 if (propIdx != -1)
562 return iter->property(propIdx).isWritable();
563 }
564 return false;
565 }
566
isPointer(const QString & propertyName) const567 bool CppComponentValue::isPointer(const QString &propertyName) const
568 {
569 foreach (const CppComponentValue *it, prototypes()) {
570 FakeMetaObject::ConstPtr iter = it->m_metaObject;
571 int propIdx = iter->propertyIndex(propertyName);
572 if (propIdx != -1)
573 return iter->property(propIdx).isPointer();
574 }
575 return false;
576 }
577
hasLocalProperty(const QString & typeName) const578 bool CppComponentValue::hasLocalProperty(const QString &typeName) const
579 {
580 int idx = m_metaObject->propertyIndex(typeName);
581 if (idx == -1)
582 return false;
583 return true;
584 }
585
hasProperty(const QString & propertyName) const586 bool CppComponentValue::hasProperty(const QString &propertyName) const
587 {
588 foreach (const CppComponentValue *it, prototypes()) {
589 FakeMetaObject::ConstPtr iter = it->m_metaObject;
590 int propIdx = iter->propertyIndex(propertyName);
591 if (propIdx != -1)
592 return true;
593 }
594 return false;
595 }
596
isDerivedFrom(FakeMetaObject::ConstPtr base) const597 bool CppComponentValue::isDerivedFrom(FakeMetaObject::ConstPtr base) const
598 {
599 foreach (const CppComponentValue *it, prototypes()) {
600 FakeMetaObject::ConstPtr iter = it->m_metaObject;
601 if (iter == base)
602 return true;
603 }
604 return false;
605 }
606
QmlEnumValue(const CppComponentValue * owner,int enumIndex)607 QmlEnumValue::QmlEnumValue(const CppComponentValue *owner, int enumIndex)
608 : m_owner(owner)
609 , m_enumIndex(enumIndex)
610 {
611 owner->valueOwner()->registerValue(this);
612 }
613
~QmlEnumValue()614 QmlEnumValue::~QmlEnumValue()
615 {
616 }
617
asQmlEnumValue() const618 const QmlEnumValue *QmlEnumValue::asQmlEnumValue() const
619 {
620 return this;
621 }
622
name() const623 QString QmlEnumValue::name() const
624 {
625 return m_owner->metaObject()->enumerator(m_enumIndex).name();
626 }
627
keys() const628 QStringList QmlEnumValue::keys() const
629 {
630 return m_owner->metaObject()->enumerator(m_enumIndex).keys();
631 }
632
owner() const633 const CppComponentValue *QmlEnumValue::owner() const
634 {
635 return m_owner;
636 }
637
638 ////////////////////////////////////////////////////////////////////////////////
639 // ValueVisitor
640 ////////////////////////////////////////////////////////////////////////////////
ValueVisitor()641 ValueVisitor::ValueVisitor()
642 {
643 }
644
~ValueVisitor()645 ValueVisitor::~ValueVisitor()
646 {
647 }
648
visit(const NullValue *)649 void ValueVisitor::visit(const NullValue *)
650 {
651 }
652
visit(const UndefinedValue *)653 void ValueVisitor::visit(const UndefinedValue *)
654 {
655 }
656
visit(const UnknownValue *)657 void ValueVisitor::visit(const UnknownValue *)
658 {
659 }
660
visit(const NumberValue *)661 void ValueVisitor::visit(const NumberValue *)
662 {
663 }
664
visit(const BooleanValue *)665 void ValueVisitor::visit(const BooleanValue *)
666 {
667 }
668
visit(const StringValue *)669 void ValueVisitor::visit(const StringValue *)
670 {
671 }
672
visit(const ObjectValue *)673 void ValueVisitor::visit(const ObjectValue *)
674 {
675 }
676
visit(const FunctionValue *)677 void ValueVisitor::visit(const FunctionValue *)
678 {
679 }
680
visit(const Reference *)681 void ValueVisitor::visit(const Reference *)
682 {
683 }
684
visit(const ColorValue *)685 void ValueVisitor::visit(const ColorValue *)
686 {
687 }
688
visit(const AnchorLineValue *)689 void ValueVisitor::visit(const AnchorLineValue *)
690 {
691 }
692
693 ////////////////////////////////////////////////////////////////////////////////
694 // Value
695 ////////////////////////////////////////////////////////////////////////////////
Value()696 Value::Value()
697 {
698 }
699
~Value()700 Value::~Value()
701 {
702 }
703
getSourceLocation(QString *,int *,int *) const704 bool Value::getSourceLocation(QString *, int *, int *) const
705 {
706 return false;
707 }
708
asNullValue() const709 const NullValue *Value::asNullValue() const
710 {
711 return 0;
712 }
713
asUndefinedValue() const714 const UndefinedValue *Value::asUndefinedValue() const
715 {
716 return 0;
717 }
718
asUnknownValue() const719 const UnknownValue *Value::asUnknownValue() const
720 {
721 return 0;
722 }
723
asNumberValue() const724 const NumberValue *Value::asNumberValue() const
725 {
726 return 0;
727 }
728
asIntValue() const729 const IntValue *Value::asIntValue() const
730 {
731 return 0;
732 }
733
asRealValue() const734 const RealValue *Value::asRealValue() const
735 {
736 return 0;
737 }
738
asBooleanValue() const739 const BooleanValue *Value::asBooleanValue() const
740 {
741 return 0;
742 }
743
asStringValue() const744 const StringValue *Value::asStringValue() const
745 {
746 return 0;
747 }
748
asUrlValue() const749 const UrlValue *Value::asUrlValue() const
750 {
751 return 0;
752 }
753
asObjectValue() const754 const ObjectValue *Value::asObjectValue() const
755 {
756 return 0;
757 }
758
asFunctionValue() const759 const FunctionValue *Value::asFunctionValue() const
760 {
761 return 0;
762 }
763
asReference() const764 const Reference *Value::asReference() const
765 {
766 return 0;
767 }
768
asColorValue() const769 const ColorValue *Value::asColorValue() const
770 {
771 return 0;
772 }
773
asAnchorLineValue() const774 const AnchorLineValue *Value::asAnchorLineValue() const
775 {
776 return 0;
777 }
778
asCppComponentValue() const779 const CppComponentValue *Value::asCppComponentValue() const
780 {
781 return 0;
782 }
783
asAstObjectValue() const784 const ASTObjectValue *Value::asAstObjectValue() const
785 {
786 return 0;
787 }
788
asQmlEnumValue() const789 const QmlEnumValue *Value::asQmlEnumValue() const
790 {
791 return 0;
792 }
793
asQmlPrototypeReference() const794 const QmlPrototypeReference *Value::asQmlPrototypeReference() const
795 {
796 return 0;
797 }
798
asAstPropertyReference() const799 const ASTPropertyReference *Value::asAstPropertyReference() const
800 {
801 return 0;
802 }
803
asAstVariableReference() const804 const ASTVariableReference *Value::asAstVariableReference() const
805 {
806 return 0;
807 }
808
asQtObjectPrototypeReference() const809 const Internal::QtObjectPrototypeReference *Value::asQtObjectPrototypeReference() const
810 {
811 return 0;
812 }
813
asAstSignal() const814 const ASTSignal *Value::asAstSignal() const
815 {
816 return 0;
817 }
818
asAstFunctionValue() const819 const ASTFunctionValue *Value::asAstFunctionValue() const
820 {
821 return 0;
822 }
823
asFunction() const824 const Function *Value::asFunction() const
825 {
826 return 0;
827 }
828
asMetaFunction() const829 const MetaFunction *Value::asMetaFunction() const
830 {
831 return 0;
832 }
833
asJSImportScope() const834 const JSImportScope *Value::asJSImportScope() const
835 {
836 return 0;
837 }
838
asTypeScope() const839 const TypeScope *Value::asTypeScope() const
840 {
841 return 0;
842 }
843
844 ////////////////////////////////////////////////////////////////////////////////
845 // Values
846 ////////////////////////////////////////////////////////////////////////////////
asNullValue() const847 const NullValue *NullValue::asNullValue() const
848 {
849 return this;
850 }
851
accept(ValueVisitor * visitor) const852 void NullValue::accept(ValueVisitor *visitor) const
853 {
854 visitor->visit(this);
855 }
856
asUndefinedValue() const857 const UndefinedValue *UndefinedValue::asUndefinedValue() const
858 {
859 return this;
860 }
861
accept(ValueVisitor * visitor) const862 void UnknownValue::accept(ValueVisitor *visitor) const
863 {
864 visitor->visit(this);
865 }
866
asUnknownValue() const867 const UnknownValue *UnknownValue::asUnknownValue() const
868 {
869 return this;
870 }
871
accept(ValueVisitor * visitor) const872 void UndefinedValue::accept(ValueVisitor *visitor) const
873 {
874 visitor->visit(this);
875 }
asNumberValue() const876 const NumberValue *NumberValue::asNumberValue() const
877 {
878 return this;
879 }
880
asRealValue() const881 const RealValue *RealValue::asRealValue() const
882 {
883 return this;
884 }
885
asIntValue() const886 const IntValue *IntValue::asIntValue() const
887 {
888 return this;
889 }
890
accept(ValueVisitor * visitor) const891 void NumberValue::accept(ValueVisitor *visitor) const
892 {
893 visitor->visit(this);
894 }
895
asBooleanValue() const896 const BooleanValue *BooleanValue::asBooleanValue() const
897 {
898 return this;
899 }
900
accept(ValueVisitor * visitor) const901 void BooleanValue::accept(ValueVisitor *visitor) const
902 {
903 visitor->visit(this);
904 }
905
asStringValue() const906 const StringValue *StringValue::asStringValue() const
907 {
908 return this;
909 }
910
asUrlValue() const911 const UrlValue *UrlValue::asUrlValue() const
912 {
913 return this;
914 }
915
accept(ValueVisitor * visitor) const916 void StringValue::accept(ValueVisitor *visitor) const
917 {
918 visitor->visit(this);
919 }
920
Reference(ValueOwner * valueOwner)921 Reference::Reference(ValueOwner *valueOwner)
922 : m_valueOwner(valueOwner)
923 {
924 m_valueOwner->registerValue(this);
925 }
926
~Reference()927 Reference::~Reference()
928 {
929 }
930
valueOwner() const931 ValueOwner *Reference::valueOwner() const
932 {
933 return m_valueOwner;
934 }
935
asReference() const936 const Reference *Reference::asReference() const
937 {
938 return this;
939 }
940
accept(ValueVisitor * visitor) const941 void Reference::accept(ValueVisitor *visitor) const
942 {
943 visitor->visit(this);
944 }
945
value(ReferenceContext *) const946 const Value *Reference::value(ReferenceContext *) const
947 {
948 return m_valueOwner->undefinedValue();
949 }
950
accept(ValueVisitor * visitor) const951 void ColorValue::accept(ValueVisitor *visitor) const
952 {
953 visitor->visit(this);
954 }
955
asColorValue() const956 const ColorValue *ColorValue::asColorValue() const
957 {
958 return this;
959 }
960
accept(ValueVisitor * visitor) const961 void AnchorLineValue::accept(ValueVisitor *visitor) const
962 {
963 visitor->visit(this);
964 }
965
asAnchorLineValue() const966 const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const
967 {
968 return this;
969 }
970
MemberProcessor()971 MemberProcessor::MemberProcessor()
972 {
973 }
974
~MemberProcessor()975 MemberProcessor::~MemberProcessor()
976 {
977 }
978
processProperty(const QString &,const Value *,const PropertyInfo &)979 bool MemberProcessor::processProperty(const QString &, const Value *, const PropertyInfo &)
980 {
981 return true;
982 }
983
processEnumerator(const QString &,const Value *)984 bool MemberProcessor::processEnumerator(const QString &, const Value *)
985 {
986 return true;
987 }
988
processSignal(const QString &,const Value *)989 bool MemberProcessor::processSignal(const QString &, const Value *)
990 {
991 return true;
992 }
993
processSlot(const QString &,const Value *)994 bool MemberProcessor::processSlot(const QString &, const Value *)
995 {
996 return true;
997 }
998
processGeneratedSlot(const QString &,const Value *)999 bool MemberProcessor::processGeneratedSlot(const QString &, const Value *)
1000 {
1001 return true;
1002 }
1003
ObjectValue(ValueOwner * valueOwner,const QString & originId)1004 ObjectValue::ObjectValue(ValueOwner *valueOwner, const QString &originId)
1005 : m_valueOwner(valueOwner), m_originId(originId),
1006 _prototype(0)
1007 {
1008 valueOwner->registerValue(this);
1009 }
1010
~ObjectValue()1011 ObjectValue::~ObjectValue()
1012 {
1013 }
1014
valueOwner() const1015 ValueOwner *ObjectValue::valueOwner() const
1016 {
1017 return m_valueOwner;
1018 }
1019
className() const1020 QString ObjectValue::className() const
1021 {
1022 return m_className;
1023 }
1024
setClassName(const QString & className)1025 void ObjectValue::setClassName(const QString &className)
1026 {
1027 m_className = className;
1028 }
1029
prototype() const1030 const Value *ObjectValue::prototype() const
1031 {
1032 return _prototype;
1033 }
1034
prototype(const Context * context) const1035 const ObjectValue *ObjectValue::prototype(const Context *context) const
1036 {
1037 const ObjectValue *prototypeObject = value_cast<ObjectValue>(_prototype);
1038 if (! prototypeObject) {
1039 if (const Reference *prototypeReference = value_cast<Reference>(_prototype))
1040 prototypeObject = value_cast<ObjectValue>(context->lookupReference(prototypeReference));
1041 }
1042 return prototypeObject;
1043 }
1044
setPrototype(const Value * prototype)1045 void ObjectValue::setPrototype(const Value *prototype)
1046 {
1047 _prototype = prototype;
1048 }
1049
setMember(const QString & name,const Value * value)1050 void ObjectValue::setMember(const QString &name, const Value *value)
1051 {
1052 m_members[name].value = value;
1053 }
1054
setPropertyInfo(const QString & name,const PropertyInfo & propertyInfo)1055 void ObjectValue::setPropertyInfo(const QString &name, const PropertyInfo &propertyInfo)
1056 {
1057 m_members[name].propertyInfo = propertyInfo;
1058 }
1059
removeMember(const QString & name)1060 void ObjectValue::removeMember(const QString &name)
1061 {
1062 m_members.remove(name);
1063 }
1064
asObjectValue() const1065 const ObjectValue *ObjectValue::asObjectValue() const
1066 {
1067 return this;
1068 }
1069
accept(ValueVisitor * visitor) const1070 void ObjectValue::accept(ValueVisitor *visitor) const
1071 {
1072 visitor->visit(this);
1073 }
1074
checkPrototype(const ObjectValue *,QSet<const ObjectValue * > *) const1075 bool ObjectValue::checkPrototype(const ObjectValue *, QSet<const ObjectValue *> *) const
1076 {
1077 #if 0
1078 const int previousSize = processed->size();
1079 processed->insert(this);
1080
1081 if (previousSize != processed->size()) {
1082 if (this == proto)
1083 return false;
1084
1085 if (prototype() && ! prototype()->checkPrototype(proto, processed))
1086 return false;
1087
1088 return true;
1089 }
1090 #endif
1091 return false;
1092 }
1093
processMembers(MemberProcessor * processor) const1094 void ObjectValue::processMembers(MemberProcessor *processor) const
1095 {
1096 QHashIterator<QString, PropertyData> it(m_members);
1097
1098 while (it.hasNext()) {
1099 it.next();
1100
1101 if (! processor->processProperty(it.key(), it.value().value, it.value().propertyInfo))
1102 break;
1103 }
1104 }
1105
lookupMember(const QString & name,const Context * context,const ObjectValue ** foundInObject,bool examinePrototypes) const1106 const Value *ObjectValue::lookupMember(const QString &name, const Context *context,
1107 const ObjectValue **foundInObject,
1108 bool examinePrototypes) const
1109 {
1110 if (const Value *m = m_members.value(name).value) {
1111 if (foundInObject)
1112 *foundInObject = this;
1113 return m;
1114 } else {
1115 LookupMember slowLookup(name);
1116 processMembers(&slowLookup);
1117 if (slowLookup.value()) {
1118 if (foundInObject)
1119 *foundInObject = this;
1120 return slowLookup.value();
1121 }
1122 }
1123
1124 const ObjectValue *prototypeObject = 0;
1125
1126 if (examinePrototypes && context) {
1127 PrototypeIterator iter(this, context);
1128 iter.next(); // skip this
1129 while (iter.hasNext()) {
1130 prototypeObject = iter.next();
1131 if (const Value *m = prototypeObject->lookupMember(name, context, foundInObject, false))
1132 return m;
1133 }
1134 }
1135
1136 if (foundInObject)
1137 *foundInObject = 0;
1138
1139 return 0;
1140 }
1141
PrototypeIterator(const ObjectValue * start,const Context * context)1142 PrototypeIterator::PrototypeIterator(const ObjectValue *start, const Context *context)
1143 : m_current(0)
1144 , m_next(start)
1145 , m_context(context)
1146 , m_error(NoError)
1147 {
1148 if (start)
1149 m_prototypes.reserve(10);
1150 }
1151
PrototypeIterator(const ObjectValue * start,const ContextPtr & context)1152 PrototypeIterator::PrototypeIterator(const ObjectValue *start, const ContextPtr &context)
1153 : m_current(0)
1154 , m_next(start)
1155 , m_context(context.data())
1156 , m_error(NoError)
1157 {
1158 if (start)
1159 m_prototypes.reserve(10);
1160 }
1161
hasNext()1162 bool PrototypeIterator::hasNext()
1163 {
1164 if (m_next)
1165 return true;
1166 if (!m_current)
1167 return false;
1168 const Value *proto = m_current->prototype();
1169 if (!proto)
1170 return false;
1171
1172 m_next = value_cast<ObjectValue>(proto);
1173 if (! m_next)
1174 m_next = value_cast<ObjectValue>(m_context->lookupReference(proto));
1175 if (!m_next) {
1176 m_error = ReferenceResolutionError;
1177 return false;
1178 }
1179 if (m_prototypes.contains(m_next)) {
1180 m_error = CycleError;
1181 m_next = 0;
1182 return false;
1183 }
1184 return true;
1185 }
1186
next()1187 const ObjectValue *PrototypeIterator::next()
1188 {
1189 if (hasNext()) {
1190 m_current = m_next;
1191 m_prototypes += m_next;
1192 m_next = 0;
1193 return m_current;
1194 }
1195 return 0;
1196 }
1197
peekNext()1198 const ObjectValue *PrototypeIterator::peekNext()
1199 {
1200 if (hasNext())
1201 return m_next;
1202 return 0;
1203 }
1204
error() const1205 PrototypeIterator::Error PrototypeIterator::error() const
1206 {
1207 return m_error;
1208 }
1209
all()1210 QList<const ObjectValue *> PrototypeIterator::all()
1211 {
1212 while (hasNext())
1213 next();
1214 return m_prototypes;
1215 }
1216
FunctionValue(ValueOwner * valueOwner)1217 FunctionValue::FunctionValue(ValueOwner *valueOwner)
1218 : ObjectValue(valueOwner)
1219 {
1220 setClassName(QLatin1String("Function"));
1221 setMember(QLatin1String("length"), valueOwner->numberValue());
1222 setPrototype(valueOwner->functionPrototype());
1223 }
1224
~FunctionValue()1225 FunctionValue::~FunctionValue()
1226 {
1227 }
1228
returnValue() const1229 const Value *FunctionValue::returnValue() const
1230 {
1231 return valueOwner()->unknownValue();
1232 }
1233
namedArgumentCount() const1234 int FunctionValue::namedArgumentCount() const
1235 {
1236 return 0;
1237 }
1238
argument(int) const1239 const Value *FunctionValue::argument(int) const
1240 {
1241 return valueOwner()->unknownValue();
1242 }
1243
argumentName(int index) const1244 QString FunctionValue::argumentName(int index) const
1245 {
1246 return QString::fromLatin1("arg%1").arg(index + 1);
1247 }
1248
optionalNamedArgumentCount() const1249 int FunctionValue::optionalNamedArgumentCount() const
1250 {
1251 return 0;
1252 }
1253
isVariadic() const1254 bool FunctionValue::isVariadic() const
1255 {
1256 return true;
1257 }
1258
asFunctionValue() const1259 const FunctionValue *FunctionValue::asFunctionValue() const
1260 {
1261 return this;
1262 }
1263
accept(ValueVisitor * visitor) const1264 void FunctionValue::accept(ValueVisitor *visitor) const
1265 {
1266 visitor->visit(this);
1267 }
1268
Function(ValueOwner * valueOwner)1269 Function::Function(ValueOwner *valueOwner)
1270 : FunctionValue(valueOwner)
1271 , m_returnValue(0)
1272 , m_optionalNamedArgumentCount(0)
1273 , m_isVariadic(false)
1274 {
1275 }
1276
~Function()1277 Function::~Function()
1278 {
1279 }
1280
addArgument(const Value * argument,const QString & name)1281 void Function::addArgument(const Value *argument, const QString &name)
1282 {
1283 if (!name.isEmpty()) {
1284 while (m_argumentNames.size() < m_arguments.size())
1285 m_argumentNames.push_back(QString());
1286 m_argumentNames.push_back(name);
1287 }
1288 m_arguments.push_back(argument);
1289 }
1290
returnValue() const1291 const Value *Function::returnValue() const
1292 {
1293 return m_returnValue;
1294 }
1295
setReturnValue(const Value * returnValue)1296 void Function::setReturnValue(const Value *returnValue)
1297 {
1298 m_returnValue = returnValue;
1299 }
1300
setVariadic(bool variadic)1301 void Function::setVariadic(bool variadic)
1302 {
1303 m_isVariadic = variadic;
1304 }
1305
setOptionalNamedArgumentCount(int count)1306 void Function::setOptionalNamedArgumentCount(int count)
1307 {
1308 m_optionalNamedArgumentCount = count;
1309 }
1310
namedArgumentCount() const1311 int Function::namedArgumentCount() const
1312 {
1313 return m_arguments.size();
1314 }
1315
optionalNamedArgumentCount() const1316 int Function::optionalNamedArgumentCount() const
1317 {
1318 return m_optionalNamedArgumentCount;
1319 }
1320
argument(int index) const1321 const Value *Function::argument(int index) const
1322 {
1323 return m_arguments.at(index);
1324 }
1325
argumentName(int index) const1326 QString Function::argumentName(int index) const
1327 {
1328 if (index < m_argumentNames.size()) {
1329 const QString name = m_argumentNames.at(index);
1330 if (!name.isEmpty())
1331 return m_argumentNames.at(index);
1332 }
1333 return FunctionValue::argumentName(index);
1334 }
1335
isVariadic() const1336 bool Function::isVariadic() const
1337 {
1338 return m_isVariadic;
1339 }
1340
asFunction() const1341 const Function *Function::asFunction() const
1342 {
1343 return this;
1344 }
1345
1346 ////////////////////////////////////////////////////////////////////////////////
1347 // typing environment
1348 ////////////////////////////////////////////////////////////////////////////////
1349
1350 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::defaultLibraryObjects;
1351 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::defaultQtObjects;
1352
loadQmlTypes(const QFileInfoList & qmlTypeFiles,QStringList * errors,QStringList * warnings)1353 CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles, QStringList *errors, QStringList *warnings)
1354 {
1355 QHash<QString, FakeMetaObject::ConstPtr> newObjects;
1356 QStringList newDependencies;
1357
1358 foreach (const QFileInfo &qmlTypeFile, qmlTypeFiles) {
1359 QString error, warning;
1360 QFile file(qmlTypeFile.absoluteFilePath());
1361 if (file.open(QIODevice::ReadOnly)) {
1362 QByteArray contents = file.readAll();
1363 file.close();
1364
1365
1366 parseQmlTypeDescriptions(contents, &newObjects, 0, &newDependencies, &error, &warning,
1367 qmlTypeFile.absoluteFilePath());
1368 } else {
1369 error = file.errorString();
1370 }
1371 if (!error.isEmpty()) {
1372 errors->append(TypeDescriptionReader::tr(
1373 "Errors while loading qmltypes from %1:\n%2").arg(
1374 qmlTypeFile.absoluteFilePath(), error));
1375 }
1376 if (!warning.isEmpty()) {
1377 warnings->append(TypeDescriptionReader::tr(
1378 "Warnings while loading qmltypes from %1:\n%2").arg(
1379 qmlTypeFile.absoluteFilePath(), warning));
1380 }
1381 }
1382
1383 return newObjects;
1384 }
1385
parseQmlTypeDescriptions(const QByteArray & contents,BuiltinObjects * newObjects,QList<ModuleApiInfo> * newModuleApis,QStringList * newDependencies,QString * errorMessage,QString * warningMessage,const QString & fileName)1386 void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &contents,
1387 BuiltinObjects *newObjects,
1388 QList<ModuleApiInfo> *newModuleApis,
1389 QStringList *newDependencies,
1390 QString *errorMessage,
1391 QString *warningMessage, const QString &fileName)
1392 {
1393 if (contents.isEmpty())
1394 return;
1395 unsigned char c = contents.at(0);
1396 switch (c) {
1397 case 0xfe:
1398 case 0xef:
1399 case 0xff:
1400 case 0xee:
1401 case 0x00:
1402 qWarning() << fileName << "seems not to be encoded in UTF8 or has a BOM.";
1403 default: break;
1404 }
1405
1406 errorMessage->clear();
1407 warningMessage->clear();
1408 TypeDescriptionReader reader(fileName, QString::fromUtf8(contents));
1409 if (!reader(newObjects, newModuleApis, newDependencies)) {
1410 if (reader.errorMessage().isEmpty())
1411 *errorMessage = QLatin1String("unknown error");
1412 else
1413 *errorMessage = reader.errorMessage();
1414 }
1415 *warningMessage = reader.warningMessage();
1416 }
1417
CppQmlTypes(ValueOwner * valueOwner)1418 CppQmlTypes::CppQmlTypes(ValueOwner *valueOwner)
1419 : m_cppContextProperties(0)
1420 , m_valueOwner(valueOwner)
1421
1422 {
1423 }
1424
1425 const QLatin1String CppQmlTypes::defaultPackage("<default>");
1426 const QLatin1String CppQmlTypes::cppPackage("<cpp>");
1427
1428 template <typename T>
load(const QString & originId,const T & fakeMetaObjects,const QString & overridePackage)1429 void CppQmlTypes::load(const QString &originId, const T &fakeMetaObjects, const QString &overridePackage)
1430 {
1431 QList<CppComponentValue *> newCppTypes;
1432 foreach (const FakeMetaObject::ConstPtr &fmo, fakeMetaObjects) {
1433 foreach (const FakeMetaObject::Export &exp, fmo->exports()) {
1434 QString package = exp.package;
1435 if (package.isEmpty())
1436 package = overridePackage;
1437 m_fakeMetaObjectsByPackage[package].insert(FakeMetaObjectWithOrigin(fmo, originId));
1438
1439 // make versionless cpp types directly
1440 // needed for access to property types that are not exported, like QDeclarativeAnchors
1441 if (exp.package == cppPackage) {
1442 QTC_ASSERT(exp.version == ComponentVersion(), continue);
1443 QTC_ASSERT(exp.type == fmo->className(), continue);
1444 CppComponentValue *cppValue = new CppComponentValue(
1445 fmo, fmo->className(), cppPackage, ComponentVersion(), ComponentVersion(),
1446 ComponentVersion::MaxVersion, m_valueOwner, originId);
1447 m_objectsByQualifiedName[qualifiedName(cppPackage, fmo->className(), ComponentVersion())] = cppValue;
1448 newCppTypes += cppValue;
1449 }
1450 }
1451 }
1452
1453 // set prototypes of cpp types
1454 foreach (CppComponentValue *object, newCppTypes) {
1455 const QString &protoCppName = object->metaObject()->superclassName();
1456 const CppComponentValue *proto = objectByCppName(protoCppName);
1457 if (proto)
1458 object->setPrototype(proto);
1459 }
1460 }
1461
1462 // explicitly instantiate load for list and hash
1463 template QMLJS_EXPORT void CppQmlTypes::load< QList<FakeMetaObject::ConstPtr> >(const QString &, const QList<FakeMetaObject::ConstPtr> &, const QString &);
1464 template QMLJS_EXPORT void CppQmlTypes::load< QHash<QString, FakeMetaObject::ConstPtr> >(const QString &, const QHash<QString, FakeMetaObject::ConstPtr> &, const QString &);
1465
createObjectsForImport(const QString & package,ComponentVersion version)1466 QList<const CppComponentValue *> CppQmlTypes::createObjectsForImport(const QString &package, ComponentVersion version)
1467 {
1468 QHash<QString, const CppComponentValue *> exportedObjects;
1469
1470 QList<const CppComponentValue *> newObjects;
1471
1472 // make new exported objects
1473 foreach (const FakeMetaObjectWithOrigin &fmoo, m_fakeMetaObjectsByPackage.value(package)) {
1474 const FakeMetaObject::ConstPtr &fmo = fmoo.fakeMetaObject;
1475 // find the highest-version export for each alias
1476 QHash<QString, FakeMetaObject::Export> bestExports;
1477 foreach (const FakeMetaObject::Export &exp, fmo->exports()) {
1478 if (exp.package != package || (version.isValid() && exp.version > version))
1479 continue;
1480
1481 if (bestExports.contains(exp.type)) {
1482 if (exp.version > bestExports.value(exp.type).version)
1483 bestExports.insert(exp.type, exp);
1484 } else {
1485 bestExports.insert(exp.type, exp);
1486 }
1487 }
1488 if (bestExports.isEmpty())
1489 continue;
1490
1491 // if it already exists, skip
1492 const QString key = qualifiedName(package, fmo->className(), version);
1493 if (m_objectsByQualifiedName.contains(key))
1494 continue;
1495
1496 ComponentVersion cppVersion;
1497 foreach (const FakeMetaObject::Export &bestExport, bestExports) {
1498 QString name = bestExport.type;
1499 bool exported = true;
1500 if (name.isEmpty()) {
1501 exported = false;
1502 name = fmo->className();
1503 }
1504
1505 CppComponentValue *newComponent = new CppComponentValue(
1506 fmo, name, package, bestExport.version, version,
1507 bestExport.metaObjectRevision, m_valueOwner,
1508 fmoo.originId);
1509
1510 // use package.cppname importversion as key
1511 if (cppVersion <= bestExport.version) {
1512 cppVersion = bestExport.version;
1513 m_objectsByQualifiedName.insert(key, newComponent);
1514 }
1515 if (exported) {
1516 if (!exportedObjects.contains(name) // we might have the same type in different versions
1517 || (newComponent->componentVersion() > exportedObjects.value(name)->componentVersion()))
1518 exportedObjects.insert(name, newComponent);
1519 }
1520 newObjects += newComponent;
1521 }
1522 }
1523
1524 // set their prototypes, creating them if necessary
1525 // this ensures that the prototypes of C++ objects are resolved correctly and with the correct
1526 // revision, and cannot be hidden by other objects.
1527 foreach (const CppComponentValue *cobject, newObjects) {
1528 CppComponentValue *object = const_cast<CppComponentValue *>(cobject);
1529 while (!object->prototype()) {
1530 const QString &protoCppName = object->metaObject()->superclassName();
1531 if (protoCppName.isEmpty())
1532 break;
1533
1534 // if the prototype already exists, done
1535 const QString key = qualifiedName(object->moduleName(), protoCppName, version);
1536 if (const CppComponentValue *proto = m_objectsByQualifiedName.value(key)) {
1537 object->setPrototype(proto);
1538 break;
1539 }
1540
1541 // get the fmo via the cpp name
1542 const CppComponentValue *cppProto = objectByCppName(protoCppName);
1543 if (!cppProto)
1544 break;
1545 FakeMetaObject::ConstPtr protoFmo = cppProto->metaObject();
1546
1547 // make a new object
1548 CppComponentValue *proto = new CppComponentValue(
1549 protoFmo, protoCppName, object->moduleName(),
1550 ComponentVersion(),
1551 object->importVersion(), ComponentVersion::MaxVersion, m_valueOwner,
1552 cppProto->originId());
1553 m_objectsByQualifiedName.insert(key, proto);
1554 object->setPrototype(proto);
1555
1556 // maybe set prototype of prototype
1557 object = proto;
1558 }
1559 }
1560
1561 return exportedObjects.values();
1562 }
1563
hasModule(const QString & module) const1564 bool CppQmlTypes::hasModule(const QString &module) const
1565 {
1566 return m_fakeMetaObjectsByPackage.contains(module);
1567 }
1568
qualifiedName(const QString & module,const QString & type,ComponentVersion version)1569 QString CppQmlTypes::qualifiedName(const QString &module, const QString &type, ComponentVersion version)
1570 {
1571 return QString::fromLatin1("%1/%2 %3").arg(
1572 module, type,
1573 version.toString());
1574
1575 }
1576
objectByQualifiedName(const QString & name) const1577 const CppComponentValue *CppQmlTypes::objectByQualifiedName(const QString &name) const
1578 {
1579 return m_objectsByQualifiedName.value(name);
1580 }
1581
objectByQualifiedName(const QString & package,const QString & type,ComponentVersion version) const1582 const CppComponentValue *CppQmlTypes::objectByQualifiedName(const QString &package, const QString &type,
1583 ComponentVersion version) const
1584 {
1585 return objectByQualifiedName(qualifiedName(package, type, version));
1586 }
1587
objectByCppName(const QString & cppName) const1588 const CppComponentValue *CppQmlTypes::objectByCppName(const QString &cppName) const
1589 {
1590 return objectByQualifiedName(qualifiedName(cppPackage, cppName, ComponentVersion()));
1591 }
1592
setCppContextProperties(const ObjectValue * contextProperties)1593 void CppQmlTypes::setCppContextProperties(const ObjectValue *contextProperties)
1594 {
1595 m_cppContextProperties = contextProperties;
1596 }
1597
cppContextProperties() const1598 const ObjectValue *CppQmlTypes::cppContextProperties() const
1599 {
1600 return m_cppContextProperties;
1601 }
1602
1603
ConvertToNumber(ValueOwner * valueOwner)1604 ConvertToNumber::ConvertToNumber(ValueOwner *valueOwner)
1605 : m_valueOwner(valueOwner), m_result(0)
1606 {
1607 }
1608
operator ()(const Value * value)1609 const Value *ConvertToNumber::operator()(const Value *value)
1610 {
1611 const Value *previousValue = switchResult(0);
1612
1613 if (value)
1614 value->accept(this);
1615
1616 return switchResult(previousValue);
1617 }
1618
switchResult(const Value * value)1619 const Value *ConvertToNumber::switchResult(const Value *value)
1620 {
1621 const Value *previousResult = m_result;
1622 m_result = value;
1623 return previousResult;
1624 }
1625
visit(const NullValue *)1626 void ConvertToNumber::visit(const NullValue *)
1627 {
1628 m_result = m_valueOwner->numberValue();
1629 }
1630
visit(const UndefinedValue *)1631 void ConvertToNumber::visit(const UndefinedValue *)
1632 {
1633 m_result = m_valueOwner->numberValue();
1634 }
1635
visit(const NumberValue * value)1636 void ConvertToNumber::visit(const NumberValue *value)
1637 {
1638 m_result = value;
1639 }
1640
visit(const BooleanValue *)1641 void ConvertToNumber::visit(const BooleanValue *)
1642 {
1643 m_result = m_valueOwner->numberValue();
1644 }
1645
visit(const StringValue *)1646 void ConvertToNumber::visit(const StringValue *)
1647 {
1648 m_result = m_valueOwner->numberValue();
1649 }
1650
visit(const ObjectValue * object)1651 void ConvertToNumber::visit(const ObjectValue *object)
1652 {
1653 if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(
1654 object->lookupMember(QLatin1String("valueOf"), ContextPtr()))) {
1655 m_result = value_cast<NumberValue>(valueOfMember->returnValue());
1656 }
1657 }
1658
visit(const FunctionValue * object)1659 void ConvertToNumber::visit(const FunctionValue *object)
1660 {
1661 if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(
1662 object->lookupMember(QLatin1String("valueOf"), ContextPtr()))) {
1663 m_result = value_cast<NumberValue>(valueOfMember->returnValue());
1664 }
1665 }
1666
ConvertToString(ValueOwner * valueOwner)1667 ConvertToString::ConvertToString(ValueOwner *valueOwner)
1668 : m_valueOwner(valueOwner), m_result(0)
1669 {
1670 }
1671
operator ()(const Value * value)1672 const Value *ConvertToString::operator()(const Value *value)
1673 {
1674 const Value *previousValue = switchResult(0);
1675
1676 if (value)
1677 value->accept(this);
1678
1679 return switchResult(previousValue);
1680 }
1681
switchResult(const Value * value)1682 const Value *ConvertToString::switchResult(const Value *value)
1683 {
1684 const Value *previousResult = m_result;
1685 m_result = value;
1686 return previousResult;
1687 }
1688
visit(const NullValue *)1689 void ConvertToString::visit(const NullValue *)
1690 {
1691 m_result = m_valueOwner->stringValue();
1692 }
1693
visit(const UndefinedValue *)1694 void ConvertToString::visit(const UndefinedValue *)
1695 {
1696 m_result = m_valueOwner->stringValue();
1697 }
1698
visit(const NumberValue *)1699 void ConvertToString::visit(const NumberValue *)
1700 {
1701 m_result = m_valueOwner->stringValue();
1702 }
1703
visit(const BooleanValue *)1704 void ConvertToString::visit(const BooleanValue *)
1705 {
1706 m_result = m_valueOwner->stringValue();
1707 }
1708
visit(const StringValue * value)1709 void ConvertToString::visit(const StringValue *value)
1710 {
1711 m_result = value;
1712 }
1713
visit(const ObjectValue * object)1714 void ConvertToString::visit(const ObjectValue *object)
1715 {
1716 if (const FunctionValue *toStringMember = value_cast<FunctionValue>(
1717 object->lookupMember(QLatin1String("toString"), ContextPtr()))) {
1718 m_result = value_cast<StringValue>(toStringMember->returnValue());
1719 }
1720 }
1721
visit(const FunctionValue * object)1722 void ConvertToString::visit(const FunctionValue *object)
1723 {
1724 if (const FunctionValue *toStringMember = value_cast<FunctionValue>(
1725 object->lookupMember(QLatin1String("toString"), ContextPtr()))) {
1726 m_result = value_cast<StringValue>(toStringMember->returnValue());
1727 }
1728 }
1729
ConvertToObject(ValueOwner * valueOwner)1730 ConvertToObject::ConvertToObject(ValueOwner *valueOwner)
1731 : m_valueOwner(valueOwner), m_result(0)
1732 {
1733 }
1734
operator ()(const Value * value)1735 const Value *ConvertToObject::operator()(const Value *value)
1736 {
1737 const Value *previousValue = switchResult(0);
1738
1739 if (value)
1740 value->accept(this);
1741
1742 return switchResult(previousValue);
1743 }
1744
switchResult(const Value * value)1745 const Value *ConvertToObject::switchResult(const Value *value)
1746 {
1747 const Value *previousResult = m_result;
1748 m_result = value;
1749 return previousResult;
1750 }
1751
visit(const NullValue * value)1752 void ConvertToObject::visit(const NullValue *value)
1753 {
1754 m_result = value;
1755 }
1756
visit(const UndefinedValue *)1757 void ConvertToObject::visit(const UndefinedValue *)
1758 {
1759 m_result = m_valueOwner->nullValue();
1760 }
1761
visit(const NumberValue *)1762 void ConvertToObject::visit(const NumberValue *)
1763 {
1764 m_result = m_valueOwner->numberCtor()->returnValue();
1765 }
1766
visit(const BooleanValue *)1767 void ConvertToObject::visit(const BooleanValue *)
1768 {
1769 m_result = m_valueOwner->booleanCtor()->returnValue();
1770 }
1771
visit(const StringValue *)1772 void ConvertToObject::visit(const StringValue *)
1773 {
1774 m_result = m_valueOwner->stringCtor()->returnValue();
1775 }
1776
visit(const ObjectValue * object)1777 void ConvertToObject::visit(const ObjectValue *object)
1778 {
1779 m_result = object;
1780 }
1781
visit(const FunctionValue * object)1782 void ConvertToObject::visit(const FunctionValue *object)
1783 {
1784 m_result = object;
1785 }
1786
operator ()(const Value * value)1787 QString TypeId::operator()(const Value *value)
1788 {
1789 _result = QLatin1String("unknown");
1790
1791 if (value)
1792 value->accept(this);
1793
1794 return _result;
1795 }
1796
visit(const NullValue *)1797 void TypeId::visit(const NullValue *)
1798 {
1799 _result = QLatin1String("null");
1800 }
1801
visit(const UndefinedValue *)1802 void TypeId::visit(const UndefinedValue *)
1803 {
1804 _result = QLatin1String("undefined");
1805 }
1806
visit(const NumberValue *)1807 void TypeId::visit(const NumberValue *)
1808 {
1809 _result = QLatin1String("number");
1810 }
1811
visit(const BooleanValue *)1812 void TypeId::visit(const BooleanValue *)
1813 {
1814 _result = QLatin1String("boolean");
1815 }
1816
visit(const StringValue *)1817 void TypeId::visit(const StringValue *)
1818 {
1819 _result = QLatin1String("string");
1820 }
1821
visit(const ObjectValue * object)1822 void TypeId::visit(const ObjectValue *object)
1823 {
1824 _result = object->className();
1825
1826 if (_result.isEmpty())
1827 _result = QLatin1String("object");
1828 }
1829
visit(const FunctionValue * object)1830 void TypeId::visit(const FunctionValue *object)
1831 {
1832 _result = object->className();
1833
1834 if (_result.isEmpty())
1835 _result = QLatin1String("Function");
1836 }
1837
visit(const ColorValue *)1838 void TypeId::visit(const ColorValue *)
1839 {
1840 _result = QLatin1String("string");
1841 }
1842
visit(const AnchorLineValue *)1843 void TypeId::visit(const AnchorLineValue *)
1844 {
1845 _result = QLatin1String("AnchorLine");
1846 }
1847
ASTObjectValue(UiQualifiedId * typeName,UiObjectInitializer * initializer,const Document * doc,ValueOwner * valueOwner)1848 ASTObjectValue::ASTObjectValue(UiQualifiedId *typeName,
1849 UiObjectInitializer *initializer,
1850 const Document *doc,
1851 ValueOwner *valueOwner)
1852 : ObjectValue(valueOwner, doc->importId()),
1853 m_typeName(typeName), m_initializer(initializer), m_doc(doc), m_defaultPropertyRef(0)
1854 {
1855 if (m_initializer) {
1856 for (UiObjectMemberList *it = m_initializer->members; it; it = it->next) {
1857 UiObjectMember *member = it->member;
1858 if (UiPublicMember *def = cast<UiPublicMember *>(member)) {
1859 if (def->type == UiPublicMember::Property && !def->name.isEmpty() && def->isValid()) {
1860 ASTPropertyReference *ref = new ASTPropertyReference(def, m_doc, valueOwner);
1861 m_properties.append(ref);
1862 if (def->defaultToken.isValid())
1863 m_defaultPropertyRef = ref;
1864 } else if (def->type == UiPublicMember::Signal && !def->name.isEmpty()) {
1865 ASTSignal *ref = new ASTSignal(def, m_doc, valueOwner);
1866 m_signals.append(ref);
1867 }
1868 }
1869 }
1870 }
1871 }
1872
~ASTObjectValue()1873 ASTObjectValue::~ASTObjectValue()
1874 {
1875 }
1876
asAstObjectValue() const1877 const ASTObjectValue *ASTObjectValue::asAstObjectValue() const
1878 {
1879 return this;
1880 }
1881
getSourceLocation(QString * fileName,int * line,int * column) const1882 bool ASTObjectValue::getSourceLocation(QString *fileName, int *line, int *column) const
1883 {
1884 *fileName = m_doc->fileName();
1885 *line = m_typeName->identifierToken.startLine;
1886 *column = m_typeName->identifierToken.startColumn;
1887 return true;
1888 }
1889
processMembers(MemberProcessor * processor) const1890 void ASTObjectValue::processMembers(MemberProcessor *processor) const
1891 {
1892 foreach (ASTPropertyReference *ref, m_properties) {
1893 uint pFlags = PropertyInfo::Readable;
1894 if (!ref->ast()->isReadonlyMember)
1895 pFlags |= PropertyInfo::Writeable;
1896 processor->processProperty(ref->ast()->name.toString(), ref, PropertyInfo(pFlags));
1897 // ### Should get a different value?
1898 processor->processGeneratedSlot(ref->onChangedSlotName(), ref);
1899 }
1900 foreach (ASTSignal *ref, m_signals) {
1901 processor->processSignal(ref->ast()->name.toString(), ref);
1902 // ### Should get a different value?
1903 processor->processGeneratedSlot(ref->slotName(), ref);
1904 }
1905
1906 ObjectValue::processMembers(processor);
1907 }
1908
defaultPropertyName() const1909 QString ASTObjectValue::defaultPropertyName() const
1910 {
1911 if (m_defaultPropertyRef) {
1912 UiPublicMember *prop = m_defaultPropertyRef->ast();
1913 if (prop)
1914 return prop->name.toString();
1915 }
1916 return QString();
1917 }
1918
initializer() const1919 UiObjectInitializer *ASTObjectValue::initializer() const
1920 {
1921 return m_initializer;
1922 }
1923
typeName() const1924 UiQualifiedId *ASTObjectValue::typeName() const
1925 {
1926 return m_typeName;
1927 }
1928
document() const1929 const Document *ASTObjectValue::document() const
1930 {
1931 return m_doc;
1932 }
1933
ASTVariableReference(VariableDeclaration * ast,const Document * doc,ValueOwner * valueOwner)1934 ASTVariableReference::ASTVariableReference(VariableDeclaration *ast, const Document *doc, ValueOwner *valueOwner)
1935 : Reference(valueOwner)
1936 , m_ast(ast)
1937 , m_doc(doc)
1938 {
1939 }
1940
~ASTVariableReference()1941 ASTVariableReference::~ASTVariableReference()
1942 {
1943 }
1944
asAstVariableReference() const1945 const ASTVariableReference *ASTVariableReference::asAstVariableReference() const
1946 {
1947 return this;
1948 }
1949
ast() const1950 const VariableDeclaration *ASTVariableReference::ast() const
1951 {
1952 return m_ast;
1953 }
1954
value(ReferenceContext * referenceContext) const1955 const Value *ASTVariableReference::value(ReferenceContext *referenceContext) const
1956 {
1957 // may be assigned to later
1958 if (!m_ast->expression)
1959 return valueOwner()->unknownValue();
1960
1961 Document::Ptr doc = m_doc->ptr();
1962 ScopeChain scopeChain(doc, referenceContext->context());
1963 ScopeBuilder builder(&scopeChain);
1964 builder.push(ScopeAstPath(doc)(m_ast->expression->firstSourceLocation().begin()));
1965
1966 Evaluate evaluator(&scopeChain, referenceContext);
1967 return evaluator(m_ast->expression);
1968 }
1969
getSourceLocation(QString * fileName,int * line,int * column) const1970 bool ASTVariableReference::getSourceLocation(QString *fileName, int *line, int *column) const
1971 {
1972 *fileName = m_doc->fileName();
1973 *line = m_ast->identifierToken.startLine;
1974 *column = m_ast->identifierToken.startColumn;
1975 return true;
1976 }
1977
1978 namespace {
1979 class UsesArgumentsArray : protected Visitor
1980 {
1981 bool m_usesArgumentsArray;
1982
1983 public:
operator ()(FunctionBody * ast)1984 bool operator()(FunctionBody *ast)
1985 {
1986 if (!ast || !ast->elements)
1987 return false;
1988 m_usesArgumentsArray = false;
1989 Node::accept(ast->elements, this);
1990 return m_usesArgumentsArray;
1991 }
1992
1993 protected:
visit(ArrayMemberExpression * ast)1994 bool visit(ArrayMemberExpression *ast)
1995 {
1996 if (IdentifierExpression *idExp = cast<IdentifierExpression *>(ast->base)) {
1997 if (idExp->name == QLatin1String("arguments"))
1998 m_usesArgumentsArray = true;
1999 }
2000 return true;
2001 }
2002
2003 // don't go into nested functions
visit(FunctionBody *)2004 bool visit(FunctionBody *) { return false; }
2005 };
2006 } // anonymous namespace
2007
ASTFunctionValue(FunctionExpression * ast,const Document * doc,ValueOwner * valueOwner)2008 ASTFunctionValue::ASTFunctionValue(FunctionExpression *ast, const Document *doc, ValueOwner *valueOwner)
2009 : FunctionValue(valueOwner)
2010 , m_ast(ast)
2011 , m_doc(doc)
2012 {
2013 setPrototype(valueOwner->functionPrototype());
2014
2015 for (FormalParameterList *it = ast->formals; it; it = it->next)
2016 m_argumentNames.append(it->name.toString());
2017
2018 m_isVariadic = UsesArgumentsArray()(ast->body);
2019 }
2020
~ASTFunctionValue()2021 ASTFunctionValue::~ASTFunctionValue()
2022 {
2023 }
2024
ast() const2025 FunctionExpression *ASTFunctionValue::ast() const
2026 {
2027 return m_ast;
2028 }
2029
namedArgumentCount() const2030 int ASTFunctionValue::namedArgumentCount() const
2031 {
2032 return m_argumentNames.size();
2033 }
2034
argumentName(int index) const2035 QString ASTFunctionValue::argumentName(int index) const
2036 {
2037 if (index < m_argumentNames.size()) {
2038 const QString &name = m_argumentNames.at(index);
2039 if (!name.isEmpty())
2040 return name;
2041 }
2042
2043 return FunctionValue::argumentName(index);
2044 }
2045
isVariadic() const2046 bool ASTFunctionValue::isVariadic() const
2047 {
2048 return m_isVariadic;
2049 }
2050
asAstFunctionValue() const2051 const ASTFunctionValue *ASTFunctionValue::asAstFunctionValue() const
2052 {
2053 return this;
2054 }
2055
getSourceLocation(QString * fileName,int * line,int * column) const2056 bool ASTFunctionValue::getSourceLocation(QString *fileName, int *line, int *column) const
2057 {
2058 *fileName = m_doc->fileName();
2059 *line = m_ast->identifierToken.startLine;
2060 *column = m_ast->identifierToken.startColumn;
2061 return true;
2062 }
2063
QmlPrototypeReference(UiQualifiedId * qmlTypeName,const Document * doc,ValueOwner * valueOwner)2064 QmlPrototypeReference::QmlPrototypeReference(UiQualifiedId *qmlTypeName, const Document *doc,
2065 ValueOwner *valueOwner)
2066 : Reference(valueOwner),
2067 m_qmlTypeName(qmlTypeName),
2068 m_doc(doc)
2069 {
2070 }
2071
~QmlPrototypeReference()2072 QmlPrototypeReference::~QmlPrototypeReference()
2073 {
2074 }
2075
asQmlPrototypeReference() const2076 const QmlPrototypeReference *QmlPrototypeReference::asQmlPrototypeReference() const
2077 {
2078 return this;
2079 }
2080
qmlTypeName() const2081 UiQualifiedId *QmlPrototypeReference::qmlTypeName() const
2082 {
2083 return m_qmlTypeName;
2084 }
2085
document() const2086 const Document *QmlPrototypeReference::document() const
2087 {
2088 return m_doc;
2089 }
2090
value(ReferenceContext * referenceContext) const2091 const Value *QmlPrototypeReference::value(ReferenceContext *referenceContext) const
2092 {
2093 return referenceContext->context()->lookupType(m_doc, m_qmlTypeName);
2094 }
2095
ASTPropertyReference(UiPublicMember * ast,const Document * doc,ValueOwner * valueOwner)2096 ASTPropertyReference::ASTPropertyReference(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner)
2097 : Reference(valueOwner), m_ast(ast), m_doc(doc)
2098 {
2099 const QString &propertyName = ast->name.toString();
2100 m_onChangedSlotName = generatedSlotName(propertyName);
2101 m_onChangedSlotName += QLatin1String("Changed");
2102 }
2103
~ASTPropertyReference()2104 ASTPropertyReference::~ASTPropertyReference()
2105 {
2106 }
2107
asAstPropertyReference() const2108 const ASTPropertyReference *ASTPropertyReference::asAstPropertyReference() const
2109 {
2110 return this;
2111 }
2112
getSourceLocation(QString * fileName,int * line,int * column) const2113 bool ASTPropertyReference::getSourceLocation(QString *fileName, int *line, int *column) const
2114 {
2115 *fileName = m_doc->fileName();
2116 *line = m_ast->identifierToken.startLine;
2117 *column = m_ast->identifierToken.startColumn;
2118 return true;
2119 }
2120
value(ReferenceContext * referenceContext) const2121 const Value *ASTPropertyReference::value(ReferenceContext *referenceContext) const
2122 {
2123 if (m_ast->statement
2124 && (!m_ast->isValid()
2125 || m_ast->memberTypeName() == QLatin1String("variant")
2126 || m_ast->memberTypeName() == QLatin1String("var")
2127 || m_ast->memberTypeName() == QLatin1String("alias"))) {
2128
2129 // Adjust the context for the current location - expensive!
2130 // ### Improve efficiency by caching the 'use chain' constructed in ScopeBuilder.
2131
2132 Document::Ptr doc = m_doc->ptr();
2133 ScopeChain scopeChain(doc, referenceContext->context());
2134 ScopeBuilder builder(&scopeChain);
2135
2136 int offset = m_ast->statement->firstSourceLocation().begin();
2137 builder.push(ScopeAstPath(doc)(offset));
2138
2139 Evaluate evaluator(&scopeChain, referenceContext);
2140 return evaluator(m_ast->statement);
2141 }
2142
2143 const QString memberType = m_ast->memberTypeName().toString();
2144
2145 const Value *builtin = valueOwner()->defaultValueForBuiltinType(memberType);
2146 if (!builtin->asUndefinedValue())
2147 return builtin;
2148
2149 if (m_ast->typeModifier.isEmpty()) {
2150 const Value *type = referenceContext->context()->lookupType(m_doc, QStringList(memberType));
2151 if (type)
2152 return type;
2153 }
2154
2155 return referenceContext->context()->valueOwner()->undefinedValue();
2156 }
2157
ASTSignal(UiPublicMember * ast,const Document * doc,ValueOwner * valueOwner)2158 ASTSignal::ASTSignal(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner)
2159 : FunctionValue(valueOwner), m_ast(ast), m_doc(doc)
2160 {
2161 const QString &signalName = ast->name.toString();
2162 m_slotName = generatedSlotName(signalName);
2163
2164 ObjectValue *v = valueOwner->newObject(/*prototype=*/0);
2165 for (UiParameterList *it = ast->parameters; it; it = it->next) {
2166 if (!it->name.isEmpty())
2167 v->setMember(it->name.toString(), valueOwner->defaultValueForBuiltinType(it->type->name.toString()));
2168 }
2169 m_bodyScope = v;
2170 }
2171
~ASTSignal()2172 ASTSignal::~ASTSignal()
2173 {
2174 }
2175
asAstSignal() const2176 const ASTSignal *ASTSignal::asAstSignal() const
2177 {
2178 return this;
2179 }
2180
namedArgumentCount() const2181 int ASTSignal::namedArgumentCount() const
2182 {
2183 int count = 0;
2184 for (UiParameterList *it = m_ast->parameters; it; it = it->next)
2185 ++count;
2186 return count;
2187 }
2188
argument(int index) const2189 const Value *ASTSignal::argument(int index) const
2190 {
2191 UiParameterList *param = m_ast->parameters;
2192 for (int i = 0; param && i < index; ++i)
2193 param = param->next;
2194 if (!param || param->type->name.isEmpty())
2195 return valueOwner()->unknownValue();
2196 return valueOwner()->defaultValueForBuiltinType(param->type->name.toString());
2197 }
2198
argumentName(int index) const2199 QString ASTSignal::argumentName(int index) const
2200 {
2201 UiParameterList *param = m_ast->parameters;
2202 for (int i = 0; param && i < index; ++i)
2203 param = param->next;
2204 if (!param || param->name.isEmpty())
2205 return FunctionValue::argumentName(index);
2206 return param->name.toString();
2207 }
2208
getSourceLocation(QString * fileName,int * line,int * column) const2209 bool ASTSignal::getSourceLocation(QString *fileName, int *line, int *column) const
2210 {
2211 *fileName = m_doc->fileName();
2212 *line = m_ast->identifierToken.startLine;
2213 *column = m_ast->identifierToken.startColumn;
2214 return true;
2215 }
2216
2217
ImportInfo()2218 ImportInfo::ImportInfo()
2219 : m_type(ImportType::Invalid)
2220 , m_ast(0)
2221 {
2222 }
2223
moduleImport(QString uri,ComponentVersion version,const QString & as,UiImport * ast)2224 ImportInfo ImportInfo::moduleImport(QString uri, ComponentVersion version,
2225 const QString &as, UiImport *ast)
2226 {
2227 // treat Qt 4.7 as QtQuick 1.0
2228 if (uri == QLatin1String("Qt") && version == ComponentVersion(4, 7)) {
2229 uri = QLatin1String("QtQuick");
2230 version = ComponentVersion(1, 0);
2231 }
2232
2233 ImportInfo info;
2234 info.m_type = ImportType::Library;
2235 info.m_name = uri;
2236 info.m_path = uri;
2237 info.m_path.replace(QLatin1Char('.'), QLatin1Char('/'));
2238 info.m_version = version;
2239 info.m_as = as;
2240 info.m_ast = ast;
2241 return info;
2242 }
2243
pathImport(const QString & docPath,const QString & path,ComponentVersion version,const QString & as,UiImport * ast)2244 ImportInfo ImportInfo::pathImport(const QString &docPath, const QString &path,
2245 ComponentVersion version, const QString &as, UiImport *ast)
2246 {
2247 ImportInfo info;
2248 info.m_name = path;
2249
2250 QFileInfo importFileInfo(path);
2251 if (!importFileInfo.isAbsolute())
2252 importFileInfo = QFileInfo(docPath + QLatin1Char('/') + path);
2253 info.m_path = importFileInfo.absoluteFilePath();
2254
2255 if (importFileInfo.isFile()) {
2256 info.m_type = ImportType::File;
2257 } else if (importFileInfo.isDir()) {
2258 info.m_type = ImportType::Directory;
2259 } else if (path.startsWith(QLatin1String("qrc:"))) {
2260 ModelManagerInterface *model = ModelManagerInterface::instance();
2261 info.m_path = path;
2262 info.m_type = !model
2263 ? ImportType::UnknownFile
2264 : model->filesAtQrcPath(info.path()).isEmpty()
2265 ? ImportType::QrcDirectory
2266 : ImportType::QrcFile;
2267 } else {
2268 info.m_type = ImportType::UnknownFile;
2269 }
2270 info.m_version = version;
2271 info.m_as = as;
2272 info.m_ast = ast;
2273 return info;
2274 }
2275
invalidImport(UiImport * ast)2276 ImportInfo ImportInfo::invalidImport(UiImport *ast)
2277 {
2278 ImportInfo info;
2279 info.m_type = ImportType::Invalid;
2280 info.m_ast = ast;
2281 return info;
2282 }
2283
implicitDirectoryImport(const QString & directory)2284 ImportInfo ImportInfo::implicitDirectoryImport(const QString &directory)
2285 {
2286 ImportInfo info;
2287 info.m_type = ImportType::ImplicitDirectory;
2288 info.m_path = directory;
2289 return info;
2290 }
2291
qrcDirectoryImport(const QString & directory)2292 ImportInfo ImportInfo::qrcDirectoryImport(const QString &directory)
2293 {
2294 ImportInfo info;
2295 info.m_type = ImportType::QrcDirectory;
2296 info.m_path = directory;
2297 return info;
2298 }
2299
isValid() const2300 bool ImportInfo::isValid() const
2301 {
2302 return m_type != ImportType::Invalid;
2303 }
2304
type() const2305 ImportType::Enum ImportInfo::type() const
2306 {
2307 return m_type;
2308 }
2309
name() const2310 QString ImportInfo::name() const
2311 {
2312 return m_name;
2313 }
2314
path() const2315 QString ImportInfo::path() const
2316 {
2317 return m_path;
2318 }
2319
as() const2320 QString ImportInfo::as() const
2321 {
2322 return m_as;
2323 }
2324
version() const2325 ComponentVersion ImportInfo::version() const
2326 {
2327 return m_version;
2328 }
2329
ast() const2330 UiImport *ImportInfo::ast() const
2331 {
2332 return m_ast;
2333 }
2334
Import()2335 Import::Import()
2336 : object(0), valid(false), used(false)
2337 {}
2338
Import(const Import & other)2339 Import::Import(const Import &other)
2340 : object(other.object), info(other.info), libraryPath(other.libraryPath),
2341 valid(other.valid), used(false)
2342 { }
2343
TypeScope(const Imports * imports,ValueOwner * valueOwner)2344 TypeScope::TypeScope(const Imports *imports, ValueOwner *valueOwner)
2345 : ObjectValue(valueOwner)
2346 , m_imports(imports)
2347 {
2348 }
2349
lookupMember(const QString & name,const Context * context,const ObjectValue ** foundInObject,bool) const2350 const Value *TypeScope::lookupMember(const QString &name, const Context *context,
2351 const ObjectValue **foundInObject, bool) const
2352 {
2353 QListIterator<Import> it(m_imports->all());
2354 it.toBack();
2355 while (it.hasPrevious()) {
2356 const Import &i = it.previous();
2357 const ObjectValue *import = i.object;
2358 const ImportInfo &info = i.info;
2359
2360 // JS import has no types
2361 if (info.type() == ImportType::File || info.type() == ImportType::QrcFile)
2362 continue;
2363
2364 if (!info.as().isEmpty()) {
2365 if (info.as() == name) {
2366 if (foundInObject)
2367 *foundInObject = this;
2368 i.used = true;
2369 return import;
2370 }
2371 continue;
2372 }
2373
2374 if (const Value *v = import->lookupMember(name, context, foundInObject)) {
2375 i.used = true;
2376 return v;
2377 }
2378 }
2379 if (foundInObject)
2380 *foundInObject = 0;
2381 return 0;
2382 }
2383
processMembers(MemberProcessor * processor) const2384 void TypeScope::processMembers(MemberProcessor *processor) const
2385 {
2386 QListIterator<Import> it(m_imports->all());
2387 it.toBack();
2388 while (it.hasPrevious()) {
2389 const Import &i = it.previous();
2390 const ObjectValue *import = i.object;
2391 const ImportInfo &info = i.info;
2392
2393 // JS import has no types
2394 if (info.type() == ImportType::File || info.type() == ImportType::QrcFile)
2395 continue;
2396
2397 if (!info.as().isEmpty())
2398 processor->processProperty(info.as(), import, PropertyInfo(PropertyInfo::Readable));
2399 else
2400 import->processMembers(processor);
2401 }
2402 }
2403
asTypeScope() const2404 const TypeScope *TypeScope::asTypeScope() const
2405 {
2406 return this;
2407 }
2408
JSImportScope(const Imports * imports,ValueOwner * valueOwner)2409 JSImportScope::JSImportScope(const Imports *imports, ValueOwner *valueOwner)
2410 : ObjectValue(valueOwner)
2411 , m_imports(imports)
2412 {
2413 }
2414
lookupMember(const QString & name,const Context *,const ObjectValue ** foundInObject,bool) const2415 const Value *JSImportScope::lookupMember(const QString &name, const Context *,
2416 const ObjectValue **foundInObject, bool) const
2417 {
2418 QListIterator<Import> it(m_imports->all());
2419 it.toBack();
2420 while (it.hasPrevious()) {
2421 const Import &i = it.previous();
2422 const ObjectValue *import = i.object;
2423 const ImportInfo &info = i.info;
2424
2425 // JS imports are always: import "somefile.js" as Foo
2426 if (info.type() != ImportType::File && info.type() != ImportType::QrcFile)
2427 continue;
2428
2429 if (info.as() == name) {
2430 if (foundInObject)
2431 *foundInObject = this;
2432 i.used = true;
2433 return import;
2434 }
2435 }
2436 if (foundInObject)
2437 *foundInObject = 0;
2438 return 0;
2439 }
2440
processMembers(MemberProcessor * processor) const2441 void JSImportScope::processMembers(MemberProcessor *processor) const
2442 {
2443 QListIterator<Import> it(m_imports->all());
2444 it.toBack();
2445 while (it.hasPrevious()) {
2446 const Import &i = it.previous();
2447 const ObjectValue *import = i.object;
2448 const ImportInfo &info = i.info;
2449
2450 if (info.type() == ImportType::File || info.type() == ImportType::QrcFile)
2451 processor->processProperty(info.as(), import, PropertyInfo(PropertyInfo::Readable));
2452 }
2453 }
2454
asJSImportScope() const2455 const JSImportScope *JSImportScope::asJSImportScope() const
2456 {
2457 return this;
2458 }
2459
Imports(ValueOwner * valueOwner)2460 Imports::Imports(ValueOwner *valueOwner)
2461 : m_typeScope(new TypeScope(this, valueOwner))
2462 , m_jsImportScope(new JSImportScope(this, valueOwner))
2463 , m_importFailed(false)
2464 {}
2465
append(const Import & import)2466 void Imports::append(const Import &import)
2467 {
2468 // when doing lookup, imports with 'as' clause are looked at first
2469 if (!import.info.as().isEmpty()) {
2470 m_imports.append(import);
2471 } else {
2472 // find first as-import and prepend
2473 for (int i = 0; i < m_imports.size(); ++i) {
2474 if (!m_imports.at(i).info.as().isEmpty()) {
2475 m_imports.insert(i, import);
2476 return;
2477 }
2478 }
2479 // not found, append
2480 m_imports.append(import);
2481 }
2482
2483 if (!import.valid)
2484 m_importFailed = true;
2485 }
2486
setImportFailed()2487 void Imports::setImportFailed()
2488 {
2489 m_importFailed = true;
2490 }
2491
info(const QString & name,const Context * context) const2492 ImportInfo Imports::info(const QString &name, const Context *context) const
2493 {
2494 QString firstId = name;
2495 int dotIdx = firstId.indexOf(QLatin1Char('.'));
2496 if (dotIdx != -1)
2497 firstId = firstId.left(dotIdx);
2498
2499 QListIterator<Import> it(m_imports);
2500 it.toBack();
2501 while (it.hasPrevious()) {
2502 const Import &i = it.previous();
2503 const ObjectValue *import = i.object;
2504 const ImportInfo &info = i.info;
2505
2506 if (!info.as().isEmpty()) {
2507 if (info.as() == firstId)
2508 return info;
2509 continue;
2510 }
2511
2512 if (info.type() == ImportType::File || info.type() == ImportType::QrcFile) {
2513 if (import->className() == firstId)
2514 return info;
2515 } else {
2516 if (import->lookupMember(firstId, context))
2517 return info;
2518 }
2519 }
2520 return ImportInfo();
2521 }
2522
nameForImportedObject(const ObjectValue * value,const Context * context) const2523 QString Imports::nameForImportedObject(const ObjectValue *value, const Context *context) const
2524 {
2525 QListIterator<Import> it(m_imports);
2526 it.toBack();
2527 while (it.hasPrevious()) {
2528 const Import &i = it.previous();
2529 const ObjectValue *import = i.object;
2530 const ImportInfo &info = i.info;
2531
2532 if (info.type() == ImportType::File || info.type() == ImportType::QrcFile) {
2533 if (import == value)
2534 return import->className();
2535 } else {
2536 const Value *v = import->lookupMember(value->className(), context);
2537 if (v == value) {
2538 QString result = value->className();
2539 if (!info.as().isEmpty()) {
2540 result.prepend(QLatin1Char('.'));
2541 result.prepend(info.as());
2542 }
2543 return result;
2544 }
2545 }
2546 }
2547 return QString();
2548 }
2549
importFailed() const2550 bool Imports::importFailed() const
2551 {
2552 return m_importFailed;
2553 }
2554
all() const2555 const QList<Import> &Imports::all() const
2556 {
2557 return m_imports;
2558 }
2559
typeScope() const2560 const TypeScope *Imports::typeScope() const
2561 {
2562 return m_typeScope;
2563 }
2564
jsImportScope() const2565 const JSImportScope *Imports::jsImportScope() const
2566 {
2567 return m_jsImportScope;
2568 }
2569
2570 #ifdef QT_DEBUG
2571
2572 class MemberDumper: public MemberProcessor
2573 {
2574 public:
MemberDumper()2575 MemberDumper() {}
2576
processProperty(const QString & name,const Value *,const PropertyInfo & pInfo)2577 bool processProperty(const QString &name, const Value *, const PropertyInfo &pInfo) override
2578 {
2579 qCDebug(qmljsLog) << "property: " << name << " flags:" << pInfo.toString();
2580 return true;
2581 }
2582
processEnumerator(const QString & name,const Value *)2583 bool processEnumerator(const QString &name, const Value *) override
2584 {
2585 qCDebug(qmljsLog) << "enumerator: " << name;
2586 return true;
2587 }
2588
processSignal(const QString & name,const Value *)2589 bool processSignal(const QString &name, const Value *) override
2590 {
2591 qCDebug(qmljsLog) << "signal: " << name;
2592 return true;
2593 }
2594
processSlot(const QString & name,const Value *)2595 bool processSlot(const QString &name, const Value *) override
2596 {
2597 qCDebug(qmljsLog) << "slot: " << name;
2598 return true;
2599 }
2600
processGeneratedSlot(const QString & name,const Value *)2601 bool processGeneratedSlot(const QString &name, const Value *) override
2602 {
2603 qCDebug(qmljsLog) << "generated slot: " << name;
2604 return true;
2605 }
2606 };
2607
dump() const2608 void Imports::dump() const
2609 {
2610 qCDebug(qmljsLog) << "Imports contents, in search order:";
2611 QListIterator<Import> it(m_imports);
2612 it.toBack();
2613 while (it.hasPrevious()) {
2614 const Import &i = it.previous();
2615 const ObjectValue *import = i.object;
2616 const ImportInfo &info = i.info;
2617
2618 qCDebug(qmljsLog) << " " << info.path() << " " << info.version().toString() << " as " << info.as() << " : " << import;
2619 MemberDumper dumper;
2620 import->processMembers(&dumper);
2621 }
2622 }
2623
2624 #endif
2625