summaryrefslogtreecommitdiff
path: root/src/libs/qmljs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/qmljs')
-rw-r--r--src/libs/qmljs/qmljs-lib.pri4
-rw-r--r--src/libs/qmljs/qmljsbind.cpp30
-rw-r--r--src/libs/qmljs/qmljsbind.h19
-rw-r--r--src/libs/qmljs/qmljscomponentversion.cpp50
-rw-r--r--src/libs/qmljs/qmljscomponentversion.h42
-rw-r--r--src/libs/qmljs/qmljsdocument.cpp41
-rw-r--r--src/libs/qmljs/qmljsdocument.h15
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp233
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h45
-rw-r--r--src/libs/qmljs/qmljslink.cpp92
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.cpp42
-rw-r--r--src/libs/qmljs/qmljsmodelmanagerinterface.h103
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