qmljsinterpreter.cpp 62.9 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
6
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
8
9
10
11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
28
29
30
31
**
**************************************************************************/

#include "qmljsinterpreter.h"
32
#include "qmljsevaluate.h"
33
#include "qmljslink.h"
34
#include "qmljsbind.h"
35
#include "qmljsscopebuilder.h"
36
#include "qmljsscopechain.h"
37
#include "qmljsscopeastpath.h"
38
#include "qmljstypedescriptionreader.h"
39
#include "qmljsvalueowner.h"
40
#include "qmljscontext.h"
41
#include "parser/qmljsast_p.h"
42

43
#include <languageutils/fakemetaobject.h>
44
#include <utils/qtcassert.h>
45

46
47
48
49
50
51
52
53
54
#include <QFile>
#include <QDir>
#include <QString>
#include <QStringList>
#include <QMetaObject>
#include <QMetaProperty>
#include <QXmlStreamReader>
#include <QProcess>
#include <QDebug>
55

56
57
#include <algorithm>

58
using namespace LanguageUtils;
59
using namespace QmlJS;
60
using namespace QmlJS::AST;
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*!
    \class QmlJS::Value
    \brief Abstract base class for the result of a JS expression.
    \sa Evaluate ValueOwner ValueVisitor

    A Value represents a category of JavaScript values, such as number
    (NumberValue), string (StringValue) or functions with a
    specific signature (FunctionValue). It can also represent internal
    categories such as "a QML component instantiation defined in a file"
    (ASTObjectValue), "a QML component defined in C++"
    (CppComponentValue) or "no specific information is available"
    (UnknownValue).

    The Value class itself provides accept() for admitting
    \l{ValueVisitor}s and a do-nothing getSourceLocation().

    Value instances should be cast to a derived type either through the
    asXXX() helper functions such as asNumberValue() or via the
    value_cast() template function.

    Values are the result of many operations in the QmlJS code model:
    \list
    \o \l{Evaluate}
    \o Context::lookupType() and Context::lookupReference()
    \o ScopeChain::lookup()
    \o ObjectValue::lookupMember()
    \endlist
*/

Roberto Raggi's avatar
Roberto Raggi committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
namespace {

class LookupMember: public MemberProcessor
{
    QString _name;
    const Value *_value;

    bool process(const QString &name, const Value *value)
    {
        if (_value)
            return false;

        if (name == _name) {
            _value = value;
            return false;
        }

        return true;
    }

public:
    LookupMember(const QString &name)
        : _name(name), _value(0) {}

    const Value *value() const { return _value; }

