summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2011-10-12 08:36:02 +0200
committerChristian Kamm <christian.d.kamm@nokia.com>2011-10-21 08:21:00 +0200
commit0b75a66407eda8de22f0ab141ccbc976daff44b4 (patch)
tree70cb46d5cbd4f4d032c956189cb676650b1358d4 /src
parent55420e2b7070b552fe7790935e56b846d10242f7 (diff)
downloadqt-creator-0b75a66407eda8de22f0ab141ccbc976daff44b4.tar.gz
QmlJS: Support module apis defined by QML modules.
Change-Id: I18ec9daf8088f7db5ff2da11da14b539f501bab3 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/libs/qmljs/qmljsdocument.h15
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp10
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h2
-rw-r--r--src/libs/qmljs/qmljslink.cpp38
-rw-r--r--src/libs/qmljs/qmljstypedescriptionreader.cpp68
-rw-r--r--src/libs/qmljs/qmljstypedescriptionreader.h9
-rw-r--r--src/plugins/qmljstools/qmljsplugindumper.cpp34
7 files changed, 147 insertions, 29 deletions
diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h
index 65c500c119..50e7a81034 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 b448212e3d..3a1ff62e8c 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 c914d28d0f..7b95f2d31f 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 3e8cc72f14..0c78ab56c2 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 02b7a03465..44b7a47e15 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 f8e5366e9d..6292d5f280 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
diff --git a/src/plugins/qmljstools/qmljsplugindumper.cpp b/src/plugins/qmljstools/qmljsplugindumper.cpp
index 921d8b994c..a574eb989f 100644
--- a/src/plugins/qmljstools/qmljsplugindumper.cpp
+++ b/src/plugins/qmljstools/qmljsplugindumper.cpp
@@ -257,21 +257,6 @@ static void printParseWarnings(const QString &libraryPath, const QString &warnin
"%2").arg(libraryPath, warning));
}
-static QList<FakeMetaObject::ConstPtr> parseHelper(const QByteArray &qmlTypeDescriptions,
- QString *error,
- QString *warning)
-{
- QList<FakeMetaObject::ConstPtr> ret;
- QHash<QString, FakeMetaObject::ConstPtr> newObjects;
- CppQmlTypesLoader::parseQmlTypeDescriptions(qmlTypeDescriptions, &newObjects,
- error, warning);
-
- if (error->isEmpty()) {
- ret = newObjects.values();
- }
- return ret;
-}
-
void PluginDumper::qmlPluginTypeDumpDone(int exitCode)
{
QProcess *process = qobject_cast<QProcess *>(sender());
@@ -295,13 +280,16 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode)
const QByteArray output = process->readAllStandardOutput();
QString error;
QString warning;
- QList<FakeMetaObject::ConstPtr> objectsList = parseHelper(output, &error, &warning);
+ CppQmlTypesLoader::BuiltinObjects objectsList;
+ QList<ModuleApiInfo> moduleApis;
+ CppQmlTypesLoader::parseQmlTypeDescriptions(output, &objectsList, &moduleApis, &error, &warning);
if (exitCode == 0) {
if (!error.isEmpty()) {
libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError,
qmldumpErrorMessage(libraryPath, error));
} else {
- libraryInfo.setMetaObjects(objectsList);
+ libraryInfo.setMetaObjects(objectsList.values());
+ libraryInfo.setModuleApis(moduleApis);
libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpDone);
}
@@ -352,6 +340,7 @@ void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths,
QStringList errors;
QStringList warnings;
QList<FakeMetaObject::ConstPtr> objects;
+ QList<ModuleApiInfo> moduleApis;
foreach (const QString &qmltypesFilePath, qmltypesFilePaths) {
Utils::FileReader reader;
@@ -362,14 +351,21 @@ void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths,
QString error;
QString warning;
- objects += parseHelper(reader.data(), &error, &warning);
- if (!error.isEmpty())
+ CppQmlTypesLoader::BuiltinObjects newObjects;
+ QList<ModuleApiInfo> newModuleApis;
+ CppQmlTypesLoader::parseQmlTypeDescriptions(reader.data(), &newObjects, &newModuleApis, &error, &warning);
+ if (!error.isEmpty()) {
errors += tr("Failed to parse '%1'.\nError: %2").arg(qmltypesFilePath, error);
+ } else {
+ objects += newObjects.values();
+ moduleApis += newModuleApis;
+ }
if (!warning.isEmpty())
warnings += warning;
}
libraryInfo.setMetaObjects(objects);
+ libraryInfo.setModuleApis(moduleApis);
if (errors.isEmpty()) {
libraryInfo.setPluginTypeInfoStatus(LibraryInfo::TypeInfoFileDone);
} else {