diff options
Diffstat (limited to 'src/libs/qmljs')
-rw-r--r-- | src/libs/qmljs/qmljs-lib.pri | 4 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsbind.cpp | 30 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsbind.h | 19 | ||||
-rw-r--r-- | src/libs/qmljs/qmljscomponentversion.cpp | 50 | ||||
-rw-r--r-- | src/libs/qmljs/qmljscomponentversion.h | 42 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsdocument.cpp | 41 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsdocument.h | 15 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.cpp | 233 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.h | 45 | ||||
-rw-r--r-- | src/libs/qmljs/qmljslink.cpp | 92 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 42 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsmodelmanagerinterface.h | 103 |
12 files changed, 512 insertions, 204 deletions
diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri index aed9d8f0b1..f04185efe4 100644 --- a/src/libs/qmljs/qmljs-lib.pri +++ b/src/libs/qmljs/qmljs-lib.pri @@ -22,6 +22,8 @@ HEADERS += \ $$PWD/qmljsscopebuilder.h \ $$PWD/qmljslineinfo.h \ $$PWD/qmljscompletioncontextfinder.h \ + $$PWD/qmljscomponentversion.h \ + $$PWD/qmljsmodelmanagerinterface.h \ $$PWD/qmljspropertyreader.h \ $$PWD/qmljsrewriter.h @@ -36,6 +38,8 @@ SOURCES += \ $$PWD/qmljsscopebuilder.cpp \ $$PWD/qmljslineinfo.cpp \ $$PWD/qmljscompletioncontextfinder.cpp \ + $$PWD/qmljscomponentversion.cpp \ + $$PWD/qmljsmodelmanagerinterface.cpp \ $$PWD/qmljspropertyreader.cpp \ $$PWD/qmljsrewriter.cpp diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp index b9dabcb3e8..68d2e2b809 100644 --- a/src/libs/qmljs/qmljsbind.cpp +++ b/src/libs/qmljs/qmljsbind.cpp @@ -53,26 +53,21 @@ Bind::~Bind() { } -QStringList Bind::fileImports() const +QList<Bind::ImportInfo> Bind::fileImports() const { return _fileImports; } -QStringList Bind::directoryImports() const +QList<Bind::ImportInfo> Bind::directoryImports() const { return _directoryImports; } -QStringList Bind::libraryImports() const +QList<Bind::ImportInfo> Bind::libraryImports() const { return _libraryImports; } -Interpreter::ObjectValue *Bind::currentObjectValue() const -{ - return _currentObjectValue; -} - Interpreter::ObjectValue *Bind::idEnvironment() const { return _idEnvironment; @@ -185,14 +180,27 @@ bool Bind::visit(AST::Program *) bool Bind::visit(UiImport *ast) { + ImportInfo info; + + if (ast->versionToken.isValid()) { + const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length); + const int dotIdx = versionString.indexOf(QLatin1Char('.')); + if (dotIdx != -1) { + info.version = ComponentVersion(versionString.left(dotIdx).toInt(), + versionString.mid(dotIdx + 1).toInt()); + } + } + if (ast->importUri) { - _libraryImports += toString(ast->importUri, QLatin1Char('/')); + info.name = toString(ast->importUri, QLatin1Char('/')); + _libraryImports += info; } else if (ast->fileName) { const QFileInfo importFileInfo(_doc->path() + QLatin1Char('/') + ast->fileName->asString()); + info.name = importFileInfo.absoluteFilePath(); if (importFileInfo.isFile()) - _fileImports += importFileInfo.absoluteFilePath(); + _fileImports += info; else if (importFileInfo.isDir()) - _directoryImports += importFileInfo.absoluteFilePath(); + _directoryImports += info; //else // error: file or directory does not exist } diff --git a/src/libs/qmljs/qmljsbind.h b/src/libs/qmljs/qmljsbind.h index ed9264e242..e71f171774 100644 --- a/src/libs/qmljs/qmljsbind.h +++ b/src/libs/qmljs/qmljsbind.h @@ -32,6 +32,7 @@ #include <qmljs/parser/qmljsastvisitor_p.h> #include <qmljs/qmljsinterpreter.h> +#include <qmljs/qmljscomponentversion.h> #include <QtCore/QHash> #include <QtCore/QStringList> @@ -50,11 +51,15 @@ public: Bind(Document *doc); virtual ~Bind(); - QStringList fileImports() const; - QStringList directoryImports() const; - QStringList libraryImports() const; + struct ImportInfo { + QString name; + ComponentVersion version; + }; + + QList<ImportInfo> fileImports() const; + QList<ImportInfo> directoryImports() const; + QList<ImportInfo> libraryImports() const; - Interpreter::ObjectValue *currentObjectValue() const; Interpreter::ObjectValue *idEnvironment() const; Interpreter::ObjectValue *rootObjectValue() const; @@ -105,9 +110,9 @@ private: QHash<AST::FunctionDeclaration *, Interpreter::ObjectValue *> _functionScopes; QStringList _includedScripts; - QStringList _fileImports; - QStringList _directoryImports; - QStringList _libraryImports; + QList<ImportInfo> _fileImports; + QList<ImportInfo> _directoryImports; + QList<ImportInfo> _libraryImports; }; } // end of namespace Qml diff --git a/src/libs/qmljs/qmljscomponentversion.cpp b/src/libs/qmljs/qmljscomponentversion.cpp new file mode 100644 index 0000000000..37f5ac514a --- /dev/null +++ b/src/libs/qmljs/qmljscomponentversion.cpp @@ -0,0 +1,50 @@ +#include "qmljscomponentversion.h" + +using namespace QmlJS; + +const int ComponentVersion::NoVersion = -1; + +ComponentVersion::ComponentVersion() + : _major(NoVersion), _minor(NoVersion) +{ +} + +ComponentVersion::ComponentVersion(int major, int minor) + : _major(major), _minor(minor) +{ +} + +ComponentVersion::~ComponentVersion() +{ +} + +bool ComponentVersion::isValid() const +{ + return _major >= 0 && _minor >= 0; +} + +namespace QmlJS { + +bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs) +{ + return lhs.major() < rhs.major() + || (lhs.major() == rhs.major() && lhs.minor() < rhs.minor()); +} + +bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs) +{ + return lhs.major() < rhs.major() + || (lhs.major() == rhs.major() && lhs.minor() <= rhs.minor()); +} + +bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs) +{ + return lhs.major() == rhs.major() && lhs.minor() == rhs.minor(); +} + +bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs) +{ + return !(lhs == rhs); +} + +} diff --git a/src/libs/qmljs/qmljscomponentversion.h b/src/libs/qmljs/qmljscomponentversion.h new file mode 100644 index 0000000000..97edc9dec5 --- /dev/null +++ b/src/libs/qmljs/qmljscomponentversion.h @@ -0,0 +1,42 @@ +#ifndef QMLJSCOMPONENTVERSION_H +#define QMLJSCOMPONENTVERSION_H + +#include "qmljs_global.h" + +namespace QmlJS { + +class QMLJS_EXPORT ComponentVersion +{ + int _major; + int _minor; + +public: + static const int NoVersion; + + ComponentVersion(); + ComponentVersion(int major, int minor); + ~ComponentVersion(); + + int major() const + { return _major; } + int minor() const + { return _minor; } + + // something in the GNU headers introduces the major() and minor() defines, + // use these two to disambiguate when necessary + int majorVersion() const + { return _major; } + int minorVersion() const + { return _minor; } + + bool isValid() const; +}; + +bool operator<(const ComponentVersion &lhs, const ComponentVersion &rhs); +bool operator<=(const ComponentVersion &lhs, const ComponentVersion &rhs); +bool operator==(const ComponentVersion &lhs, const ComponentVersion &rhs); +bool operator!=(const ComponentVersion &lhs, const ComponentVersion &rhs); + +} // namespace QmlJS + +#endif // QMLJSCOMPONENTVERSION_H diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index 6a2c9dc3e4..65df8170a7 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -371,47 +371,6 @@ Document::Ptr Snapshot::documentFromSource(const QString &code, return newDoc; } -QList<Document::Ptr> Snapshot::importedDocuments(const Document::Ptr &doc, const QString &importPath) const -{ - // ### TODO: maybe we should add all imported documents in the parse Document::parse() method, regardless of whether they're in the path or not. - - QList<Document::Ptr> result; - - QString docPath = doc->path(); - docPath += QLatin1Char('/'); - docPath += importPath; - docPath = QDir::cleanPath(docPath); - - foreach (Document::Ptr candidate, _documents) { - if (candidate == doc) - continue; // ignore this document - else if (candidate->isJSDocument()) - continue; // skip JS documents - - if (candidate->path() == doc->path() || candidate->path() == docPath) - result.append(candidate); - } - - return result; -} - -QMap<QString, Document::Ptr> Snapshot::componentsDefinedByImportedDocuments(const Document::Ptr &doc, const QString &importPath) const -{ - QMap<QString, Document::Ptr> result; - - const QString docPath = doc->path() + '/' + importPath; - - foreach (Document::Ptr candidate, *this) { - if (candidate == doc) - continue; - - if (candidate->path() == doc->path() || candidate->path() == docPath) - result.insert(candidate->componentName(), candidate); - } - - return result; -} - Document::Ptr Snapshot::document(const QString &fileName) const { return _documents.value(QDir::cleanPath(fileName)); diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index acbe3d9a05..5f45602327 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -44,6 +44,10 @@ namespace QmlJS { class Bind; class Snapshot; +namespace Interpreter { + class FakeMetaObject; +} + class QMLJS_EXPORT Document { public: @@ -114,6 +118,8 @@ class QMLJS_EXPORT LibraryInfo bool _valid; QList<QmlDirParser::Component> _components; QList<QmlDirParser::Plugin> _plugins; + typedef QList<const Interpreter::FakeMetaObject *> FakeMetaObjectList; + FakeMetaObjectList _metaObjects; public: LibraryInfo(); @@ -126,6 +132,12 @@ public: QList<QmlDirParser::Plugin> plugins() const { return _plugins; } + FakeMetaObjectList metaObjects() const + { return _metaObjects; } + + void setMetaObjects(const FakeMetaObjectList &objects) + { _metaObjects = objects; } + bool isValid() const { return _valid; } }; @@ -157,9 +169,6 @@ public: Document::Ptr documentFromSource(const QString &code, const QString &fileName) const; - - QList<Document::Ptr> importedDocuments(const Document::Ptr &doc, const QString &importPath) const; - QMap<QString, Document::Ptr> componentsDefinedByImportedDocuments(const Document::Ptr &doc, const QString &importPath) const; }; } // end of namespace Qml diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index c7f9b5cba5..c111768cc5 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -30,16 +30,19 @@ #include "qmljsinterpreter.h" #include "qmljsevaluate.h" #include "qmljslink.h" +#include "qmljsbind.h" #include "qmljsscopebuilder.h" +#include "qmljscomponentversion.h" #include "parser/qmljsast_p.h" #include <QtCore/QFile> +#include <QtCore/QDir> #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QMetaObject> #include <QtCore/QMetaProperty> #include <QtCore/QXmlStreamReader> -#include <QtCore/QCoreApplication> +#include <QtCore/QProcess> #include <QtCore/QDebug> using namespace QmlJS::Interpreter; @@ -202,8 +205,8 @@ class FakeMetaObject { QString m_name; QString m_package; - int m_major; - int m_minor; + QString m_packageNameVersion; + ComponentVersion m_version; const FakeMetaObject *m_super; QString m_superName; QList<FakeMetaEnum> m_enums; @@ -214,9 +217,13 @@ class FakeMetaObject { QString m_defaultPropertyName; public: - FakeMetaObject(const QString &name, const QString &package, int majorVersion, int minorVersion) - : m_name(name), m_package(package), m_major(majorVersion), m_minor(minorVersion), m_super(0) - {} + FakeMetaObject(const QString &name, const QString &package, ComponentVersion version) + : m_name(name), m_package(package), m_version(version), m_super(0) + { + m_packageNameVersion = QString::fromLatin1("%1.%2 %3.%4").arg( + package, name, + QString::number(version.majorVersion()), QString::number(version.minorVersion())); + } void setSuperclassName(const QString &superclass) { m_superName = superclass; } @@ -231,6 +238,8 @@ public: { return m_name; } QString packageName() const { return m_package; } + QString packageClassVersionString() const + { return m_packageNameVersion; } void addEnum(const FakeMetaEnum &fakeEnum) { m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); } @@ -263,10 +272,8 @@ public: FakeMetaMethod method(int index) const { return m_methods.at(index); } - int majorVersion() const - { return m_major; } - int minorVersion() const - { return m_minor; } + ComponentVersion version() const + { return m_version; } QString defaultPropertyName() const { return m_defaultPropertyName; } @@ -331,6 +338,11 @@ class QmlXmlReader public: QmlXmlReader(QIODevice *dev) : _xml(dev) + , _objects(0) + {} + + QmlXmlReader(const QByteArray &data) + : _xml(data) {} bool operator()(QMap<QString, FakeMetaObject *> *objects) { @@ -391,7 +403,7 @@ private: bool doInsert = true; QString name, defaultPropertyName; - int major = -1, minor = -1; + QmlJS::ComponentVersion version; QString extends; foreach (const QXmlStreamAttribute &attr, _xml.attributes()) { if (attr.name() == QLatin1String("name")) { @@ -401,28 +413,29 @@ private: return; } } else if (attr.name() == QLatin1String("version")) { - QString version = attr.value().toString(); - int dotIdx = version.indexOf('.'); + QString versionStr = attr.value().toString(); + int dotIdx = versionStr.indexOf('.'); if (dotIdx == -1) { bool ok = false; - major = version.toInt(&ok); + const int major = versionStr.toInt(&ok); if (!ok) { - invalidAttr(version, QLatin1String("version"), tag); + invalidAttr(versionStr, QLatin1String("version"), tag); return; } - minor = -1; + version = QmlJS::ComponentVersion(major, QmlJS::ComponentVersion::NoVersion); } else { bool ok = false; - major = version.left(dotIdx).toInt(&ok); + const int major = versionStr.left(dotIdx).toInt(&ok); if (!ok) { - invalidAttr(version, QLatin1String("version"), tag); + invalidAttr(versionStr, QLatin1String("version"), tag); return; } - minor = version.mid(dotIdx + 1).toInt(&ok); + const int minor = versionStr.mid(dotIdx + 1).toInt(&ok); if (!ok) { - invalidAttr(version, QLatin1String("version"), tag); + invalidAttr(versionStr, QLatin1String("version"), tag); return; } + version = QmlJS::ComponentVersion(major, minor); } } else if (attr.name() == QLatin1String("defaultProperty")) { defaultPropertyName = attr.value().toString(); @@ -441,8 +454,7 @@ private: QString className, packageName; split(name, &packageName, &className); - FakeMetaObject *metaObject = new FakeMetaObject(className, packageName, - major, minor); + FakeMetaObject *metaObject = new FakeMetaObject(className, packageName, version); if (! extends.isEmpty()) metaObject->setSuperclassName(extends); if (! defaultPropertyName.isEmpty()) @@ -682,6 +694,7 @@ private: } FakeMetaMethod method(name, type); + method.setMethodType(FakeMetaMethod::Slot); while (_xml.readNextStartElement()) { if (_xml.name() == QLatin1String("param")) { @@ -701,8 +714,6 @@ private: } // end of anonymous namespace -const int QmlObjectValue::NoVersion = -1; - QmlObjectValue::QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine) : ObjectValue(engine), _metaObject(metaObject) @@ -773,7 +784,7 @@ const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const const QString typeName = prop.typeName(); // ### Verify type resolving. - QmlObjectValue *objectValue = engine()->metaTypeSystem().staticTypeForImport(typeName); + QmlObjectValue *objectValue = engine()->cppQmlTypes().typeForImport(typeName); if (objectValue) return objectValue; @@ -863,11 +874,8 @@ const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const QString QmlObjectValue::packageName() const { return _metaObject->packageName(); } -int QmlObjectValue::majorVersion() const -{ return _metaObject->majorVersion(); } - -int QmlObjectValue::minorVersion() const -{ return _metaObject->minorVersion(); } +QmlJS::ComponentVersion QmlObjectValue::version() const +{ return _metaObject->version(); } QString QmlObjectValue::defaultPropertyName() const { return _metaObject->defaultPropertyName(); } @@ -910,6 +918,26 @@ bool QmlObjectValue::enumContainsKey(const QString &enumName, const QString &enu return false; } +// Returns true if this object is in a package or if there is an object that +// has this one in its prototype chain and is itself in a package. +bool QmlObjectValue::hasChildInPackage() const +{ + if (!packageName().isEmpty()) + return true; + QHashIterator<QString, QmlObjectValue *> it(engine()->cppQmlTypes().types()); + while (it.hasNext()) { + it.next(); + const FakeMetaObject *other = it.value()->_metaObject; + if (other->packageName().isEmpty()) + continue; + for (const FakeMetaObject *iter = other; iter; iter = iter->superClass()) { + if (iter == _metaObject) // this object is a parent of other + return true; + } + } + return false; +} + bool QmlObjectValue::isDerivedFrom(const FakeMetaObject *base) const { for (const FakeMetaObject *iter = _metaObject; iter; iter = iter->superClass()) { @@ -1327,7 +1355,6 @@ ScopeChain::ScopeChain() } ScopeChain::QmlComponentChain::QmlComponentChain() - : rootObject(0), ids(0) { } @@ -1340,8 +1367,7 @@ void ScopeChain::QmlComponentChain::clear() { qDeleteAll(instantiatingComponents); instantiatingComponents.clear(); - rootObject = 0; - ids = 0; + document = Document::Ptr(0); } void ScopeChain::QmlComponentChain::add(QList<const ObjectValue *> *list) const @@ -1349,9 +1375,12 @@ void ScopeChain::QmlComponentChain::add(QList<const ObjectValue *> *list) const foreach (QmlComponentChain *parent, instantiatingComponents) parent->add(list); - if (rootObject) - list->append(rootObject); - if (ids) + if (!document) + return; + + if (ObjectValue *root = document->bind()->rootObjectValue()) + list->append(root); + if (ObjectValue *ids = document->bind()->idEnvironment()) list->append(ids); } @@ -1367,11 +1396,18 @@ void ScopeChain::update() parent->add(&_all); } - if (qmlComponentScope.rootObject && ! qmlScopeObjects.contains(qmlComponentScope.rootObject)) - _all += qmlComponentScope.rootObject; + ObjectValue *root = 0; + ObjectValue *ids = 0; + if (qmlComponentScope.document) { + root = qmlComponentScope.document->bind()->rootObjectValue(); + ids = qmlComponentScope.document->bind()->idEnvironment(); + } + + if (root && !qmlScopeObjects.contains(root)) + _all += root; _all += qmlScopeObjects; - if (qmlComponentScope.ids) - _all += qmlComponentScope.ids; + if (ids) + _all += ids; if (qmlTypes) _all += qmlTypes; _all += jsScopes; @@ -1456,10 +1492,11 @@ const ObjectValue *Context::lookupType(const QmlJS::Document *doc, UiQualifiedId const ObjectValue *Context::lookupType(const QmlJS::Document *doc, const QStringList &qmlTypeName) { const ObjectValue *objectValue = typeEnvironment(doc); - if (!objectValue) - return 0; foreach (const QString &name, qmlTypeName) { + if (!objectValue) + return 0; + const Value *value = objectValue->property(name, this); if (!value) return 0; @@ -1911,19 +1948,18 @@ const Value *Function::invoke(const Activation *activation) const // typing environment //////////////////////////////////////////////////////////////////////////////// -QList<const FakeMetaObject *> MetaTypeSystem::_metaObjects; +QList<const FakeMetaObject *> CppQmlTypesLoader::builtinObjects; -QStringList MetaTypeSystem::load(const QFileInfoList &xmlFiles) +QStringList CppQmlTypesLoader::load(const QFileInfoList &xmlFiles) { - QMap<QString, FakeMetaObject *> objects; - + QMap<QString, FakeMetaObject *> newObjects; QStringList errorMsgs; foreach (const QFileInfo &xmlFile, xmlFiles) { QFile file(xmlFile.absoluteFilePath()); if (file.open(QIODevice::ReadOnly)) { QmlXmlReader read(&file); - if (!read(&objects)) { + if (!read(&newObjects)) { errorMsgs.append(read.errorMessage()); } file.close(); @@ -1934,54 +1970,84 @@ QStringList MetaTypeSystem::load(const QFileInfoList &xmlFiles) } if (errorMsgs.isEmpty()) { - qDeleteAll(_metaObjects); - _metaObjects.clear(); - - foreach (FakeMetaObject *obj, objects.values()) { - const QString superName = obj->superclassName(); - if (! superName.isEmpty()) { - obj->setSuperclass(objects.value(superName, 0)); - } - _metaObjects.append(obj); + setSuperClasses(&newObjects); + + // we need to go from QList<T *> of newObjects.values() to QList<const T *> + // and there seems to be no better way + QMapIterator<QString, FakeMetaObject *> it(newObjects); + while (it.hasNext()) { + it.next(); + builtinObjects.append(it.value()); } } return errorMsgs; } -void MetaTypeSystem::reload(Engine *interpreter) +QString CppQmlTypesLoader::parseQmlTypeXml(const QByteArray &xml, QMap<QString, FakeMetaObject *> *newObjects) { - QHash<const FakeMetaObject *, QmlObjectValue *> qmlObjects; - _importedTypes.clear(); + QmlXmlReader reader(xml); + if (!reader(newObjects)) { + if (reader.errorMessage().isEmpty()) + return QLatin1String("unknown error"); + return reader.errorMessage(); + } + setSuperClasses(newObjects); + return QString(); +} - foreach (const FakeMetaObject *metaObject, _metaObjects) { - QmlObjectValue *objectValue = new QmlObjectValue(metaObject, interpreter); - qmlObjects.insert(metaObject, objectValue); - _importedTypes[metaObject->packageName()].append(objectValue); +void CppQmlTypesLoader::setSuperClasses(QMap<QString, FakeMetaObject *> *newObjects) +{ + QMapIterator<QString, FakeMetaObject *> it(*newObjects); + while (it.hasNext()) { + it.next(); + FakeMetaObject *obj = it.value(); + + const QString superName = obj->superclassName(); + if (! superName.isEmpty()) { + FakeMetaObject *superClass = newObjects->value(superName); + if (superClass) + obj->setSuperclass(superClass); + else + qWarning() << "QmlJS::Interpreter::MetaTypeSystem: Can't find superclass" << superName << "for" << it.key(); + } } +} - foreach (const FakeMetaObject *metaObject, _metaObjects) { - QmlObjectValue *objectValue = qmlObjects.value(metaObject); - if (!objectValue) +void CppQmlTypes::load(Engine *engine, const QList<const FakeMetaObject *> &objects) +{ + // load + foreach (const FakeMetaObject *metaObject, objects) { + // make sure we're not loading duplicate objects + if (_typesByFullyQualifiedName.contains(metaObject->packageClassVersionString())) + continue; + + QmlObjectValue *objectValue = new QmlObjectValue(metaObject, engine); + _typesByPackage[metaObject->packageName()].append(objectValue); + _typesByFullyQualifiedName[metaObject->packageClassVersionString()] = objectValue; + } + + // set prototype correctly + foreach (const FakeMetaObject *metaObject, objects) { + QmlObjectValue *objectValue = _typesByFullyQualifiedName.value(metaObject->packageClassVersionString()); + if (!objectValue || !metaObject->superClass()) continue; - objectValue->setPrototype(qmlObjects.value(metaObject->superClass(), 0)); + objectValue->setPrototype(_typesByFullyQualifiedName.value(metaObject->superClass()->packageClassVersionString())); } } -QList<QmlObjectValue *> MetaTypeSystem::staticTypesForImport(const QString &packageName, int majorVersion, int minorVersion) const +QList<QmlObjectValue *> CppQmlTypes::typesForImport(const QString &packageName, QmlJS::ComponentVersion version) const { QMap<QString, QmlObjectValue *> objectValuesByName; - foreach (QmlObjectValue *qmlObjectValue, _importedTypes.value(packageName)) { - if (qmlObjectValue->majorVersion() < majorVersion || - (qmlObjectValue->majorVersion() == majorVersion && qmlObjectValue->minorVersion() <= minorVersion)) { + foreach (QmlObjectValue *qmlObjectValue, _typesByPackage.value(packageName)) { + if (qmlObjectValue->version() <= version) { // we got a candidate. const QString typeName = qmlObjectValue->className(); QmlObjectValue *previousCandidate = objectValuesByName.value(typeName, 0); if (previousCandidate) { // check if our new candidate is newer than the one we found previously - if (qmlObjectValue->majorVersion() > previousCandidate->majorVersion() || - (qmlObjectValue->majorVersion() == previousCandidate->majorVersion() && qmlObjectValue->minorVersion() > previousCandidate->minorVersion())) { + if (previousCandidate->version() < qmlObjectValue->version()) { // the new candidate has a higher version no. than the one we found previously, so replace it objectValuesByName.insert(typeName, qmlObjectValue); } @@ -1994,7 +2060,7 @@ QList<QmlObjectValue *> MetaTypeSystem::staticTypesForImport(const QString &pack return objectValuesByName.values(); } -QmlObjectValue *MetaTypeSystem::staticTypeForImport(const QString &qualifiedName) const +QmlObjectValue *CppQmlTypes::typeForImport(const QString &qualifiedName) const { QString name = qualifiedName; QString packageName; @@ -2005,15 +2071,14 @@ QmlObjectValue *MetaTypeSystem::staticTypeForImport(const QString &qualifiedName } QmlObjectValue *previousCandidate = 0; - foreach (QmlObjectValue *qmlObjectValue, _importedTypes.value(packageName)) { + foreach (QmlObjectValue *qmlObjectValue, _typesByPackage.value(packageName)) { const QString typeName = qmlObjectValue->className(); if (typeName != name) continue; if (previousCandidate) { // check if our new candidate is newer than the one we found previously - if (qmlObjectValue->majorVersion() > previousCandidate->majorVersion() || - (qmlObjectValue->majorVersion() == previousCandidate->majorVersion() && qmlObjectValue->minorVersion() > previousCandidate->minorVersion())) { + if (previousCandidate->version() < qmlObjectValue->version()) { // the new candidate has a higher version no. than the one we found previously, so replace it previousCandidate = qmlObjectValue; } @@ -2025,9 +2090,9 @@ QmlObjectValue *MetaTypeSystem::staticTypeForImport(const QString &qualifiedName return previousCandidate; } -bool MetaTypeSystem::hasPackage(const QString &package) const +bool CppQmlTypes::hasPackage(const QString &package) const { - return _importedTypes.contains(package); + return _typesByPackage.contains(package); } ConvertToNumber::ConvertToNumber(Engine *engine) @@ -2303,7 +2368,7 @@ Engine::Engine() { initializePrototypes(); - _metaTypeSystem.reload(this); + _cppQmlTypes.load(this, CppQmlTypesLoader::builtinObjects); } Engine::~Engine() @@ -2531,34 +2596,42 @@ void Engine::initializePrototypes() _objectCtor = new ObjectCtor(this); _objectCtor->setPrototype(_functionPrototype); _objectCtor->setProperty("prototype", _objectPrototype); + _objectCtor->setReturnValue(newObject()); _functionCtor = new FunctionCtor(this); _functionCtor->setPrototype(_functionPrototype); _functionCtor->setProperty("prototype", _functionPrototype); + _functionCtor->setReturnValue(newFunction()); _arrayCtor = new ArrayCtor(this); _arrayCtor->setPrototype(_functionPrototype); _arrayCtor->setProperty("prototype", _arrayPrototype); + _arrayCtor->setReturnValue(newArray()); _stringCtor = new StringCtor(this); _stringCtor->setPrototype(_functionPrototype); _stringCtor->setProperty("prototype", _stringPrototype); + _stringCtor->setReturnValue(stringValue()); _booleanCtor = new BooleanCtor(this); _booleanCtor->setPrototype(_functionPrototype); _booleanCtor->setProperty("prototype", _booleanPrototype); + _booleanCtor->setReturnValue(booleanValue()); _numberCtor = new NumberCtor(this); _numberCtor->setPrototype(_functionPrototype); _numberCtor->setProperty("prototype", _numberPrototype); + _numberCtor->setReturnValue(numberValue()); _dateCtor = new DateCtor(this); _dateCtor->setPrototype(_functionPrototype); _dateCtor->setProperty("prototype", _datePrototype); + _dateCtor->setReturnValue(_datePrototype); _regexpCtor = new RegExpCtor(this); _regexpCtor->setPrototype(_functionPrototype); _regexpCtor->setProperty("prototype", _regexpPrototype); + _regexpCtor->setReturnValue(_regexpPrototype); addFunction(_objectCtor, "getPrototypeOf", 1); addFunction(_objectCtor, "getOwnPropertyDescriptor", 2); diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index b1aed52538..4981265554 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -32,6 +32,7 @@ #include <qmljs/qmljsdocument.h> #include <qmljs/qmljs_global.h> +#include <qmljs/qmljscomponentversion.h> #include <qmljs/parser/qmljsastfwd_p.h> #include <QtCore/QFileInfoList> @@ -247,8 +248,7 @@ public: ~QmlComponentChain(); QList<QmlComponentChain *> instantiatingComponents; - const ObjectValue *rootObject; - const ObjectValue *ids; + Document::Ptr document; void add(QList<const ObjectValue *> *list) const; void clear(); @@ -381,9 +381,6 @@ private: class QMLJS_EXPORT QmlObjectValue: public ObjectValue { public: - static const int NoVersion; - -public: QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine); virtual ~QmlObjectValue(); @@ -391,13 +388,13 @@ public: const Value *propertyValue(const FakeMetaProperty &prop) const; QString packageName() const; - int majorVersion() const; - int minorVersion() const; + ComponentVersion version() const; QString defaultPropertyName() const; QString propertyType(const QString &propertyName) const; bool isListProperty(const QString &name) const; bool isEnum(const QString &typeName) const; bool enumContainsKey(const QString &enumName, const QString &enumKeyName) const; + bool hasChildInPackage() const; protected: const Value *findOrCreateSignature(int index, const FakeMetaMethod &method, QString *methodName) const; @@ -508,23 +505,35 @@ private: // typing environment //////////////////////////////////////////////////////////////////////////////// -class QMLJS_EXPORT MetaTypeSystem +class QMLJS_EXPORT CppQmlTypesLoader { - static QList<const FakeMetaObject *> _metaObjects; - public: /** \return an empty list when successful, error messages otherwise. */ static QStringList load(const QFileInfoList &xmlFiles); + static QList<const FakeMetaObject *> builtinObjects; - void reload(Interpreter::Engine *interpreter); + // parses the xml string and fills the newObjects map + static QString parseQmlTypeXml(const QByteArray &xml, QMap<QString, FakeMetaObject *> *newObjects); +private: + static void setSuperClasses(QMap<QString, FakeMetaObject *> *newObjects); +}; - QList<Interpreter::QmlObjectValue *> staticTypesForImport(const QString &prefix, int majorVersion, int minorVersion) const; - Interpreter::QmlObjectValue *staticTypeForImport(const QString &qualifiedName) const; +class QMLJS_EXPORT CppQmlTypes +{ +public: + void load(Interpreter::Engine *interpreter, const QList<const FakeMetaObject *> &objects); + + QList<Interpreter::QmlObjectValue *> typesForImport(const QString &prefix, ComponentVersion version) const; + Interpreter::QmlObjectValue *typeForImport(const QString &qualifiedName) const; bool hasPackage(const QString &package) const; + QHash<QString, QmlObjectValue *> types() const + { return _typesByFullyQualifiedName; } + private: - QHash<QString, QList<QmlObjectValue *> > _importedTypes; + QHash<QString, QList<QmlObjectValue *> > _typesByPackage; + QHash<QString, QmlObjectValue *> _typesByFullyQualifiedName; }; class ConvertToNumber: protected ValueVisitor // ECMAScript ToInt() @@ -674,8 +683,10 @@ public: QString typeId(const Value *value); // typing: - const MetaTypeSystem &metaTypeSystem() const - { return _metaTypeSystem; } + CppQmlTypes &cppQmlTypes() + { return _cppQmlTypes; } + const CppQmlTypes &cppQmlTypes() const + { return _cppQmlTypes; } void registerValue(Value *value); // internal @@ -723,7 +734,7 @@ private: ConvertToObject _convertToObject; TypeId _typeId; - MetaTypeSystem _metaTypeSystem; + CppQmlTypes _cppQmlTypes; }; diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index d9325b9d1f..41e713e62a 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -63,8 +63,8 @@ void Link::initializeScopeChain() } else { // add scope chains for all components that import this file foreach (Document::Ptr otherDoc, _snapshot) { - foreach (const QString &fileImport, otherDoc->bind()->fileImports()) { - if (_doc->fileName() == fileImport) { + foreach (const Bind::ImportInfo &fileImport, otherDoc->bind()->fileImports()) { + if (_doc->fileName() == fileImport.name) { ScopeChain::QmlComponentChain *component = new ScopeChain::QmlComponentChain; componentScopes.insert(otherDoc.data(), component); scopeChain.qmlComponentScope.instantiatingComponents += component; @@ -110,10 +110,7 @@ void Link::makeComponentChain( } // build this component scope - if (bind->rootObjectValue()) - target->rootObject = bind->rootObjectValue(); - - target->ids = bind->idEnvironment(); + target->document = doc; } void Link::linkImports() @@ -134,7 +131,7 @@ void Link::populateImportedTypes(Interpreter::ObjectValue *typeEnv, Document::Pt return; // Add the implicitly available Script type - const ObjectValue *scriptValue = engine()->metaTypeSystem().staticTypeForImport("Script"); + const ObjectValue *scriptValue = engine()->cppQmlTypes().typeForImport("Script"); if (scriptValue) typeEnv->setProperty("Script", scriptValue); @@ -247,8 +244,7 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A } const QString packageName = Bind::toString(import->importUri, '.'); - int majorVersion = QmlObjectValue::NoVersion; - int minorVersion = QmlObjectValue::NoVersion; + ComponentVersion version; if (import->versionToken.isValid()) { const QString versionString = doc->source().mid(import->versionToken.offset, import->versionToken.length); @@ -258,8 +254,9 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A tr("expected two numbers separated by a dot")); return; } else { - majorVersion = versionString.left(dotIdx).toInt(); - minorVersion = versionString.mid(dotIdx + 1).toInt(); + const int majorVersion = versionString.left(dotIdx).toInt(); + const int minorVersion = versionString.mid(dotIdx + 1).toInt(); + version = ComponentVersion(majorVersion, minorVersion); } } else { error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()), @@ -267,50 +264,55 @@ void Link::importNonFile(Interpreter::ObjectValue *typeEnv, Document::Ptr doc, A return; } - // if the package is in the meta type system, use it - if (engine()->metaTypeSystem().hasPackage(packageName)) { - foreach (QmlObjectValue *object, engine()->metaTypeSystem().staticTypesForImport(packageName, majorVersion, minorVersion)) { - namespaceObject->setProperty(object->className(), object); - } - return; - } else { - // check the filesystem - const QString packagePath = Bind::toString(import->importUri, QDir::separator()); - foreach (const QString &importPath, _importPaths) { - QDir dir(importPath); - if (!dir.cd(packagePath)) - continue; + bool importFound = false; - const LibraryInfo libraryInfo = _snapshot.libraryInfo(dir.path()); - if (!libraryInfo.isValid()) - continue; + // check the filesystem + const QString packagePath = Bind::toString(import->importUri, QDir::separator()); + foreach (const QString &importPath, _importPaths) { + QDir dir(importPath); + if (!dir.cd(packagePath)) + continue; - if (!libraryInfo.plugins().isEmpty()) - _context->setDocumentImportsPlugins(doc.data()); + const LibraryInfo libraryInfo = _snapshot.libraryInfo(dir.path()); + if (!libraryInfo.isValid()) + continue; - QSet<QString> importedTypes; - foreach (const QmlDirParser::Component &component, libraryInfo.components()) { - if (importedTypes.contains(component.typeName)) - continue; + importFound = true; - if (component.majorVersion > majorVersion - || (component.majorVersion == majorVersion - && component.minorVersion > minorVersion)) - continue; + if (!libraryInfo.plugins().isEmpty()) + engine()->cppQmlTypes().load(engine(), libraryInfo.metaObjects()); - importedTypes.insert(component.typeName); - if (Document::Ptr importedDoc = _snapshot.document(dir.filePath(component.fileName))) { - if (importedDoc->bind()->rootObjectValue()) - namespaceObject->setProperty(component.typeName, importedDoc->bind()->rootObjectValue()); - } + QSet<QString> importedTypes; + foreach (const QmlDirParser::Component &component, libraryInfo.components()) { + if (importedTypes.contains(component.typeName)) + continue; + + ComponentVersion componentVersion(component.majorVersion, component.minorVersion); + if (version < componentVersion) + continue; + + importedTypes.insert(component.typeName); + if (Document::Ptr importedDoc = _snapshot.document(dir.filePath(component.fileName))) { + if (importedDoc->bind()->rootObjectValue()) + namespaceObject->setProperty(component.typeName, importedDoc->bind()->rootObjectValue()); } + } - return; + break; + } + + // if there are cpp-based types for this package, use them too + if (engine()->cppQmlTypes().hasPackage(packageName)) { + importFound = true; + foreach (QmlObjectValue *object, engine()->cppQmlTypes().typesForImport(packageName, version)) { + namespaceObject->setProperty(object->className(), object); } } - error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()), - tr("package not found")); + if (!importFound) { + error(doc, locationFromRange(import->firstSourceLocation(), import->lastSourceLocation()), + tr("package not found")); + } } UiQualifiedId *Link::qualifiedTypeNameId(Node *node) diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp new file mode 100644 index 0000000000..90917547f5 --- /dev/null +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -0,0 +1,42 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "qmljsmodelmanagerinterface.h" + +using namespace QmlJS; + +ModelManagerInterface::ModelManagerInterface(QObject *parent) + : QObject(parent) +{ +} + +ModelManagerInterface::~ModelManagerInterface() +{ +} + diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h new file mode 100644 index 0000000000..bf00b13745 --- /dev/null +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -0,0 +1,103 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef QMLJSMODELMANAGERINTERFACE_H +#define QMLJSMODELMANAGERINTERFACE_H + +#include "qmljs_global.h" +#include "qmljsdocument.h" + +#include <QObject> +#include <QStringList> +#include <QSharedPointer> +#include <QPointer> + +namespace ProjectExplorer { + class Project; +} + +namespace QmlJS { + +class Snapshot; + +class QMLJS_EXPORT ModelManagerInterface: public QObject +{ + Q_OBJECT + +public: + class ProjectInfo + { + public: + ProjectInfo() + { } + + ProjectInfo(QPointer<ProjectExplorer::Project> project) + : project(project) + { } + + operator bool() const + { return ! project.isNull(); } + + bool isValid() const + { return ! project.isNull(); } + + bool isNull() const + { return project.isNull(); } + + public: // attributes + QPointer<ProjectExplorer::Project> project; + QStringList sourceFiles; + QStringList importPaths; + }; + +public: + ModelManagerInterface(QObject *parent = 0); + virtual ~ModelManagerInterface(); + + virtual QmlJS::Snapshot snapshot() const = 0; + virtual void updateSourceFiles(const QStringList &files, + bool emitDocumentOnDiskChanged) = 0; + virtual void fileChangedOnDisk(const QString &path) = 0; + virtual void removeFiles(const QStringList &files) = 0; + + virtual QList<ProjectInfo> projectInfos() const = 0; + virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const = 0; + virtual void updateProjectInfo(const ProjectInfo &pinfo) = 0; + + virtual QStringList importPaths() const = 0; + +signals: + void documentUpdated(QmlJS::Document::Ptr doc); + void documentChangedOnDisk(QmlJS::Document::Ptr doc); + void aboutToRemoveFiles(const QStringList &files); +}; + +} // namespace QmlJS + +#endif // QMLJSMODELMANAGERINTERFACE_H |