Commit fdd0a15e authored by Christian Kamm's avatar Christian Kamm
Browse files

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: default avatarFawzi Mohamed <fawzi.mohamed@nokia.com>
parent 22e2c0ad
......@@ -157,11 +157,14 @@ void FakeMetaObject::addExport(const QString &name, const QString &package, Comp
exp.type = name;
exp.package = package;
exp.version = version;
exp.packageNameVersion = QString::fromLatin1("%1/%2 %3").arg(
package, name,
version.toString());
m_exports.append(exp);
}
void FakeMetaObject::setExportMetaObjectRevision(int exportIndex, int metaObjectRevision)
{
m_exports[exportIndex].metaObjectRevision = metaObjectRevision;
}
QList<FakeMetaObject::Export> FakeMetaObject::exports() const
{ return m_exports; }
FakeMetaObject::Export FakeMetaObject::exportInPackage(const QString &package) const
......@@ -219,5 +222,8 @@ QString FakeMetaObject::attachedTypeName() const
void FakeMetaObject::setAttachedTypeName(const QString &name)
{ m_attachedTypeName = name; }
FakeMetaObject::Export::Export()
: metaObjectRevision(0)
{}
bool FakeMetaObject::Export::isValid() const
{ return !type.isEmpty(); }
{ return version.isValid() || !package.isEmpty() || !type.isEmpty(); }
......@@ -139,10 +139,12 @@ public:
class LANGUAGEUTILS_EXPORT Export {
public:
Export();
QString package;
QString type;
ComponentVersion version;
QString packageNameVersion;
int metaObjectRevision;
bool isValid() const;
};
......@@ -166,6 +168,7 @@ public:
void setClassName(const QString &name);
void addExport(const QString &name, const QString &package, ComponentVersion version);
void setExportMetaObjectRevision(int exportIndex, int metaObjectRevision);
QList<Export> exports() const;
Export exportInPackage(const QString &package) const;
......
......@@ -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);
......
......@@ -473,7 +473,7 @@ const QmlJS::QmlObjectValue *NodeMetaInfoPrivate::getQmlObjectValue() const
// otherwise get the qml object value that's available in the document
foreach (const QmlJS::Import &import, context()->imports(document())->all()) {
if (import.info.name() != module)
if (import.info.path() != module)
continue;
const Value *lookupResult = import.object->lookupMember(type, context());
if ((value = dynamic_cast<const QmlObjectValue *>(lookupResult)))
......@@ -692,7 +692,9 @@ bool NodeMetaInfoPrivate::cleverCheckType(const QString &otherType) const
const LanguageUtils::FakeMetaObject::Export exp =
qmlObjectValue->metaObject()->exportInPackage(package);
const QString convertedName = exp.type;
QString convertedName = exp.type;
if (convertedName.isEmpty())
convertedName = qmlObjectValue->className();
return typeName == convertedName;
}
......
......@@ -386,12 +386,12 @@ public:
const Imports *imports = m_context->imports(m_doc.data());
ImportInfo importInfo = imports->info(fullTypeName, m_context.data());
if (importInfo.isValid() && importInfo.type() == ImportInfo::LibraryImport) {
QString name = importInfo.name().replace("\\", ".");
QString name = importInfo.name();
majorVersion = importInfo.version().majorVersion();
minorVersion = importInfo.version().minorVersion();
typeName.prepend(name + ".");
} else if (importInfo.isValid() && importInfo.type() == ImportInfo::DirectoryImport) {
QString path = importInfo.name();
QString path = importInfo.path();
QDir dir(m_doc->path());
QString relativeDir = dir.relativeFilePath(path);
QString name = relativeDir.replace("/", ".");
......
......@@ -1302,7 +1302,7 @@ TextEditor::BaseTextEditorWidget::Link QmlJSTextEditorWidget::findLinkAt(const Q
// if it's a file import, link to the file
foreach (const ImportInfo &import, semanticInfo.document->bind()->imports()) {
if (import.ast() == importAst && import.type() == ImportInfo::FileImport) {
BaseTextEditorWidget::Link link(import.name());
BaseTextEditorWidget::Link link(import.path());
link.begin = importAst->firstSourceLocation().begin();
link.end = importAst->lastSourceLocation().end();
return link;
......
......@@ -253,7 +253,7 @@ void HoverHandler::handleImport(const ScopeChain &scopeChain, AST::UiImport *nod
}
setToolTip(msg);
} else {
setToolTip(import.info.name());
setToolTip(import.info.path());
}
break;
}
......
......@@ -418,7 +418,7 @@ static void findNewFileImports(const Document::Ptr &doc, const Snapshot &snapsho
{
// scan files and directories that are explicitly imported
foreach (const ImportInfo &import, doc->bind()->imports()) {
const QString &importName = import.name();
const QString &importName = import.path();
if (import.type() == ImportInfo::FileImport) {
if (! snapshot.document(importName))
*importedFiles += importName;
......@@ -530,7 +530,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
const QStringList importPaths = modelManager->importPaths();
foreach (const ImportInfo &import, doc->bind()->imports()) {
if (import.type() == ImportInfo::DirectoryImport) {
const QString targetPath = import.name();
const QString targetPath = import.path();
findNewQmlLibraryInPath(targetPath, snapshot, modelManager,
importedFiles, scannedPaths, newLibraries);
}
......@@ -539,7 +539,7 @@ static void findNewLibraryImports(const Document::Ptr &doc, const Snapshot &snap
if (!import.version().isValid())
continue;
foreach (const QString &importPath, importPaths) {
const QString targetPath = QDir(importPath).filePath(import.name());
const QString targetPath = QDir(importPath).filePath(import.path());
findNewQmlLibrary(targetPath, import.version(), snapshot, modelManager,
importedFiles, scannedPaths, newLibraries);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment