forked from qt-creator/qt-creator
		
	QmlJS: Support module apis defined by QML modules.
Change-Id: I18ec9daf8088f7db5ff2da11da14b539f501bab3 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
		| @@ -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; } | ||||
|  | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user