diff options
author | Christian Kamm <[email protected]> | 2011-10-12 08:36:02 +0200 |
---|---|---|
committer | Christian Kamm <[email protected]> | 2011-10-21 08:21:00 +0200 |
commit | 0b75a66407eda8de22f0ab141ccbc976daff44b4 (patch) | |
tree | 70cb46d5cbd4f4d032c956189cb676650b1358d4 /src/libs | |
parent | 55420e2b7070b552fe7790935e56b846d10242f7 (diff) |
QmlJS: Support module apis defined by QML modules.
Change-Id: I18ec9daf8088f7db5ff2da11da14b539f501bab3
Reviewed-by: Fawzi Mohamed <[email protected]>
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/qmljs/qmljsdocument.h | 15 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.cpp | 10 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.h | 2 | ||||
-rw-r--r-- | src/libs/qmljs/qmljslink.cpp | 38 | ||||
-rw-r--r-- | src/libs/qmljs/qmljstypedescriptionreader.cpp | 68 | ||||
-rw-r--r-- | src/libs/qmljs/qmljstypedescriptionreader.h | 9 |
6 files changed, 132 insertions, 10 deletions
diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index 65c500c119d..50e7a81034d 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -128,6 +128,14 @@ private: friend class Snapshot; }; +class QMLJS_EXPORT ModuleApiInfo +{ +public: + QString uri; + LanguageUtils::ComponentVersion version; + QString cppName; +}; + class QMLJS_EXPORT LibraryInfo { public: @@ -152,6 +160,7 @@ private: QList<QmlDirParser::TypeInfo> _typeinfos; typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList; FakeMetaObjectList _metaObjects; + QList<ModuleApiInfo> _moduleApis; PluginTypeInfoStatus _dumpStatus; QString _dumpError; @@ -176,6 +185,12 @@ public: void setMetaObjects(const FakeMetaObjectList &objects) { _metaObjects = objects; } + QList<ModuleApiInfo> moduleApis() const + { return _moduleApis; } + + void setModuleApis(const QList<ModuleApiInfo> &apis) + { _moduleApis = apis; } + bool isValid() const { return _status == Found; } diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index b448212e3d9..3a1ff62e8c2 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -1285,13 +1285,10 @@ CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInf QString error, warning; QFile file(qmlTypeFile.absoluteFilePath()); if (file.open(QIODevice::ReadOnly)) { - QString contents = QString::fromUtf8(file.readAll()); + QByteArray contents = file.readAll(); file.close(); - TypeDescriptionReader reader(contents); - if (!reader(&newObjects)) - error = reader.errorMessage(); - warning = reader.warningMessage(); + parseQmlTypeDescriptions(contents, &newObjects, 0, &error, &warning); } else { error = file.errorString(); } @@ -1312,13 +1309,14 @@ CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInf void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml, BuiltinObjects *newObjects, + QList<ModuleApiInfo> *newModuleApis, QString *errorMessage, QString *warningMessage) { errorMessage->clear(); warningMessage->clear(); TypeDescriptionReader reader(QString::fromUtf8(xml)); - if (!reader(newObjects)) { + if (!reader(newObjects, newModuleApis)) { if (reader.errorMessage().isEmpty()) { *errorMessage = QLatin1String("unknown error"); } else { diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index c914d28d0f8..7b95f2d31fc 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -643,7 +643,7 @@ public: static void parseQmlTypeDescriptions( const QByteArray &qmlTypes, BuiltinObjects *newObjects, - QString *errorMessage, QString *warningMessage); + QList<ModuleApiInfo> *newModuleApis, QString *errorMessage, QString *warningMessage); }; class QMLJS_EXPORT CppQmlTypes diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 3e8cc72f147..0c78ab56c24 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -89,6 +89,8 @@ public: QHash<ImportCacheKey, Import> importCache; + QHash<QString, QList<ModuleApiInfo> > importableModuleApis; + Document::Ptr document; QList<DiagnosticMessage> *diagnosticMessages; @@ -231,6 +233,8 @@ Context::ImportsPerDocument LinkPrivate::linkImports() void LinkPrivate::populateImportedTypes(Imports *imports, Document::Ptr doc) { + importableModuleApis.clear(); + // implicit imports: the <default> package is always available loadImplicitDefaultImports(imports); @@ -315,6 +319,18 @@ Import LinkPrivate::importFileOrDirectory(Document::Ptr doc, const ImportInfo &i return import; } +static ModuleApiInfo findBestModuleApi(const QList<ModuleApiInfo> &apis, const ComponentVersion &version) +{ + ModuleApiInfo best; + foreach (const ModuleApiInfo &moduleApi, apis) { + if (moduleApi.version <= version + && (!best.version.isValid() || best.version < moduleApi.version)) { + best = moduleApi; + } + } + return best; +} + /* import Qt 4.6 import Qt 4.6 as Xxx @@ -372,6 +388,13 @@ Import LinkPrivate::importNonFile(Document::Ptr doc, const ImportInfo &importInf } } + // check module apis that previous imports may have enabled + ModuleApiInfo moduleApi = findBestModuleApi(importableModuleApis.value(packageName), version); + if (moduleApi.version.isValid()) { + importFound = true; + import.object->setPrototype(valueOwner->cppQmlTypes().objectByCppName(moduleApi.name)); + } + if (!importFound && importInfo.ast()) { import.valid = false; error(doc, locationFromRange(importInfo.ast()->firstSourceLocation(), @@ -442,6 +465,21 @@ bool LinkPrivate::importLibrary(Document::Ptr doc, foreach (const CppComponentValue *object, valueOwner->cppQmlTypes().createObjectsForImport(packageName, version)) { import->object->setMember(object->className(), object); } + + // all but no-uri module apis become available for import + QList<ModuleApiInfo> noUriModuleApis; + foreach (const ModuleApiInfo &moduleApi, libraryInfo.moduleApis()) { + if (moduleApi.uri.isEmpty()) { + noUriModuleApis += moduleApi; + } else { + importableModuleApis[moduleApi.uri] += moduleApi; + } + } + + // if a module api has no uri, it shares the same name + ModuleApiInfo sameUriModuleApi = findBestModuleApi(noUriModuleApis, version); + if (sameUriModuleApi.version.isValid()) + import->object->setPrototype(valueOwner->cppQmlTypes().objectByCppName(sameUriModuleApi.name)); } } diff --git a/src/libs/qmljs/qmljstypedescriptionreader.cpp b/src/libs/qmljs/qmljstypedescriptionreader.cpp index 02b7a034653..44b7a47e15f 100644 --- a/src/libs/qmljs/qmljstypedescriptionreader.cpp +++ b/src/libs/qmljs/qmljstypedescriptionreader.cpp @@ -59,7 +59,9 @@ TypeDescriptionReader::~TypeDescriptionReader() { } -bool TypeDescriptionReader::operator()(QHash<QString, FakeMetaObject::ConstPtr> *objects) +bool TypeDescriptionReader::operator()( + QHash<QString, FakeMetaObject::ConstPtr> *objects, + QList<ModuleApiInfo> *moduleApis) { Engine engine; @@ -77,6 +79,7 @@ bool TypeDescriptionReader::operator()(QHash<QString, FakeMetaObject::ConstPtr> } _objects = objects; + _moduleApis = moduleApis; readDocument(parser.ast()); return _errorMessage.isEmpty(); @@ -152,8 +155,11 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast) continue; } - if (typeName == QLatin1String("Component")) + if (typeName == QLatin1String("Component")) { readComponent(component); + } else if (typeName == QLatin1String("ModuleApi")) { + readModuleApi(component); + } } } @@ -226,6 +232,40 @@ void TypeDescriptionReader::readComponent(UiObjectDefinition *ast) _objects->insert(fmo->className(), fmo); } +void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast) +{ + ModuleApiInfo apiInfo; + + for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) { + UiObjectMember *member = it->member; + UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member); + + if (script) { + const QString name = toString(script->qualifiedId); + if (name == "uri") { + apiInfo.uri = readStringBinding(script); + } else if (name == "version") { + apiInfo.version = readNumericVersionBinding(script); + } else if (name == "name") { + apiInfo.name = readStringBinding(script); + } else { + addWarning(script->firstSourceLocation(), + "Expected only uri, version and name script bindings"); + } + } else { + addWarning(member->firstSourceLocation(), "Expected only script bindings"); + } + } + + if (!apiInfo.version.isValid()) { + addError(ast->firstSourceLocation(), "ModuleApi definition has no or invalid 'version' binding"); + return; + } + + if (_moduleApis) + _moduleApis->append(apiInfo); +} + void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod, FakeMetaObject::Ptr fmo) { FakeMetaMethod fmm; @@ -438,6 +478,30 @@ double TypeDescriptionReader::readNumericBinding(AST::UiScriptBinding *ast) return numericLit->value; } +ComponentVersion TypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast) +{ + ComponentVersion invalidVersion; + + if (!ast || !ast->statement) { + addError(ast->colonToken, "Expected numeric literal after colon"); + return invalidVersion; + } + + ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement); + if (!expStmt) { + addError(ast->statement->firstSourceLocation(), "Expected numeric literal after colon"); + return invalidVersion; + } + + NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression); + if (!numericLit) { + addError(expStmt->firstSourceLocation(), "Expected numeric literal after colon"); + return invalidVersion; + } + + return ComponentVersion(_source.mid(numericLit->literalToken.begin(), numericLit->literalToken.length)); +} + int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast) { double v = readNumericBinding(ast); diff --git a/src/libs/qmljs/qmljstypedescriptionreader.h b/src/libs/qmljs/qmljstypedescriptionreader.h index f8e5366e9d2..6292d5f2800 100644 --- a/src/libs/qmljs/qmljstypedescriptionreader.h +++ b/src/libs/qmljs/qmljstypedescriptionreader.h @@ -34,6 +34,8 @@ #define QMLJSTYPEDESCRIPTIONREADER_H #include <languageutils/fakemetaobject.h> +#include <languageutils/componentversion.h> +#include "qmljsdocument.h" // for Q_DECLARE_TR_FUNCTIONS #include <QtCore/QCoreApplication> @@ -60,7 +62,9 @@ public: explicit TypeDescriptionReader(const QString &data); ~TypeDescriptionReader(); - bool operator()(QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects); + bool operator()( + QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects, + QList<ModuleApiInfo> *moduleApis); QString errorMessage() const; QString warningMessage() const; @@ -68,6 +72,7 @@ private: void readDocument(AST::UiProgram *ast); void readModule(AST::UiObjectDefinition *ast); void readComponent(AST::UiObjectDefinition *ast); + void readModuleApi(AST::UiObjectDefinition *ast); void readSignalOrMethod(AST::UiObjectDefinition *ast, bool isMethod, LanguageUtils::FakeMetaObject::Ptr fmo); void readProperty(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo); void readEnum(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo); @@ -76,6 +81,7 @@ private: QString readStringBinding(AST::UiScriptBinding *ast); bool readBoolBinding(AST::UiScriptBinding *ast); double readNumericBinding(AST::UiScriptBinding *ast); + LanguageUtils::ComponentVersion readNumericVersionBinding(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); @@ -88,6 +94,7 @@ private: QString _errorMessage; QString _warningMessage; QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects; + QList<ModuleApiInfo> *_moduleApis; }; } // namespace QmlJS |