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 &parameterNames = method.parameterNames();
534             const QStringList &parameterTypes = 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