    virtual bool processProperty(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processEnumerator(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processSignal(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processSlot(const QString &name, const Value *value)
    {
        return process(name, value);
    }

    virtual bool processGeneratedSlot(const QString &name, const Value *value)
    {
        return process(name, value);
    }
};

143
144
class MetaFunction: public FunctionValue
{
145
    FakeMetaMethod _method;
146
147

public:
148
149
    MetaFunction(const FakeMetaMethod &method, ValueOwner *valueOwner)
        : FunctionValue(valueOwner), _method(method)
150
151
152
    {
    }

153
    virtual int namedArgumentCount() const
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    {
        return _method.parameterNames().size();
    }

    virtual QString argumentName(int index) const
    {
        if (index < _method.parameterNames().size())
            return _method.parameterNames().at(index);

        return FunctionValue::argumentName(index);
    }

    virtual bool isVariadic() const
    {
        return false;
    }
};

Roberto Raggi's avatar
Roberto Raggi committed
172
173
} // end of anonymous namespace

174
CppComponentValue::CppComponentValue(FakeMetaObject::ConstPtr metaObject, const QString &className,
175
                               const QString &packageName, const ComponentVersion &componentVersion,
176
177
                               const ComponentVersion &importVersion, int metaObjectRevision,
                               ValueOwner *valueOwner)
178
    : ObjectValue(valueOwner),
179
      _metaObject(metaObject),
180
181
      _moduleName(packageName),
      _componentVersion(componentVersion),
182
183
      _importVersion(importVersion),
      _metaObjectRevision(metaObjectRevision)
184
{
185
    setClassName(className);
186
187
188
    int nEnums = metaObject->enumeratorCount();
    for (int i = 0; i < nEnums; ++i) {
        FakeMetaEnum fEnum = metaObject->enumerator(i);
189
        _enums[fEnum.name()] = new QmlEnumValue(this, i);
190
    }
191
}
Roberto Raggi's avatar
Roberto Raggi committed
192

193
CppComponentValue::~CppComponentValue()
194
{
195
196
197
198
#if QT_VERSION >= 0x050000
    delete _metaSignatures.load();
    delete _signalScopes.load();
#else
199
200
    delete _metaSignatures;
    delete _signalScopes;
201
#endif
202
203
204
205
206
207
208
209
210
}

static QString generatedSlotName(const QString &base)
{
    QString slotName = QLatin1String("on");
    slotName += base.at(0).toUpper();
    slotName += base.midRef(1);
    return slotName;
}
Roberto Raggi's avatar
Roberto Raggi committed
211

Christian Kamm's avatar
Christian Kamm committed
212
213
214
215
216
const CppComponentValue *CppComponentValue::asCppComponentValue() const
{
    return this;
}

217
void CppComponentValue::processMembers(MemberProcessor *processor) const
218
{
Roberto Raggi's avatar
Roberto Raggi committed
219
    // process the meta enums
220
221
    for (int index = _metaObject->enumeratorOffset(); index < _metaObject->enumeratorCount(); ++index) {
        FakeMetaEnum e = _metaObject->enumerator(index);
222
223

        for (int i = 0; i < e.keyCount(); ++i) {
224
            processor->processEnumerator(e.key(i), valueOwner()->numberValue());
225
226
227
        }
    }

228
229
    // all explicitly defined signal names
    QSet<QString> explicitSignals;
230

231
    // make MetaFunction instances lazily when first needed
232
233
234
#if QT_VERSION >= 0x050000
    QList<const Value *> *signatures = _metaSignatures.load();
#else
235
    QList<const Value *> *signatures = _metaSignatures;
236
#endif
237
238
239
240
241
242
243
    if (!signatures) {
        signatures = new QList<const Value *>;
        signatures->reserve(_metaObject->methodCount());
        for (int index = 0; index < _metaObject->methodCount(); ++index)
            signatures->append(new MetaFunction(_metaObject->method(index), valueOwner()));
        if (!_metaSignatures.testAndSetOrdered(0, signatures)) {
            delete signatures;
244
245
246
#if QT_VERSION >= 0x050000
            signatures = _metaSignatures.load();
#else
247
            signatures = _metaSignatures;
248
#endif
249
250
251
        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
252
253
    // process the meta methods
    for (int index = 0; index < _metaObject->methodCount(); ++index) {
254
        const FakeMetaMethod method = _metaObject->method(index);
255
        if (_metaObjectRevision < method.revision())
256
257
            continue;

Christian Kamm's avatar
Christian Kamm committed
258
        const QString &methodName = _metaObject->method(index).methodName();
259
        const Value *signature = signatures->at(index);
260

261
        if (method.methodType() == FakeMetaMethod::Slot && method.access() == FakeMetaMethod::Public) {
Roberto Raggi's avatar
Roberto Raggi committed
262
            processor->processSlot(methodName, signature);
263

264
        } else if (method.methodType() == FakeMetaMethod::Signal && method.access() != FakeMetaMethod::Private) {
265
            // process the signal
Roberto Raggi's avatar
Roberto Raggi committed
266
            processor->processSignal(methodName, signature);
267
            explicitSignals.insert(methodName);
268

269
            // process the generated slot
270
            const QString &slotName = generatedSlotName(methodName);
Roberto Raggi's avatar
Roberto Raggi committed
271
            processor->processGeneratedSlot(slotName, signature);
272
        }
Roberto Raggi's avatar
Roberto Raggi committed
273
274
    }

275
276
    // process the meta properties
    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
277
        const FakeMetaProperty prop = _metaObject->property(index);
278
        if (_metaObjectRevision < prop.revision())
279
            continue;
280
281

        const QString propertyName = prop.name();
282
        processor->processProperty(propertyName, valueForCppName(prop.typeName()));
283
284
285
286
287
288
289

        // every property always has a onXyzChanged slot, even if the NOTIFY
        // signal has a different name
        QString signalName = propertyName;
        signalName += QLatin1String("Changed");
        if (!explicitSignals.contains(signalName)) {
            // process the generated slot
290
            const QString &slotName = generatedSlotName(signalName);
291
            processor->processGeneratedSlot(slotName, valueOwner()->unknownValue());
292
293
294
        }
    }

295
296
297
    // look into attached types
    const QString &attachedTypeName = _metaObject->attachedTypeName();
    if (!attachedTypeName.isEmpty()) {
298
        const CppComponentValue *attachedType = valueOwner()->cppQmlTypes().objectByCppName(attachedTypeName);
299
        if (attachedType && attachedType != this) // ### only weak protection against infinite loops
300
301
            attachedType->processMembers(processor);
    }
302

303
304
305
    ObjectValue::processMembers(processor);
}

306
const Value *CppComponentValue::valueForCppName(const QString &typeName) const
307
{
308
    const CppQmlTypes &cppTypes = valueOwner()->cppQmlTypes();
Roberto Raggi's avatar
Roberto Raggi committed
309

310
    // check in the same package/version first
311
    const CppComponentValue *objectValue = cppTypes.objectByQualifiedName(
312
313
314
315
316
317
318
                _moduleName, typeName, _importVersion);
    if (objectValue)
        return objectValue;

    // fallback to plain cpp name
    objectValue = cppTypes.objectByCppName(typeName);
    if (objectValue)
319
        return objectValue;
Roberto Raggi's avatar
Roberto Raggi committed
320

321
322
323
324
325
326
327
    // try qml builtin type names
    if (const Value *v = valueOwner()->defaultValueForBuiltinType(typeName)) {
        if (!v->asUndefinedValue())
            return v;
    }

    // map other C++ types
328
    if (typeName == QLatin1String("QByteArray")
Christian Kamm's avatar
Christian Kamm committed
329
            || typeName == QLatin1String("QString")) {
Christian Kamm's avatar
Christian Kamm committed
330
        return valueOwner()->stringValue();
Christian Kamm's avatar
Christian Kamm committed
331
    } else if (typeName == QLatin1String("QUrl")) {
Christian Kamm's avatar
Christian Kamm committed
332
        return valueOwner()->urlValue();
333
    } else if (typeName == QLatin1String("long")) {
Christian Kamm's avatar
Christian Kamm committed
334
        return valueOwner()->intValue();
335
336
    }  else if (typeName == QLatin1String("float")
                || typeName == QLatin1String("qreal")) {
Christian Kamm's avatar
Christian Kamm committed
337
        return valueOwner()->realValue();
338
    } else if (typeName == QLatin1String("QFont")) {
Christian Kamm's avatar
Christian Kamm committed
339
        return valueOwner()->qmlFontObject();
340
341
342
    } else if (typeName == QLatin1String("QPoint")
            || typeName == QLatin1String("QPointF")
            || typeName == QLatin1String("QVector2D")) {
Christian Kamm's avatar
Christian Kamm committed
343
        return valueOwner()->qmlPointObject();
344
345
    } else if (typeName == QLatin1String("QSize")
            || typeName == QLatin1String("QSizeF")) {
Christian Kamm's avatar
Christian Kamm committed
346
        return valueOwner()->qmlSizeObject();
347
348
    } else if (typeName == QLatin1String("QRect")
            || typeName == QLatin1String("QRectF")) {
Christian Kamm's avatar
Christian Kamm committed
349
        return valueOwner()->qmlRectObject();
350
    } else if (typeName == QLatin1String("QVector3D")) {
Christian Kamm's avatar
Christian Kamm committed
351
        return valueOwner()->qmlVector3DObject();
352
    } else if (typeName == QLatin1String("QColor")) {
Christian Kamm's avatar
Christian Kamm committed
353
        return valueOwner()->colorValue();
354
    } else if (typeName == QLatin1String("QDeclarativeAnchorLine")) {
Christian Kamm's avatar
Christian Kamm committed
355
        return valueOwner()->anchorLineValue();
356
357
    }

Christian Kamm's avatar
Christian Kamm committed
358
    // might be an enum
359
    const CppComponentValue *base = this;
360
361
    const QStringList components = typeName.split(QLatin1String("::"));
    if (components.size() == 2) {
362
        base = valueOwner()->cppQmlTypes().objectByCppName(components.first());
363
364
    }
    if (base) {
365
        if (const QmlEnumValue *value = base->getEnumValue(components.last()))
Christian Kamm's avatar
Christian Kamm committed
366
            return value;
Christian Kamm's avatar
Christian Kamm committed
367
368
    }

369
370
    // may still be a cpp based value
    return valueOwner()->unknownValue();
371
}
372

373
const CppComponentValue *CppComponentValue::prototype() const
374
{
Christian Kamm's avatar
Christian Kamm committed
375
    Q_ASSERT(!_prototype || value_cast<CppComponentValue>(_prototype));
376
    return static_cast<const CppComponentValue *>(_prototype);
377
378
}

379
380
381
382
383
/*!
  \returns a list started by this object and followed by all its prototypes

  Prefer to use this over calling prototype() in a loop, as it avoids cycles.
*/
384
QList<const CppComponentValue *> CppComponentValue::prototypes() const
385
{
386
387
    QList<const CppComponentValue *> protos;
    for (const CppComponentValue *it = this; it; it = it->prototype()) {
388
389
390
391
392
393
394
        if (protos.contains(it))
            break;
        protos += it;
    }
    return protos;
}

395
FakeMetaObject::ConstPtr CppComponentValue::metaObject() const
396
{
397
    return _metaObject;
398
399
}

400
QString CppComponentValue::moduleName() const
401
{ return _moduleName; }
402

403
ComponentVersion CppComponentValue::componentVersion() const
404
{ return _componentVersion; }
405

406
ComponentVersion CppComponentValue::importVersion() const
407
408
{ return _importVersion; }

409
QString CppComponentValue::defaultPropertyName() const
410
411
{ return _metaObject->defaultPropertyName(); }

412
QString CppComponentValue::propertyType(const QString &propertyName) const
413
{
414
    foreach (const CppComponentValue *it, prototypes()) {
415
        FakeMetaObject::ConstPtr iter = it->_metaObject;
416
        int propIdx = iter->propertyIndex(propertyName);
417
        if (propIdx != -1) {
418
            return iter->property(propIdx).typeName();
419
420
421
422
423
        }
    }
    return QString();
}

424
bool CppComponentValue::isListProperty(const QString &propertyName) const
425
{
426
    foreach (const CppComponentValue *it, prototypes()) {
427
        FakeMetaObject::ConstPtr iter = it->_metaObject;
428
429
430
431
432
433
        int propIdx = iter->propertyIndex(propertyName);
        if (propIdx != -1) {
            return iter->property(propIdx).isList();
        }
    }
    return false;
434
435
}

436
FakeMetaEnum CppComponentValue::getEnum(const QString &typeName, const CppComponentValue **foundInScope) const
437
{
438
    foreach (const CppComponentValue *it, prototypes()) {
Christian Kamm's avatar
Christian Kamm committed
439
440
441
442
443
444
445
446
447
448
449
        FakeMetaObject::ConstPtr iter = it->_metaObject;
        const int index = iter->enumeratorIndex(typeName);
        if (index != -1) {
            if (foundInScope)
                *foundInScope = it;
            return iter->enumerator(index);
        }
    }
    if (foundInScope)
        *foundInScope = 0;
    return FakeMetaEnum();
450
451
}

452
const QmlEnumValue *CppComponentValue::getEnumValue(const QString &typeName, const CppComponentValue **foundInScope) const
453
{
454
    foreach (const CppComponentValue *it, prototypes()) {
Christian Kamm's avatar
Christian Kamm committed
455
456
457
458
459
460
461
462
463
        if (const QmlEnumValue *e = it->_enums.value(typeName)) {
            if (foundInScope)
                *foundInScope = it;
            return e;
        }
    }
    if (foundInScope)
        *foundInScope = 0;
    return 0;
464
465
}

466
const ObjectValue *CppComponentValue::signalScope(const QString &signalName) const
467
{
468
469
470
#if QT_VERSION >= 0x050000
    QHash<QString, const ObjectValue *> *scopes = _signalScopes.load();
#else
471
    QHash<QString, const ObjectValue *> *scopes = _signalScopes;
472
#endif
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
    if (!scopes) {
        scopes = new QHash<QString, const ObjectValue *>;
        // usually not all methods are signals
        scopes->reserve(_metaObject->methodCount() / 2);
        for (int index = 0; index < _metaObject->methodCount(); ++index) {
            const FakeMetaMethod &method = _metaObject->method(index);
            if (method.methodType() != FakeMetaMethod::Signal || method.access() == FakeMetaMethod::Private)
                continue;

            const QStringList &parameterNames = method.parameterNames();
            const QStringList &parameterTypes = method.parameterTypes();
            QTC_ASSERT(parameterNames.size() == parameterTypes.size(), continue);

            ObjectValue *scope = valueOwner()->newObject(/*prototype=*/0);
            for (int i = 0; i < parameterNames.size(); ++i) {
                const QString &name = parameterNames.at(i);
                const QString &type = parameterTypes.at(i);
                if (name.isEmpty())
                    continue;
                scope->setMember(name, valueForCppName(type));
            }
            scopes->insert(generatedSlotName(method.methodName()), scope);
        }
        if (!_signalScopes.testAndSetOrdered(0, scopes)) {
497
            delete scopes;
498
499
500
#if QT_VERSION >= 0x050000
            scopes = _signalScopes.load();
#else
501
            scopes = _signalScopes;
502
#endif
503
504
505
506
507
508
        }
    }

    return scopes->value(signalName);
}

509
bool CppComponentValue::isWritable(const QString &propertyName) const
510
{
511
    foreach (const CppComponentValue *it, prototypes()) {
512
        FakeMetaObject::ConstPtr iter = it->_metaObject;
513
514
515
516
517
518
519
520
        int propIdx = iter->propertyIndex(propertyName);
        if (propIdx != -1) {
            return iter->property(propIdx).isWritable();
        }
    }
    return false;
}

521
bool CppComponentValue::isPointer(const QString &propertyName) const
522
{
523
    foreach (const CppComponentValue *it, prototypes()) {
524
        FakeMetaObject::ConstPtr iter = it->_metaObject;
525
526
527
528
529
530
531
532
        int propIdx = iter->propertyIndex(propertyName);
        if (propIdx != -1) {
            return iter->property(propIdx).isPointer();
        }
    }
    return false;
}

533
bool CppComponentValue::hasLocalProperty(const QString &typeName) const
534
535
536
537
538
539
540
{
    int idx = _metaObject->propertyIndex(typeName);
    if (idx == -1)
        return false;
    return true;
}

541
bool CppComponentValue::hasProperty(const QString &propertyName) const
542
{
543
    foreach (const CppComponentValue *it, prototypes()) {
544
        FakeMetaObject::ConstPtr iter = it->_metaObject;
545
546
547
548
549
550
551
552
        int propIdx = iter->propertyIndex(propertyName);
        if (propIdx != -1) {
            return true;
        }
    }
    return false;
}

553
bool CppComponentValue::isDerivedFrom(FakeMetaObject::ConstPtr base) const
554
{
555
    foreach (const CppComponentValue *it, prototypes()) {
556
        FakeMetaObject::ConstPtr iter = it->_metaObject;
557
558
559
560
561
562
        if (iter == base)
            return true;
    }
    return false;
}

563
QmlEnumValue::QmlEnumValue(const CppComponentValue *owner, int enumIndex)
564
565
    : _owner(owner)
    , _enumIndex(enumIndex)
Christian Kamm's avatar
Christian Kamm committed
566
{
567
    owner->valueOwner()->registerValue(this);
Christian Kamm's avatar
Christian Kamm committed
568
569
570
571
572
573
}

QmlEnumValue::~QmlEnumValue()
{
}

Christian Kamm's avatar
Christian Kamm committed
574
575
576
577
578
const QmlEnumValue *QmlEnumValue::asQmlEnumValue() const
{
    return this;
}

Christian Kamm's avatar
Christian Kamm committed
579
580
QString QmlEnumValue::name() const
{
581
    return _owner->metaObject()->enumerator(_enumIndex).name();
Christian Kamm's avatar
Christian Kamm committed
582
583
584
585
}

QStringList QmlEnumValue::keys() const
{
586
587
588
    return _owner->metaObject()->enumerator(_enumIndex).keys();
}

589
const CppComponentValue *QmlEnumValue::owner() const
590
591
{
    return _owner;
Christian Kamm's avatar
Christian Kamm committed
592
593
}

594
595
596
////////////////////////////////////////////////////////////////////////////////
// ValueVisitor
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
ValueVisitor::ValueVisitor()
{
}

ValueVisitor::~ValueVisitor()
{
}

void ValueVisitor::visit(const NullValue *)
{
}

void ValueVisitor::visit(const UndefinedValue *)
{
}

613
614
615
616
void ValueVisitor::visit(const UnknownValue *)
{
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
void ValueVisitor::visit(const NumberValue *)
{
}

void ValueVisitor::visit(const BooleanValue *)
{
}

void ValueVisitor::visit(const StringValue *)
{
}

void ValueVisitor::visit(const ObjectValue *)
{
}

void ValueVisitor::visit(const FunctionValue *)
{
}
636

Roberto Raggi's avatar
Roberto Raggi committed
637
638
639
void ValueVisitor::visit(const Reference *)
{
}
640

641
642
643
644
void ValueVisitor::visit(const ColorValue *)
{
}

645
646
647
648
void ValueVisitor::visit(const AnchorLineValue *)
{
}

649
650
651
////////////////////////////////////////////////////////////////////////////////
// Value
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
652
653
654
655
656
657
658
659
Value::Value()
{
}

Value::~Value()
{
}

660
661
662
663
664
bool Value::getSourceLocation(QString *, int *, int *) const
{
    return false;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
665
666
667
668
669
670
671
672
673
674
const NullValue *Value::asNullValue() const
{
    return 0;
}

const UndefinedValue *Value::asUndefinedValue() const
{
    return 0;
}

675
676
677
678
679
const UnknownValue *Value::asUnknownValue() const
{
    return 0;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
680
681
682
683
684
const NumberValue *Value::asNumberValue() const
{
    return 0;
}

685
686
687
688
689
690
691
692
693
694
const IntValue *Value::asIntValue() const
{
    return 0;
}

const RealValue *Value::asRealValue() const
{
    return 0;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
695
696
697
698
699
700
701
702
703
704
const BooleanValue *Value::asBooleanValue() const
{
    return 0;
}

const StringValue *Value::asStringValue() const
{
    return 0;
}

Christian Kamm's avatar
Christian Kamm committed
705
706
707
708
709
const UrlValue *Value::asUrlValue() const
{
    return 0;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
710
711
712
713
714
715
716
717
718
const ObjectValue *Value::asObjectValue() const
{
    return 0;
}

const FunctionValue *Value::asFunctionValue() const
{
    return 0;
}
719

Roberto Raggi's avatar
Roberto Raggi committed
720
721
722
723
724
const Reference *Value::asReference() const
{
    return 0;
}

725
726
727
728
729
const ColorValue *Value::asColorValue() const
{
    return 0;
}

730
731
732
733
734
const AnchorLineValue *Value::asAnchorLineValue() const
{
    return 0;
}

Christian Kamm's avatar
Christian Kamm committed
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
const CppComponentValue *Value::asCppComponentValue() const
{
    return 0;
}

const ASTObjectValue *Value::asAstObjectValue() const
{
    return 0;
}

const QmlEnumValue *Value::asQmlEnumValue() const
{
    return 0;
}

const QmlPrototypeReference *Value::asQmlPrototypeReference() const
{
    return 0;
}

const ASTPropertyReference *Value::asAstPropertyReference() const
{
    return 0;
}

760
761
762
763
764
const ASTSignal *Value::asAstSignal() const
{
    return 0;
}

765
766
767
////////////////////////////////////////////////////////////////////////////////
// Values
////////////////////////////////////////////////////////////////////////////////
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
const NullValue *NullValue::asNullValue() const
{
    return this;
}

void NullValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const UndefinedValue *UndefinedValue::asUndefinedValue() const
{
    return this;
}

783
void UnknownValue::accept(ValueVisitor *visitor) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
784
785
786
{
    visitor->visit(this);
}
787

788
789
790
791
792
793
794
795
796
const UnknownValue *UnknownValue::asUnknownValue() const
{
    return this;
}

void UndefinedValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
797
798
799
800
801
const NumberValue *NumberValue::asNumberValue() const
{
    return this;
}

802
803
804
805
806
807
808
809
810
811
const RealValue *RealValue::asRealValue() const
{
    return this;
}

const IntValue *IntValue::asIntValue() const
{
    return this;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
void NumberValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const BooleanValue *BooleanValue::asBooleanValue() const
{
    return this;
}

void BooleanValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const StringValue *StringValue::asStringValue() const
{
    return this;
}

Christian Kamm's avatar
Christian Kamm committed
832
833
834
835
836
const UrlValue *UrlValue::asUrlValue() const
{
    return this;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
837
838
839
840
841
void StringValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

842
843
Reference::Reference(ValueOwner *valueOwner)
    : _valueOwner(valueOwner)
Roberto Raggi's avatar
Roberto Raggi committed
844
{
845
    _valueOwner->registerValue(this);
Roberto Raggi's avatar
Roberto Raggi committed
846
847
848
849
850
851
}

Reference::~Reference()
{
}

852
ValueOwner *Reference::valueOwner() const
853
{
854
    return _valueOwner;
855
856
}

Roberto Raggi's avatar
Roberto Raggi committed
857
858
859
860
861
862
863
864
865
866
const Reference *Reference::asReference() const
{
    return this;
}

void Reference::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

867
const Value *Reference::value(ReferenceContext *) const
868
{
869
    return _valueOwner->undefinedValue();
870
}
Roberto Raggi's avatar
Roberto Raggi committed
871

872
873
874
875
876
877
878
879
880
881
void ColorValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const ColorValue *ColorValue::asColorValue() const
{
    return this;
}

882
883
884
885
886
887
888
889
890
891
void AnchorLineValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const
{
    return this;
}

892
893
894
895
896
897
898
899
900
901
902
903
904
MemberProcessor::MemberProcessor()
{
}

MemberProcessor::~MemberProcessor()
{
}

bool MemberProcessor::processProperty(const QString &, const Value *)
{
    return true;
}

905
906
907
908
909
bool MemberProcessor::processEnumerator(const QString &, const Value *)
{
    return true;
}

910
911
912
913
914
915
916
917
918
919
bool MemberProcessor::processSignal(const QString &, const Value *)
{
    return true;
}

bool MemberProcessor::processSlot(const QString &, const Value *)
{
    return true;
}

920
921
922
923
924
bool MemberProcessor::processGeneratedSlot(const QString &, const Value *)
{
    return true;
}

925
926
ObjectValue::ObjectValue(ValueOwner *valueOwner)
    : _valueOwner(valueOwner),
927
      _prototype(0)
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
928
{
929
    valueOwner->registerValue(this);
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
930
931
932
933
934
935
}

ObjectValue::~ObjectValue()
{
}

936
ValueOwner *ObjectValue::valueOwner() const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
937
{
938
    return _valueOwner;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
939
940
941
942
943
944
945
946
947
948
949
950
}

QString ObjectValue::className() const
{
    return _className;
}

void ObjectValue::setClassName(const QString &className)
{
    _className = className;
}

951
952
953
954
955
const Value *ObjectValue::prototype() const
{
    return _prototype;
}

956
const ObjectValue *ObjectValue::prototype(const Context *context) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
957
{
Christian Kamm's avatar
Christian Kamm committed
958
    const ObjectValue *prototypeObject = value_cast<ObjectValue>(_prototype);
959
    if (! prototypeObject) {
Christian Kamm's avatar
Christian Kamm committed
960
961
        if (const Reference *prototypeReference = value_cast<Reference>(_prototype)) {
            prototypeObject = value_cast<ObjectValue>(context->lookupReference(prototypeReference));
962
963
964
965
966
967
968
969
        }
    }
    return prototypeObject;
}

void ObjectValue::setPrototype(const Value *prototype)
{
    _prototype = prototype;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
970
971
}

972
void ObjectValue::setMember(const QString &name, const Value *value)
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
973
974
975
976
{
    _members[name] = value;
}

977
void ObjectValue::removeMember(const QString &name)
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
978
979
980
981
982
983
984
985
986
987
988
989
990
991
{
    _members.remove(name);
}

const ObjectValue *ObjectValue::asObjectValue() const
{
    return this;
}

void ObjectValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

992
bool ObjectValue::checkPrototype(const ObjectValue *, QSet<const ObjectValue *> *) const
993
{
994
#if 0
995
996
997
998
999
1000
1001
    const int previousSize = processed->size();
    processed->insert(this);

    if (previousSize != processed->size()) {
        if (this == proto)
            return false;

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1002
        if (prototype() && ! prototype()->checkPrototype(proto, processed))
1003
1004
1005
1006
            return false;

        return true;
    }
1007
#endif
1008
1009
1010
    return false;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1011
1012
1013
1014
1015
1016
1017
void ObjectValue::processMembers(MemberProcessor *processor) const
{
    QHashIterator<QString, const Value *> it(_members);

    while (it.hasNext()) {
        it.next();

1018
        if (! processor->processProperty(it.key(), it.value()))
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1019
1020
1021
1022
            break;
    }
}

1023
1024
1025
const Value *ObjectValue::lookupMember(const QString &name, const Context *context,
                                       const ObjectValue **foundInObject,
                                       bool examinePrototypes) const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1026
{
1027
1028
1029
    if (const Value *m = _members.value(name)) {
        if (foundInObject)
            *foundInObject = this;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1030
        return m;
1031
    } else {
Roberto Raggi's avatar
Roberto Raggi committed
1032
1033
        LookupMember slowLookup(name);
        processMembers(&slowLookup);
1034
1035
1036
        if (slowLookup.value()) {
            if (foundInObject)
                *foundInObject = this;
Roberto Raggi's avatar
Roberto Raggi committed
1037
            return slowLookup.value();
1038
        }
Roberto Raggi's avatar
Roberto Raggi committed
1039
    }
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1040

Christian Kamm's avatar
Christian Kamm committed
1041
    if (examinePrototypes && context) {
1042
1043
1044
1045
        PrototypeIterator iter(this, context);
        iter.next(); // skip this
        while (iter.hasNext()) {
            const ObjectValue *prototypeObject = iter.next();
1046
            if (const Value *m = prototypeObject->lookupMember(name, context, foundInObject, false))
1047
1048
                return m;
        }
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1049
1050
    }

1051
1052
    if (foundInObject)
        *foundInObject = 0;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1053
1054
1055
    return 0;
}

1056
1057
1058
1059
PrototypeIterator::PrototypeIterator(const ObjectValue *start, const Context *context)
    : m_current(0)
    , m_next(start)
    , m_context(context)
1060
    , m_error(NoError)
1061
1062
1063
1064
1065
{
    if (start)
        m_prototypes.reserve(10);
}

Christian Kamm's avatar
Christian Kamm committed
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
PrototypeIterator::PrototypeIterator(const ObjectValue *start, const ContextPtr &context)
    : m_current(0)
    , m_next(start)
    , m_context(context.data())
    , m_error(NoError)
{
    if (start)
        m_prototypes.reserve(10);
}

1076
1077
1078
1079
1080
1081
bool PrototypeIterator::hasNext()
{
    if (m_next)
        return true;
    if (!m_current)
        return false;
1082
1083
1084
1085
    const Value *proto = m_current->prototype();
    if (!proto)
        return false;

Christian Kamm's avatar
Christian Kamm committed
1086
    m_next = value_cast<ObjectValue>(proto);
1087
    if (! m_next)
Christian Kamm's avatar
Christian Kamm committed
1088
        m_next = value_cast<ObjectValue>(m_context->lookupReference(proto));
1089
1090
1091
1092
1093
1094
    if (!m_next) {
        m_error = ReferenceResolutionError;
        return false;
    }
    if (m_prototypes.contains(m_next)) {
        m_error = CycleError;
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
        m_next = 0;
        return false;
    }
    return true;
}

const ObjectValue *PrototypeIterator::next()
{
    if (hasNext()) {
        m_current = m_next;
        m_prototypes += m_next;
        m_next = 0;
        return m_current;
    }
    return 0;
}

const ObjectValue *PrototypeIterator::peekNext()
{
    if (hasNext()) {
        return m_next;
    }
    return 0;
}

1120
1121
1122
1123
1124
PrototypeIterator::Error PrototypeIterator::error() const
{
    return m_error;
}

1125
1126
1127
1128
1129
1130
1131
QList<const ObjectValue *> PrototypeIterator::all()
{
    while (hasNext())
        next();
    return m_prototypes;
}

1132
1133
FunctionValue::FunctionValue(ValueOwner *valueOwner)
    : ObjectValue(valueOwner)
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1134
{
1135
    setClassName("Function");
1136
    setMember(QLatin1String("length"), valueOwner->numberValue());
1137
    setPrototype(valueOwner->functionPrototype());
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1138
1139
1140
1141
1142
1143
}

FunctionValue::~FunctionValue()
{
}

1144
1145
const Value *FunctionValue::returnValue() const
{
1146
    return valueOwner()->unknownValue();
1147
1148
}

1149
int FunctionValue::namedArgumentCount() const
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1150
1151
1152
1153
{
    return 0;
}

1154
1155
const Value *FunctionValue::argument(int) const
{
1156
    return valueOwner()->unknownValue();
1157
1158
1159
1160
}

QString FunctionValue::argumentName(int index) const
{
Roberto Raggi's avatar
Roberto Raggi committed
1161
    return QString::fromLatin1("arg%1").arg(index + 1);
1162
1163
}

1164
1165
1166
1167
1168
int FunctionValue::optionalNamedArgumentCount() const
{
    return 0;
}

1169
1170
1171
1172
1173
bool FunctionValue::isVariadic() const
{
    return true;
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
const FunctionValue *FunctionValue::asFunctionValue() const
{
    return this;
}

void FunctionValue::accept(ValueVisitor *visitor) const
{
    visitor->visit(this);
}

1184
Function::Function(ValueOwner *valueOwner)
1185
1186
1187
1188
    : FunctionValue(valueOwner)
    , _returnValue(0)
    , _optionalNamedArgumentCount(0)
    , _isVariadic(false)
1189
1190
1191
{
}

Roberto Raggi's avatar
Roberto Raggi committed
1192
1193
1194
1195
Function::~Function()
{
}

1196
void Function::addArgument(const Value *argument, const QString &name)
1197
{
1198
1199
1200
1201
1202
    if (!name.isEmpty()) {
        while (_argumentNames.size() < _arguments.size())
            _argumentNames.push_back(QString());
        _argumentNames.push_back(name);
    }
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1203
    _arguments.push_back(argument);
1204
1205
}

Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
1206
const Value *Function::returnValue() const