diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index c8354a88fa3b27615a2fcfe5669d2a858a48fad9..0e439f46ad92143182ef40af29618fd5f9c9086b 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -40,6 +40,7 @@ #include "parser/qmljsast_p.h" #include <languageutils/fakemetaobject.h> +#include <coreplugin/messagemanager.h> #include <QtCore/QFile> #include <QtCore/QDir> @@ -1580,31 +1581,38 @@ const Value *Function::invoke(const Activation *activation) const QHash<QString, FakeMetaObject::ConstPtr> CppQmlTypesLoader::builtinObjects; QHash<QString, QList<LanguageUtils::ComponentVersion> > CppQmlTypesLoader::builtinPackages; -QStringList CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles) +void CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles) { QHash<QString, FakeMetaObject::ConstPtr> newObjects; - QStringList errorMsgs; + Core::MessageManager *messageManager = Core::MessageManager::instance(); foreach (const QFileInfo &qmlTypeFile, qmlTypeFiles) { + QString error, warning; QFile file(qmlTypeFile.absoluteFilePath()); if (file.open(QIODevice::ReadOnly)) { QString contents = QString::fromUtf8(file.readAll()); file.close(); QmlJS::TypeDescriptionReader reader(contents); - if (!reader(&newObjects)) { - errorMsgs.append(reader.errorMessage()); - } + if (!reader(&newObjects)) + error = reader.errorMessage(); + warning = reader.warningMessage(); } else { - errorMsgs.append(QmlJS::TypeDescriptionReader::tr("%1: %2") - .arg(qmlTypeFile.absoluteFilePath(), - file.errorString())); + error = file.errorString(); + } + if (!error.isEmpty()) { + messageManager->printToOutputPane( + TypeDescriptionReader::tr("Errors while loading qmltypes from %1:\n%2").arg( + qmlTypeFile.absoluteFilePath(), error)); + } + if (!warning.isEmpty()) { + messageManager->printToOutputPane( + TypeDescriptionReader::tr("Warnings while loading qmltypes from %1:\n%2").arg( + qmlTypeFile.absoluteFilePath(), warning)); } } - if (errorMsgs.isEmpty()) { - builtinObjects.unite(newObjects); - } + builtinObjects.unite(newObjects); QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr>::const_iterator iter = builtinObjects.constBegin(); @@ -1617,18 +1625,24 @@ QStringList CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles) } } } - return errorMsgs; } -QString CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml, QHash<QString, FakeMetaObject::ConstPtr> *newObjects) +void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml, + QHash<QString, FakeMetaObject::ConstPtr> *newObjects, + QString *errorMessage, + QString *warningMessage) { + errorMessage->clear(); + warningMessage->clear(); QmlJS::TypeDescriptionReader reader(QString::fromUtf8(xml)); if (!reader(newObjects)) { - if (reader.errorMessage().isEmpty()) - return QLatin1String("unknown error"); - return reader.errorMessage(); + if (reader.errorMessage().isEmpty()) { + *errorMessage = QLatin1String("unknown error"); + } else { + *errorMessage = reader.errorMessage(); + } } - return QString(); + *warningMessage = reader.warningMessage(); } const QLatin1String CppQmlTypes::defaultPackage("<default>"); diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 5c68ca493df765dd2a0b546e98386e1321473fed..b644b9dad196107c6eed0f4d6c0206cd8e9d34a2 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -614,15 +614,19 @@ private: class QMLJS_EXPORT CppQmlTypesLoader { public: - /** \return an empty list when successful, error messages otherwise. */ - static QStringList loadQmlTypes(const QFileInfoList &xmlFiles); + /** Loads a set of qmltypes files into the builtin objects list + and prints any errors to the General Messages pane + */ + static void loadQmlTypes(const QFileInfoList &qmltypesFiles); static QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> builtinObjects; static QHash<QString, QList<LanguageUtils::ComponentVersion> > builtinPackages; - // parses the xml string and fills the newObjects map - static QString parseQmlTypeDescriptions(const QByteArray &xml, - QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *newObjects); + // parses the contents of a qmltypes file and fills the newObjects map + static void parseQmlTypeDescriptions( + const QByteArray &qmlTypes, + QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *newObjects, + QString *errorMessage, QString *warningMessage); }; class QMLJS_EXPORT CppQmlTypes diff --git a/src/libs/qmljs/qmljstypedescriptionreader.cpp b/src/libs/qmljs/qmljstypedescriptionreader.cpp index caecb50731234a19a8ebc12fb660f22ae50a90e8..7768f3352fae0c8210e9927478c446b37cac2282 100644 --- a/src/libs/qmljs/qmljstypedescriptionreader.cpp +++ b/src/libs/qmljs/qmljstypedescriptionreader.cpp @@ -89,6 +89,11 @@ QString TypeDescriptionReader::errorMessage() const return _errorMessage; } +QString TypeDescriptionReader::warningMessage() const +{ + return _warningMessage; +} + void TypeDescriptionReader::readDocument(UiProgram *ast) { if (!ast) { @@ -144,7 +149,7 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast) UiObjectMember *member = it->member; UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member); if (!component || Bind::toString(component->qualifiedTypeNameId) != "Component") { - //addError(member->firstSourceLocation(), "Expected only 'Component' object definitions"); + addWarning(member->firstSourceLocation(), "Expected only 'Component' object definitions"); continue; } @@ -160,6 +165,14 @@ void TypeDescriptionReader::addError(const SourceLocation &loc, const QString &m message); } +void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString &message) +{ + _warningMessage += QString("%1:%2: %3\n").arg( + QString::number(loc.startLine), + QString::number(loc.startColumn), + message); +} + void TypeDescriptionReader::readComponent(UiObjectDefinition *ast) { FakeMetaObject::Ptr fmo(new FakeMetaObject); @@ -177,7 +190,7 @@ void TypeDescriptionReader::readComponent(UiObjectDefinition *ast) } else if (name == "Enum") { readEnum(component, fmo); } else { - //addError(component->firstSourceLocation(), "Expected only Property, Method, Signal and Enum object definitions"); + addWarning(component->firstSourceLocation(), "Expected only Property, Method, Signal and Enum object definitions"); } } else if (script) { QString name = Bind::toString(script->qualifiedId); @@ -192,10 +205,10 @@ void TypeDescriptionReader::readComponent(UiObjectDefinition *ast) } else if (name == "attachedType") { fmo->setAttachedTypeName(readStringBinding(script)); } else { - //addError(script->firstSourceLocation(), "Expected only name, prototype, defaultProperty, attachedType and exports script bindings"); + addWarning(script->firstSourceLocation(), "Expected only name, prototype, defaultProperty, attachedType and exports script bindings"); } } else { - //addError(member->firstSourceLocation(), "Expected only script bindings and object definitions"); + addWarning(member->firstSourceLocation(), "Expected only script bindings and object definitions"); } } @@ -227,7 +240,7 @@ void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isM if (name == "Parameter") { readParameter(component, &fmm); } else { - //addError(component->firstSourceLocation(), "Expected only Parameter object definitions"); + addWarning(component->firstSourceLocation(), "Expected only Parameter object definitions"); } } else if (script) { QString name = Bind::toString(script->qualifiedId); @@ -238,11 +251,11 @@ void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isM } else if (name == "revision") { fmm.setRevision(readIntBinding(script)); } else { - //addError(script->firstSourceLocation(), "Expected only name and type script bindings"); + addWarning(script->firstSourceLocation(), "Expected only name and type script bindings"); } } else { - //addError(member->firstSourceLocation(), "Expected only script bindings and object definitions"); + addWarning(member->firstSourceLocation(), "Expected only script bindings and object definitions"); } } @@ -267,7 +280,7 @@ void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject UiObjectMember *member = it->member; UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member); if (!script) { - //addError(member->firstSourceLocation(), "Expected script binding"); + addWarning(member->firstSourceLocation(), "Expected script binding"); continue; } @@ -285,7 +298,7 @@ void TypeDescriptionReader::readProperty(UiObjectDefinition *ast, FakeMetaObject } else if (id == "revision") { revision = readIntBinding(script); } else { - //addError(script->firstSourceLocation(), "Expected only type, name, revision, isPointer, isReadonly and isList script bindings"); + addWarning(script->firstSourceLocation(), "Expected only type, name, revision, isPointer, isReadonly and isList script bindings"); } } @@ -305,7 +318,7 @@ void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, FakeMetaObject::Pt UiObjectMember *member = it->member; UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member); if (!script) { - //addError(member->firstSourceLocation(), "Expected script binding"); + addWarning(member->firstSourceLocation(), "Expected script binding"); continue; } @@ -315,7 +328,7 @@ void TypeDescriptionReader::readEnum(UiObjectDefinition *ast, FakeMetaObject::Pt } else if (name == "values") { readEnumValues(script, &fme); } else { - //addError(script->firstSourceLocation(), "Expected only name and values script bindings"); + addWarning(script->firstSourceLocation(), "Expected only name and values script bindings"); } } @@ -331,7 +344,7 @@ void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMetho UiObjectMember *member = it->member; UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member); if (!script) { - //addError(member->firstSourceLocation(), "Expected script binding"); + addWarning(member->firstSourceLocation(), "Expected script binding"); continue; } @@ -347,7 +360,7 @@ void TypeDescriptionReader::readParameter(UiObjectDefinition *ast, FakeMetaMetho } else if (id == "isList") { // ### unhandled } else { - //addError(script->firstSourceLocation(), "Expected only name and type script bindings"); + addWarning(script->firstSourceLocation(), "Expected only name and type script bindings"); } } diff --git a/src/libs/qmljs/qmljstypedescriptionreader.h b/src/libs/qmljs/qmljstypedescriptionreader.h index 136bb04ed596a1b5785473b128b21e9de076ef24..647f333a729edd5e9ac3f2dc66aab66fe7d01cce 100644 --- a/src/libs/qmljs/qmljstypedescriptionreader.h +++ b/src/libs/qmljs/qmljstypedescriptionreader.h @@ -64,6 +64,7 @@ public: bool operator()(QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects); QString errorMessage() const; + QString warningMessage() const; private: void readDocument(AST::UiProgram *ast); @@ -80,10 +81,13 @@ private: int readIntBinding(AST::UiScriptBinding *ast); void readExports(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo); void readEnumValues(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaEnum *fme); + void addError(const AST::SourceLocation &loc, const QString &message); + void addWarning(const AST::SourceLocation &loc, const QString &message); QString _source; QString _errorMessage; + QString _warningMessage; QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects; }; diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index ded28bc7db4ddbd55addec48343d7b68af0752b7..6a48b6fea9c942355a28849f62ac9fec9f233df3 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -118,9 +118,7 @@ void ModelManager::loadQmlTypeDescriptions(const QString &resourcePath) QDir::Files, QDir::Name); - const QStringList errors = Interpreter::CppQmlTypesLoader::loadQmlTypes(qmlTypesFiles); - foreach (const QString &error, errors) - qWarning() << qPrintable(error); + Interpreter::CppQmlTypesLoader::loadQmlTypes(qmlTypesFiles); // disabled for now: Prefer the xml file until the type dumping functionality // has been moved into Qt. diff --git a/src/plugins/qmljstools/qmljsplugindumper.cpp b/src/plugins/qmljstools/qmljsplugindumper.cpp index 6ad21f2a1e96f8ff98197b084f2fdcf158095c9d..ab010c28e67e344f593bd8dad706548a050fb3c2 100644 --- a/src/plugins/qmljstools/qmljsplugindumper.cpp +++ b/src/plugins/qmljstools/qmljsplugindumper.cpp @@ -147,11 +147,22 @@ static QString qmldumpFailedMessage(const QString &error) ).arg(firstLines); } -static QList<FakeMetaObject::ConstPtr> parseHelper(const QByteArray &qmlTypeDescriptions, QString *error) +static void printParseWarnings(const QString &libraryPath, const QString &warning) +{ + Core::MessageManager *messageManager = Core::MessageManager::instance(); + messageManager->printToOutputPane( + PluginDumper::tr("Warnings while parsing qmltypes information of %1:\n" + "%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; - *error = Interpreter::CppQmlTypesLoader::parseQmlTypeDescriptions(qmlTypeDescriptions, &newObjects); + Interpreter::CppQmlTypesLoader::parseQmlTypeDescriptions(qmlTypeDescriptions, &newObjects, + error, warning); if (error->isEmpty()) { ret = newObjects.values(); @@ -179,17 +190,21 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode) const QByteArray output = process->readAllStandardOutput(); QString error; - QList<FakeMetaObject::ConstPtr> objectsList = parseHelper(output, &error); - if (exitCode == 0 && !error.isEmpty()) { - libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, tr("Type dump of C++ plugin failed. Parse error:\n'%1'").arg(error)); - } + QString warning; + QList<FakeMetaObject::ConstPtr> objectsList = parseHelper(output, &error, &warning); + if (exitCode == 0) { + if (!error.isEmpty()) { + libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, tr("Type dump of C++ plugin failed. Parse error:\n'%1'").arg(error)); + } else { + libraryInfo.setMetaObjects(objectsList); + // ### disabled code path for running qmldump to get Qt's builtins + // if (libraryPath.isEmpty()) + // Interpreter::CppQmlTypesLoader::builtinObjects.append(objectsList); + libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpDone); + } - if (exitCode == 0 && error.isEmpty()) { - libraryInfo.setMetaObjects(objectsList); -// ### disabled code path for running qmldump to get Qt's builtins -// if (libraryPath.isEmpty()) -// Interpreter::CppQmlTypesLoader::builtinObjects.append(objectsList); - libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpDone); + if (!warning.isEmpty()) + printParseWarnings(libraryPath, warning); } if (!libraryPath.isEmpty()) @@ -244,7 +259,8 @@ void PluginDumper::dump(const Plugin &plugin) } QString error; - const QList<FakeMetaObject::ConstPtr> objectsList = parseHelper(reader.data(), &error); + QString warning; + const QList<FakeMetaObject::ConstPtr> objectsList = parseHelper(reader.data(), &error, &warning); if (error.isEmpty()) { libraryInfo.setMetaObjects(objectsList); @@ -253,6 +269,9 @@ void PluginDumper::dump(const Plugin &plugin) libraryInfo.setPluginTypeInfoStatus(LibraryInfo::TypeInfoFileError, tr("Failed to parse '%1'.\nError: %2").arg(path, error)); } + if (!warning.isEmpty()) + printParseWarnings(plugin.qmldirPath, warning); + m_modelManager->updateLibraryInfo(plugin.qmldirPath, libraryInfo); return; }