forked from qt-creator/qt-creator
QmlJS: Separate metaObjectRevision from minor version number.
They need not to be identical. Additionally: * Rename ImportInfo::name to path, because that's what it does. * Add ImportInfo::name, for getting the uri with the names separated by dots. * Allow for exportMetaObjectRevisions in qmltypes files. * Allow for exports with an empty type name, as generated by qmlRegisterRevision. They are used for associating meta object revisions with non-exported types. * Rewrite the Qt 4.7 import to QtQuick 1.0 at an early stage. In preparation for the Qt 5 type information update, where Qt 4.7 is gone. Change-Id: Ia287193623d9530a56b9eb8d2481d50aabd94c3e Reviewed-on: http://codereview.qt-project.org/5309 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
@@ -200,6 +200,7 @@ bool Bind::visit(UiImport *ast)
|
||||
{
|
||||
ComponentVersion version;
|
||||
ImportInfo::Type type = ImportInfo::InvalidImport;
|
||||
QString path;
|
||||
QString name;
|
||||
|
||||
if (ast->versionToken.isValid()) {
|
||||
@@ -213,19 +214,27 @@ bool Bind::visit(UiImport *ast)
|
||||
|
||||
if (ast->importUri) {
|
||||
type = ImportInfo::LibraryImport;
|
||||
name = toString(ast->importUri, QDir::separator());
|
||||
path = toString(ast->importUri, QDir::separator());
|
||||
name = toString(ast->importUri, QLatin1Char(','));
|
||||
|
||||
// treat Qt 4.7 as QtQuick 1.0
|
||||
if (path == QLatin1String("Qt") && version == ComponentVersion(4, 7)) {
|
||||
path = QLatin1String("QtQuick");
|
||||
name = path;
|
||||
version = ComponentVersion(1, 0);
|
||||
}
|
||||
|
||||
if (!version.isValid()) {
|
||||
_diagnosticMessages->append(
|
||||
errorMessage(ast, tr("package import requires a version number")));
|
||||
}
|
||||
} else if (!ast->fileName.isEmpty()) {
|
||||
const QString &fileName = ast->fileName.toString();
|
||||
QFileInfo importFileInfo(fileName);
|
||||
name = ast->fileName.toString();
|
||||
QFileInfo importFileInfo(name);
|
||||
if (!importFileInfo.isAbsolute()) {
|
||||
importFileInfo=QFileInfo(_doc->path() + QDir::separator() + fileName);
|
||||
importFileInfo = QFileInfo(_doc->path() + QDir::separator() + name);
|
||||
}
|
||||
name = importFileInfo.absoluteFilePath();
|
||||
path = importFileInfo.absoluteFilePath();
|
||||
if (importFileInfo.isFile())
|
||||
type = ImportInfo::FileImport;
|
||||
else if (importFileInfo.isDir())
|
||||
@@ -234,7 +243,7 @@ bool Bind::visit(UiImport *ast)
|
||||
type = ImportInfo::UnknownFileImport;
|
||||
}
|
||||
}
|
||||
_imports += ImportInfo(type, name, version, ast);
|
||||
_imports += ImportInfo(type, path, name, version, ast);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -161,13 +161,15 @@ public:
|
||||
|
||||
QmlObjectValue::QmlObjectValue(FakeMetaObject::ConstPtr metaObject, const QString &className,
|
||||
const QString &packageName, const ComponentVersion &componentVersion,
|
||||
const ComponentVersion &importVersion, ValueOwner *valueOwner)
|
||||
const ComponentVersion &importVersion, int metaObjectRevision,
|
||||
ValueOwner *valueOwner)
|
||||
: ObjectValue(valueOwner),
|
||||
_attachedType(0),
|
||||
_metaObject(metaObject),
|
||||
_moduleName(packageName),
|
||||
_componentVersion(componentVersion),
|
||||
_importVersion(importVersion)
|
||||
_importVersion(importVersion),
|
||||
_metaObjectRevision(metaObjectRevision)
|
||||
{
|
||||
setClassName(className);
|
||||
int nEnums = metaObject->enumeratorCount();
|
||||
@@ -208,7 +210,7 @@ void QmlObjectValue::processMembers(MemberProcessor *processor) const
|
||||
// process the meta methods
|
||||
for (int index = 0; index < _metaObject->methodCount(); ++index) {
|
||||
const FakeMetaMethod method = _metaObject->method(index);
|
||||
if (_componentVersion.isValid() && _componentVersion.minorVersion() < method.revision())
|
||||
if (_metaObjectRevision < method.revision())
|
||||
continue;
|
||||
|
||||
QString methodName;
|
||||
@@ -234,7 +236,7 @@ void QmlObjectValue::processMembers(MemberProcessor *processor) const
|
||||
// process the meta properties
|
||||
for (int index = 0; index < _metaObject->propertyCount(); ++index) {
|
||||
const FakeMetaProperty prop = _metaObject->property(index);
|
||||
if (_componentVersion.isValid() && _componentVersion.minorVersion() < prop.revision())
|
||||
if (_metaObjectRevision < prop.revision())
|
||||
continue;
|
||||
|
||||
const QString propertyName = prop.name();
|
||||
@@ -1262,8 +1264,9 @@ void CppQmlTypes::load(const T &fakeMetaObjects, const QString &overridePackage)
|
||||
QTC_ASSERT(exp.version == ComponentVersion(), continue);
|
||||
QTC_ASSERT(exp.type == fmo->className(), continue);
|
||||
QmlObjectValue *cppValue = new QmlObjectValue(
|
||||
fmo, fmo->className(), cppPackage, ComponentVersion(), ComponentVersion(), _valueOwner);
|
||||
_objectsByQualifiedName[exp.packageNameVersion] = cppValue;
|
||||
fmo, fmo->className(), cppPackage, ComponentVersion(), ComponentVersion(),
|
||||
ComponentVersion::MaxVersion, _valueOwner);
|
||||
_objectsByQualifiedName[qualifiedName(cppPackage, fmo->className(), ComponentVersion())] = cppValue;
|
||||
newCppTypes += cppValue;
|
||||
}
|
||||
}
|
||||
@@ -1284,6 +1287,7 @@ template void CppQmlTypes::load< QHash<QString, FakeMetaObject::ConstPtr> >(cons
|
||||
QList<const QmlObjectValue *> CppQmlTypes::createObjectsForImport(const QString &package, ComponentVersion version)
|
||||
{
|
||||
QList<const QmlObjectValue *> exportedObjects;
|
||||
QList<const QmlObjectValue *> newObjects;
|
||||
|
||||
// make new exported objects
|
||||
foreach (const FakeMetaObject::ConstPtr &fmo, _fakeMetaObjectsByPackage.value(package)) {
|
||||
@@ -1303,16 +1307,26 @@ QList<const QmlObjectValue *> CppQmlTypes::createObjectsForImport(const QString
|
||||
if (_objectsByQualifiedName.contains(key))
|
||||
continue;
|
||||
|
||||
QString name = bestExport.type;
|
||||
bool exported = true;
|
||||
if (name.isEmpty()) {
|
||||
exported = false;
|
||||
name = fmo->className();
|
||||
}
|
||||
|
||||
QmlObjectValue *newObject = new QmlObjectValue(
|
||||
fmo, bestExport.type, package, bestExport.version, version, _valueOwner);
|
||||
fmo, name, package, bestExport.version, version,
|
||||
bestExport.metaObjectRevision, _valueOwner);
|
||||
|
||||
// use package.cppname importversion as key
|
||||
_objectsByQualifiedName.insert(key, newObject);
|
||||
exportedObjects += newObject;
|
||||
if (exported)
|
||||
exportedObjects += newObject;
|
||||
newObjects += newObject;
|
||||
}
|
||||
|
||||
// set their prototypes, creating them if necessary
|
||||
foreach (const QmlObjectValue *cobject, exportedObjects) {
|
||||
foreach (const QmlObjectValue *cobject, newObjects) {
|
||||
QmlObjectValue *object = const_cast<QmlObjectValue *>(cobject);
|
||||
while (!object->prototype()) {
|
||||
const QString &protoCppName = object->metaObject()->superclassName();
|
||||
@@ -1335,7 +1349,7 @@ QList<const QmlObjectValue *> CppQmlTypes::createObjectsForImport(const QString
|
||||
// make a new object
|
||||
QmlObjectValue *proto = new QmlObjectValue(
|
||||
protoFmo, protoCppName, object->moduleName(), ComponentVersion(),
|
||||
object->importVersion(), _valueOwner);
|
||||
object->importVersion(), ComponentVersion::MaxVersion, _valueOwner);
|
||||
_objectsByQualifiedName.insert(key, proto);
|
||||
object->setPrototype(proto);
|
||||
|
||||
@@ -1916,10 +1930,11 @@ ImportInfo::ImportInfo()
|
||||
{
|
||||
}
|
||||
|
||||
ImportInfo::ImportInfo(Type type, const QString &name,
|
||||
ImportInfo::ImportInfo(Type type, const QString &path, const QString &name,
|
||||
ComponentVersion version, UiImport *ast)
|
||||
: _type(type)
|
||||
, _name(name)
|
||||
, _path(path)
|
||||
, _version(version)
|
||||
, _ast(ast)
|
||||
{
|
||||
@@ -1940,6 +1955,11 @@ QString ImportInfo::name() const
|
||||
return _name;
|
||||
}
|
||||
|
||||
QString ImportInfo::path() const
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
QString ImportInfo::id() const
|
||||
{
|
||||
if (_ast)
|
||||
@@ -2208,7 +2228,7 @@ void Imports::dump() const
|
||||
const ObjectValue *import = i.object;
|
||||
const ImportInfo &info = i.info;
|
||||
|
||||
qDebug() << " " << info.name() << " " << info.version().toString() << " as " << info.id() << " : " << import;
|
||||
qDebug() << " " << info.path() << " " << info.version().toString() << " as " << info.id() << " : " << import;
|
||||
MemberDumper dumper;
|
||||
import->processMembers(&dumper);
|
||||
}
|
||||
|
@@ -419,7 +419,7 @@ class QMLJS_EXPORT QmlObjectValue: public ObjectValue
|
||||
public:
|
||||
QmlObjectValue(LanguageUtils::FakeMetaObject::ConstPtr metaObject, const QString &className,
|
||||
const QString &moduleName, const LanguageUtils::ComponentVersion &componentVersion,
|
||||
const LanguageUtils::ComponentVersion &importVersion,
|
||||
const LanguageUtils::ComponentVersion &importVersion, int metaObjectRevision,
|
||||
ValueOwner *valueOwner);
|
||||
virtual ~QmlObjectValue();
|
||||
|
||||
@@ -464,6 +464,7 @@ private:
|
||||
const LanguageUtils::ComponentVersion _importVersion;
|
||||
mutable QHash<int, const Value *> _metaSignature;
|
||||
QHash<QString, const QmlEnumValue * > _enums;
|
||||
int _metaObjectRevision;
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT Activation
|
||||
@@ -823,17 +824,21 @@ public:
|
||||
};
|
||||
|
||||
ImportInfo();
|
||||
ImportInfo(Type type, const QString &name,
|
||||
ImportInfo(Type type, const QString &path, const QString &name = QString(),
|
||||
LanguageUtils::ComponentVersion version = LanguageUtils::ComponentVersion(),
|
||||
AST::UiImport *ast = 0);
|
||||
|
||||
bool isValid() const;
|
||||
Type type() const;
|
||||
|
||||
// LibraryImport: uri with '/' separator
|
||||
// Other: absoluteFilePath
|
||||
// LibraryImport: uri with ',' separator
|
||||
// Other: non-absolute path
|
||||
QString name() const;
|
||||
|
||||
// LibraryImport: uri with QDir::separator separator
|
||||
// Other: absoluteFilePath
|
||||
QString path() const;
|
||||
|
||||
// null if the import has no 'as', otherwise the target id
|
||||
QString id() const;
|
||||
|
||||
@@ -843,6 +848,7 @@ public:
|
||||
private:
|
||||
Type _type;
|
||||
QString _name;
|
||||
QString _path;
|
||||
LanguageUtils::ComponentVersion _version;
|
||||
AST::UiImport *_ast;
|
||||
};
|
||||
|
@@ -52,27 +52,27 @@ class ImportCacheKey
|
||||
public:
|
||||
explicit ImportCacheKey(const ImportInfo &info)
|
||||
: type(info.type())
|
||||
, name(info.name())
|
||||
, path(info.path())
|
||||
, majorVersion(info.version().majorVersion())
|
||||
, minorVersion(info.version().minorVersion())
|
||||
{}
|
||||
|
||||
int type;
|
||||
QString name;
|
||||
QString path;
|
||||
int majorVersion;
|
||||
int minorVersion;
|
||||
};
|
||||
|
||||
uint qHash(const ImportCacheKey &info)
|
||||
{
|
||||
return ::qHash(info.type) ^ ::qHash(info.name) ^
|
||||
return ::qHash(info.type) ^ ::qHash(info.path) ^
|
||||
::qHash(info.majorVersion) ^ ::qHash(info.minorVersion);
|
||||
}
|
||||
|
||||
bool operator==(const ImportCacheKey &i1, const ImportCacheKey &i2)
|
||||
{
|
||||
return i1.type == i2.type
|
||||
&& i1.name == i2.name
|
||||
&& i1.path == i2.path
|
||||
&& i1.majorVersion == i2.majorVersion
|
||||
&& i1.minorVersion == i2.minorVersion;
|
||||
}
|
||||
@@ -291,7 +291,7 @@ Import LinkPrivate::importFileOrDirectory(Document::Ptr doc, const ImportInfo &i
|
||||
import.info = importInfo;
|
||||
import.object = 0;
|
||||
|
||||
const QString &path = importInfo.name();
|
||||
const QString &path = importInfo.path();
|
||||
|
||||
if (importInfo.type() == ImportInfo::DirectoryImport
|
||||
|| importInfo.type() == ImportInfo::ImplicitDirectoryImport) {
|
||||
@@ -326,12 +326,12 @@ Import LinkPrivate::importNonFile(Document::Ptr doc, const ImportInfo &importInf
|
||||
import.info = importInfo;
|
||||
import.object = new ObjectValue(valueOwner);
|
||||
|
||||
const QString packageName = Bind::toString(importInfo.ast()->importUri, '.');
|
||||
const QString packageName = importInfo.name();
|
||||
const ComponentVersion version = importInfo.version();
|
||||
|
||||
bool importFound = false;
|
||||
|
||||
const QString &packagePath = importInfo.name();
|
||||
const QString &packagePath = importInfo.path();
|
||||
// check the filesystem with full version
|
||||
foreach (const QString &importPath, importPaths) {
|
||||
QString libraryPath = QString("%1/%2.%3").arg(importPath, packagePath, version.toString());
|
||||
@@ -410,8 +410,8 @@ bool LinkPrivate::importLibrary(Document::Ptr doc,
|
||||
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
|
||||
if (modelManager) {
|
||||
if (importInfo.type() == ImportInfo::LibraryImport) {
|
||||
if (importInfo.version().isValid()) {
|
||||
const QString uri = importInfo.name().replace(QDir::separator(), QLatin1Char('.'));
|
||||
if (version.isValid()) {
|
||||
const QString uri = importInfo.name();
|
||||
modelManager->loadPluginTypes(
|
||||
libraryPath, importPath,
|
||||
uri, version.toString());
|
||||
@@ -429,14 +429,12 @@ bool LinkPrivate::importLibrary(Document::Ptr doc,
|
||||
} else if (libraryInfo.pluginTypeInfoStatus() == LibraryInfo::DumpError
|
||||
|| libraryInfo.pluginTypeInfoStatus() == LibraryInfo::TypeInfoFileError) {
|
||||
// Only underline import if package isn't described in .qmltypes anyway
|
||||
QString packageName;
|
||||
if (ast && ast->importUri)
|
||||
packageName = Bind::toString(importInfo.ast()->importUri, '.');
|
||||
QString packageName = importInfo.name();
|
||||
if (errorLoc.isValid() && (packageName.isEmpty() || !valueOwner->cppQmlTypes().hasModule(packageName))) {
|
||||
error(doc, errorLoc, libraryInfo.pluginTypeInfoError());
|
||||
}
|
||||
} else if (ast && ast->importUri) {
|
||||
const QString packageName = Bind::toString(importInfo.ast()->importUri, '.');
|
||||
} else {
|
||||
const QString packageName = importInfo.name();
|
||||
valueOwner->cppQmlTypes().load(libraryInfo.metaObjects(), packageName);
|
||||
foreach (const QmlObjectValue *object, valueOwner->cppQmlTypes().createObjectsForImport(packageName, version)) {
|
||||
import->object->setMember(object->className(), object);
|
||||
|
@@ -266,7 +266,7 @@ void ScopeChain::initializeRootScope()
|
||||
// add scope chains for all components that import this file
|
||||
foreach (Document::Ptr otherDoc, snapshot) {
|
||||
foreach (const ImportInfo &import, otherDoc->bind()->imports()) {
|
||||
if (import.type() == ImportInfo::FileImport && m_document->fileName() == import.name()) {
|
||||
if (import.type() == ImportInfo::FileImport && m_document->fileName() == import.path()) {
|
||||
QmlComponentChain *component = new QmlComponentChain(otherDoc);
|
||||
componentScopes.insert(otherDoc.data(), component);
|
||||
chain->addInstantiatingComponent(component);
|
||||
|
@@ -199,10 +199,14 @@ void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
|
||||
fmo->setDefaultPropertyName(readStringBinding(script));
|
||||
} else if (name == "exports") {
|
||||
readExports(script, fmo);
|
||||
} else if (name == "exportMetaObjectRevisions") {
|
||||
readMetaObjectRevisions(script, fmo);
|
||||
} else if (name == "attachedType") {
|
||||
fmo->setAttachedTypeName(readStringBinding(script));
|
||||
} else {
|
||||
addWarning(script->firstSourceLocation(), "Expected only name, prototype, defaultProperty, attachedType and exports script bindings");
|
||||
addWarning(script->firstSourceLocation(),
|
||||
"Expected only name, prototype, defaultProperty, attachedType, exports"
|
||||
"and exportMetaObjectRevisions script bindings");
|
||||
}
|
||||
} else {
|
||||
addWarning(member->firstSourceLocation(), "Expected only script bindings and object definitions");
|
||||
@@ -488,6 +492,50 @@ void TypeDescriptionReader::readExports(UiScriptBinding *ast, FakeMetaObject::Pt
|
||||
}
|
||||
}
|
||||
|
||||
void TypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast, FakeMetaObject::Ptr fmo)
|
||||
{
|
||||
if (!ast || !ast->statement) {
|
||||
addError(ast->colonToken, "Expected array of numbers after colon");
|
||||
return;
|
||||
}
|
||||
|
||||
ExpressionStatement *expStmt = dynamic_cast<ExpressionStatement *>(ast->statement);
|
||||
if (!expStmt) {
|
||||
addError(ast->statement->firstSourceLocation(), "Expected array of numbers after colon");
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayLiteral *arrayLit = dynamic_cast<ArrayLiteral *>(expStmt->expression);
|
||||
if (!arrayLit) {
|
||||
addError(expStmt->firstSourceLocation(), "Expected array of numbers after colon");
|
||||
return;
|
||||
}
|
||||
|
||||
int exportIndex = 0;
|
||||
const int exportCount = fmo->exports().size();
|
||||
for (ElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
|
||||
NumericLiteral *numberLit = cast<NumericLiteral *>(it->expression);
|
||||
if (!numberLit) {
|
||||
addError(arrayLit->firstSourceLocation(), "Expected array literal with only number literal members");
|
||||
return;
|
||||
}
|
||||
|
||||
if (exportIndex >= exportCount) {
|
||||
addError(numberLit->firstSourceLocation(), "Meta object revision without matching export");
|
||||
return;
|
||||
}
|
||||
|
||||
const double v = numberLit->value;
|
||||
const int metaObjectRevision = static_cast<int>(v);
|
||||
if (metaObjectRevision != v) {
|
||||
addError(numberLit->firstSourceLocation(), "Expected integer");
|
||||
return;
|
||||
}
|
||||
|
||||
fmo->setExportMetaObjectRevision(exportIndex, metaObjectRevision);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeDescriptionReader::readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme)
|
||||
{
|
||||
if (!ast || !ast->statement) {
|
||||
|
@@ -78,6 +78,7 @@ private:
|
||||
double readNumericBinding(AST::UiScriptBinding *ast);
|
||||
int readIntBinding(AST::UiScriptBinding *ast);
|
||||
void readExports(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
|
||||
void readMetaObjectRevisions(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
|
||||
void readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme);
|
||||
|
||||
void addError(const AST::SourceLocation &loc, const QString &message);
|
||||
|
Reference in New Issue
Block a user