diff options
author | Marco Benelli <marco.benelli@theqtcompany.com> | 2016-02-26 17:28:30 +0100 |
---|---|---|
committer | Marco Benelli <marco.benelli@theqtcompany.com> | 2016-04-19 11:18:21 +0000 |
commit | 22acc52d71120bccb7fe9bb4390801e44a8ab379 (patch) | |
tree | d6068f0e2032d1e52c3b20d5344808ee5795e499 | |
parent | 94cba885bde551cad5d58da0b6a70049c924ec2a (diff) | |
download | qt-creator-22acc52d71120bccb7fe9bb4390801e44a8ab379.tar.gz |
Qml code model: handle modules dependencies.
Fix the broken hierarchies between qml objects.
Change-Id: Id36c735cab0129af382fab7b9dd90c228304168c
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
Reviewed-by: Alessandro Portale <alessandro.portale@theqtcompany.com>
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsdocument.cpp | 1 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsdocument.h | 7 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.cpp | 12 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.h | 8 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsplugindumper.cpp | 133 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsplugindumper.h | 9 | ||||
-rw-r--r-- | src/libs/qmljs/qmljstypedescriptionreader.cpp | 31 | ||||
-rw-r--r-- | src/libs/qmljs/qmljstypedescriptionreader.h | 5 | ||||
-rw-r--r-- | tests/auto/qml/codemodel/codemodel.pro | 4 | ||||
-rw-r--r-- | tests/auto/qml/codemodel/dependencies/dependencies.pro | 20 | ||||
-rw-r--r-- | tests/auto/qml/codemodel/dependencies/samples/001_ApplicationWindow.qml | 35 | ||||
-rw-r--r-- | tests/auto/qml/codemodel/dependencies/samples/002_Window.qml | 34 | ||||
-rw-r--r-- | tests/auto/qml/codemodel/dependencies/samples/SampleLib.qml | 32 | ||||
-rw-r--r-- | tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp | 153 |
15 files changed, 458 insertions, 27 deletions
diff --git a/.gitignore b/.gitignore index f100f3152c..92f7b6f6f5 100644 --- a/.gitignore +++ b/.gitignore @@ -187,6 +187,7 @@ tmp/ /tests/auto/ioutils/tst_ioutils /tests/auto/profilewriter/tst_profilewriter /tests/auto/qml/codemodel/check/tst_codemodel_check +/tests/auto/qml/codemodel/dependencies/tst_dependencies /tests/auto/qml/persistenttrie/tst_trie_check /tests/auto/qml/qmldesigner/bauhaustests/tst_bauhaus /tests/auto/qml/qmldesigner/coretests/tst_qmldesigner_core diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index b61f44ca08..82cf503666 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -519,6 +519,7 @@ void Snapshot::insertLibraryInfo(const QString &path, const LibraryInfo &info) foreach (const Export &e, cImport.possibleExports) _dependencies.addExport(component.fileName, e.exportName, e.pathRequired, e.typeName); } + cImport.fingerprint = info.fingerprint(); _dependencies.addCoreImport(cImport); } diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index 0c39b52c02..5328fbe609 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -154,6 +154,7 @@ private: typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList; FakeMetaObjectList _metaObjects; QList<ModuleApiInfo> _moduleApis; + QStringList _dependencies; QByteArray _fingerprint; PluginTypeInfoStatus _dumpStatus; @@ -190,6 +191,12 @@ public: void setModuleApis(const QList<ModuleApiInfo> &apis) { _moduleApis = apis; } + QStringList dependencies() const + { return _dependencies; } + + void setDependencies(const QStringList &deps) + { _dependencies = deps; } + bool isValid() const { return _status == Found; } diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 078ee96ad8..b0d097beb4 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -1117,11 +1117,13 @@ const Value *ObjectValue::lookupMember(const QString &name, const Context *conte } } + const ObjectValue *prototypeObject = 0; + if (examinePrototypes && context) { PrototypeIterator iter(this, context); iter.next(); // skip this while (iter.hasNext()) { - const ObjectValue *prototypeObject = iter.next(); + prototypeObject = iter.next(); if (const Value *m = prototypeObject->lookupMember(name, context, foundInObject, false)) return m; } @@ -1129,6 +1131,7 @@ const Value *ObjectValue::lookupMember(const QString &name, const Context *conte if (foundInObject) *foundInObject = 0; + return 0; } @@ -1346,6 +1349,7 @@ CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::defaultQtObjects; CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInfoList &qmlTypeFiles, QStringList *errors, QStringList *warnings) { QHash<QString, FakeMetaObject::ConstPtr> newObjects; + QStringList newDependencies; foreach (const QFileInfo &qmlTypeFile, qmlTypeFiles) { QString error, warning; @@ -1355,7 +1359,8 @@ CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInf file.close(); - parseQmlTypeDescriptions(contents, &newObjects, 0, &error, &warning, qmlTypeFile.absoluteFilePath()); + parseQmlTypeDescriptions(contents, &newObjects, 0, &newDependencies, &error, &warning, + qmlTypeFile.absoluteFilePath()); } else { error = file.errorString(); } @@ -1377,6 +1382,7 @@ CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInf void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &contents, BuiltinObjects *newObjects, QList<ModuleApiInfo> *newModuleApis, + QStringList *newDependencies, QString *errorMessage, QString *warningMessage, const QString &fileName) { @@ -1396,7 +1402,7 @@ void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &contents, errorMessage->clear(); warningMessage->clear(); TypeDescriptionReader reader(fileName, QString::fromUtf8(contents)); - if (!reader(newObjects, newModuleApis)) { + if (!reader(newObjects, newModuleApis, newDependencies)) { if (reader.errorMessage().isEmpty()) *errorMessage = QLatin1String("unknown error"); else diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index f6a143a49e..806b858f39 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -720,8 +720,12 @@ public: // parses the contents of a qmltypes file and fills the newObjects map static void parseQmlTypeDescriptions(const QByteArray &contents, - BuiltinObjects *newObjects, - QList<ModuleApiInfo> *newModuleApis, QString *errorMessage, QString *warningMessage, const QString &fileName); + BuiltinObjects *newObjects, + QList<ModuleApiInfo> *newModuleApis, + QStringList *newDependencies, + QString *errorMessage, + QString *warningMessage, + const QString &fileName); }; class QMLJS_EXPORT FakeMetaObjectWithOrigin diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index aa08ec044d..555b77671a 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -27,6 +27,7 @@ #include "qmljsmodelmanagerinterface.h" #include <qmljs/qmljsinterpreter.h> +#include <qmljs/qmljsviewercontext.h> //#include <projectexplorer/session.h> //#include <coreplugin/messagemanager.h> #include <utils/filesystemwatcher.h> @@ -309,7 +310,9 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode) QString warning; CppQmlTypesLoader::BuiltinObjects objectsList; QList<ModuleApiInfo> moduleApis; - CppQmlTypesLoader::parseQmlTypeDescriptions(output, &objectsList, &moduleApis, &error, &warning, + QStringList dependencies; + CppQmlTypesLoader::parseQmlTypeDescriptions(output, &objectsList, &moduleApis, &dependencies, + &error, &warning, QLatin1String("<dump of ") + libraryPath + QLatin1Char('>')); if (exitCode == 0) { if (!error.isEmpty()) { @@ -361,39 +364,131 @@ void PluginDumper::pluginChanged(const QString &pluginLibrary) dump(plugin); } -void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths, - const QString &libraryPath, - QmlJS::LibraryInfo libraryInfo) -{ - QStringList errors; - QStringList warnings; - QList<FakeMetaObject::ConstPtr> objects; - QList<ModuleApiInfo> moduleApis; - - foreach (const QString &qmltypesFilePath, qmltypesFilePaths) { +void PluginDumper::loadQmlTypeDescription(const QStringList &paths, + QStringList &errors, + QStringList &warnings, + QList<FakeMetaObject::ConstPtr> &objects, + QList<ModuleApiInfo> *moduleApi, + QStringList *dependencies) const { + for (const QString &p: paths) { Utils::FileReader reader; - if (!reader.fetch(qmltypesFilePath, QFile::Text)) { + if (!reader.fetch(p, QFile::Text)) { errors += reader.errorString(); continue; } - QString error; QString warning; - CppQmlTypesLoader::BuiltinObjects newObjects; - QList<ModuleApiInfo> newModuleApis; - CppQmlTypesLoader::parseQmlTypeDescriptions(reader.data(), &newObjects, &newModuleApis, &error, &warning, qmltypesFilePath); + CppQmlTypesLoader::BuiltinObjects objs; + QList<ModuleApiInfo> apis; + QStringList deps; + CppQmlTypesLoader::parseQmlTypeDescriptions(reader.data(), &objs, &apis, &deps, + &error, &warning, p); if (!error.isEmpty()) { - errors += tr("Failed to parse \"%1\".\nError: %2").arg(qmltypesFilePath, error); + errors += tr("Failed to parse \"%1\".\nError: %2").arg(p, error); } else { - objects += newObjects.values(); - moduleApis += newModuleApis; + objects += objs.values(); + if (moduleApi) + *moduleApi += apis; + if (!deps.isEmpty()) + *dependencies += deps; } if (!warning.isEmpty()) warnings += warning; } +} +/*! + * \brief Build the path of an existing qmltypes file from a module name. + * \param name + * \return the module's qmltypes file path + * + * Look for \a name qmltypes file in model manager's import paths. + * For each import path the following files are searched, in this order: + * + * - <name>.<major>.<minor>/plugins.qmltypes + * - <name>.<major>/plugins.qmltypes + * - <name>/plugins.qmltypes + * + * That means that a more qualified directory name has precedence over a + * less qualified one. Be aware that the import paths order has a stronger + * precedence, so a less qualified name could shadow a more qualified one if + * it resides in a different import path. + * + * \sa LinkPrivate::importNonFile + */ +QString PluginDumper::buildQmltypesPath(const QString &name) const +{ + QStringList importName = name.split(QLatin1Char(' ')); + QString qualifiedName = importName[0]; + QString majorVersion; + QString minorVersion; + if (importName.length() == 2) { + QString versionString = importName[1]; + QStringList version = versionString.split(QLatin1Char('.')); + if (version.length() == 2) { + majorVersion = version[0]; + minorVersion = version[1]; + } + } + + for (const PathAndLanguage &p: m_modelManager->importPaths()) { + QString moduleName(qualifiedName.replace(QLatin1Char('.'), QLatin1Char('/'))); + QString moduleNameMajor(moduleName + QLatin1Char('.') + majorVersion); + QString moduleNameMajorMinor(moduleNameMajor + QLatin1Char('.') + minorVersion); + + for (const auto n: QStringList{moduleNameMajorMinor, moduleNameMajor, moduleName}) { + QString filename(p.path().toString() + QLatin1Char('/') + n + + QLatin1String("/plugins.qmltypes")); + if (QFile::exists(filename)) + return filename; + } + } + return QString(); +} + +/*! + * \brief Recursively load dependencies. + * \param dependencies + * \param errors + * \param warnings + * \param objects + * + * Recursively load type descriptions of dependencies, collecting results + * in \a objects. + */ +void PluginDumper::loadDependencies(const QStringList &dependencies, + QStringList &errors, + QStringList &warnings, + QList<FakeMetaObject::ConstPtr> &objects) const +{ + QStringList dependenciesPaths; + QString path; + for (const QString &name: dependencies) { + path = buildQmltypesPath(name); + if (!path.isNull()) + dependenciesPaths << path; + } + QStringList newDependencies; + loadQmlTypeDescription(dependenciesPaths, errors, warnings, objects, 0, &newDependencies); + if (!newDependencies.isEmpty()) + loadDependencies(newDependencies, errors, warnings, objects); +} + +void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths, + const QString &libraryPath, + QmlJS::LibraryInfo libraryInfo) +{ + QStringList errors; + QStringList warnings; + QList<FakeMetaObject::ConstPtr> objects; + QList<ModuleApiInfo> moduleApis; + QStringList dependencies; + + loadQmlTypeDescription(qmltypesFilePaths, errors, warnings, objects, &moduleApis, &dependencies); + loadDependencies(dependencies, errors, warnings, objects); libraryInfo.setMetaObjects(objects); libraryInfo.setModuleApis(moduleApis); + libraryInfo.setDependencies(dependencies); if (errors.isEmpty()) { libraryInfo.setPluginTypeInfoStatus(LibraryInfo::TypeInfoFileDone); } else { diff --git a/src/libs/qmljs/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h index f0a716df9c..31c9b5e019 100644 --- a/src/libs/qmljs/qmljsplugindumper.h +++ b/src/libs/qmljs/qmljsplugindumper.h @@ -75,6 +75,15 @@ private: void runQmlDump(const QmlJS::ModelManagerInterface::ProjectInfo &info, const QStringList &arguments, const QString &importPath); void dump(const Plugin &plugin); + void loadQmlTypeDescription(const QStringList &path, QStringList &errors, QStringList &warnings, + QList<LanguageUtils::FakeMetaObject::ConstPtr> &objects, + QList<ModuleApiInfo> *moduleApi, + QStringList *dependencies) const; + QString buildQmltypesPath(const QString &name) const; + void loadDependencies(const QStringList &dependencies, + QStringList &errors, + QStringList &warnings, + QList<LanguageUtils::FakeMetaObject::ConstPtr> &objects) const; void loadQmltypesFile(const QStringList &qmltypesFilePaths, const QString &libraryPath, QmlJS::LibraryInfo libraryInfo); diff --git a/src/libs/qmljs/qmljstypedescriptionreader.cpp b/src/libs/qmljs/qmljstypedescriptionreader.cpp index 5ada19fe12..ea660cd2ee 100644 --- a/src/libs/qmljs/qmljstypedescriptionreader.cpp +++ b/src/libs/qmljs/qmljstypedescriptionreader.cpp @@ -52,7 +52,8 @@ TypeDescriptionReader::~TypeDescriptionReader() bool TypeDescriptionReader::operator()( QHash<QString, FakeMetaObject::ConstPtr> *objects, - QList<ModuleApiInfo> *moduleApis) + QList<ModuleApiInfo> *moduleApis, + QStringList *dependencies) { Engine engine; @@ -71,6 +72,7 @@ bool TypeDescriptionReader::operator()( _objects = objects; _moduleApis = moduleApis; + _dependencies = dependencies; readDocument(parser.ast()); return _errorMessage.isEmpty(); @@ -141,6 +143,12 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast) UiObjectMember *member = it->member; UiObjectDefinition *component = dynamic_cast<UiObjectDefinition *>(member); + UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member); + if (script && (toString(script->qualifiedId) == QStringLiteral("dependencies"))) { + readDependencies(script); + continue; + } + QString typeName; if (component) typeName = toString(component->qualifiedTypeNameId); @@ -174,6 +182,27 @@ void TypeDescriptionReader::addWarning(const SourceLocation &loc, const QString message); } +void TypeDescriptionReader::readDependencies(UiScriptBinding *ast) { + ExpressionStatement *stmt = dynamic_cast<ExpressionStatement*>(ast->statement); + if (!stmt) { + addError(ast->statement->firstSourceLocation(), tr("Expected dependency definitions")); + return; + } + ArrayLiteral *exp = dynamic_cast<ArrayLiteral *>(stmt->expression); + if (!exp) { + addError(stmt->expression->firstSourceLocation(), tr("Expected dependency definitions")); + return; + } + for (ElementList *l = exp->elements; l; l = l->next) { + StringLiteral *str = dynamic_cast<StringLiteral *>(l->expression); + if (!exp) { + addWarning(l->expression->firstSourceLocation(), + tr("Cannot read dependency: skipping.")); + } + *_dependencies << str->value.toString(); + } +} + void TypeDescriptionReader::readComponent(UiObjectDefinition *ast) { FakeMetaObject::Ptr fmo(new FakeMetaObject); diff --git a/src/libs/qmljs/qmljstypedescriptionreader.h b/src/libs/qmljs/qmljstypedescriptionreader.h index 85829d04ee..900ec38304 100644 --- a/src/libs/qmljs/qmljstypedescriptionreader.h +++ b/src/libs/qmljs/qmljstypedescriptionreader.h @@ -58,13 +58,15 @@ public: bool operator()( QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects, - QList<ModuleApiInfo> *moduleApis); + QList<ModuleApiInfo> *moduleApis, + QStringList *dependencies); QString errorMessage() const; QString warningMessage() const; private: void readDocument(AST::UiProgram *ast); void readModule(AST::UiObjectDefinition *ast); + void readDependencies(AST::UiScriptBinding *ast); void readComponent(AST::UiObjectDefinition *ast); void readModuleApi(AST::UiObjectDefinition *ast); void readSignalOrMethod(AST::UiObjectDefinition *ast, bool isMethod, LanguageUtils::FakeMetaObject::Ptr fmo); @@ -90,6 +92,7 @@ private: QString _warningMessage; QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects; QList<ModuleApiInfo> *_moduleApis; + QStringList *_dependencies; }; } // namespace QmlJS diff --git a/tests/auto/qml/codemodel/codemodel.pro b/tests/auto/qml/codemodel/codemodel.pro index 2e42b5cb7c..61114626c1 100644 --- a/tests/auto/qml/codemodel/codemodel.pro +++ b/tests/auto/qml/codemodel/codemodel.pro @@ -1,4 +1,6 @@ TEMPLATE = subdirs SUBDIRS += check \ - importscheck + importscheck \ + dependencies + diff --git a/tests/auto/qml/codemodel/dependencies/dependencies.pro b/tests/auto/qml/codemodel/dependencies/dependencies.pro new file mode 100644 index 0000000000..b56dfdbe6d --- /dev/null +++ b/tests/auto/qml/codemodel/dependencies/dependencies.pro @@ -0,0 +1,20 @@ +QTC_LIB_DEPENDS += qmljs +QTC_PLUGIN_DEPENDS += qmljstools + +include(../../../qttest.pri) + +DEFINES+=QTCREATORDIR=\\\"$$IDE_SOURCE_TREE\\\" +DEFINES+=TESTSRCDIR=\\\"$$PWD\\\" + +QT += core +QT -= gui + +CONFIG += c++11 + +TARGET = tst_dependencies +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += tst_dependencies.cpp diff --git a/tests/auto/qml/codemodel/dependencies/samples/001_ApplicationWindow.qml b/tests/auto/qml/codemodel/dependencies/samples/001_ApplicationWindow.qml new file mode 100644 index 0000000000..6c55b2e8ab --- /dev/null +++ b/tests/auto/qml/codemodel/dependencies/samples/001_ApplicationWindow.qml @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Controls 1.3 + +ApplicationWindow { + title: qsTr("Hello World") + width: 640 + height: 480 + visible: true +} + diff --git a/tests/auto/qml/codemodel/dependencies/samples/002_Window.qml b/tests/auto/qml/codemodel/dependencies/samples/002_Window.qml new file mode 100644 index 0000000000..71dbbd2b7b --- /dev/null +++ b/tests/auto/qml/codemodel/dependencies/samples/002_Window.qml @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Controls 1.3 + +Window { + title: qsTr("Hello World") + width: 640 + height: 480 + visible: true +} diff --git a/tests/auto/qml/codemodel/dependencies/samples/SampleLib.qml b/tests/auto/qml/codemodel/dependencies/samples/SampleLib.qml new file mode 100644 index 0000000000..2495247708 --- /dev/null +++ b/tests/auto/qml/codemodel/dependencies/samples/SampleLib.qml @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.4 +import QtQuick.Controls 1.4 + +TreeView { + id: lib +} + diff --git a/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp b/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp new file mode 100644 index 0000000000..ffa9e2f1eb --- /dev/null +++ b/tests/auto/qml/codemodel/dependencies/tst_dependencies.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include <QString> +#include <QStringList> +#include <QFutureInterface> +#include <QFile> +#include <QTextStream> +#include <QDateTime> +#include <QLibraryInfo> +#include <QtTest> + +#include <QDebug> + +#include <qmljs/qmljsinterpreter.h> +#include <qmljs/qmljsdocument.h> +#include <qmljs/qmljsbind.h> +#include <qmljs/qmljslink.h> +#include <qmljs/qmljscontext.h> +#include <qmljs/qmljsviewercontext.h> +#include <qmljs/qmljscheck.h> +#include <qmljs/qmljsimportdependencies.h> +#include <qmljs/parser/qmljsast_p.h> +#include <qmljs/parser/qmljsengine_p.h> +#include <qmljs/qmljsmodelmanagerinterface.h> +#include <qmljstools/qmljssemanticinfo.h> +#include <extensionsystem/pluginmanager.h> + +using namespace QmlJS; +using namespace QmlJS::AST; +using namespace QmlJS::StaticAnalysis; + +static Document::MutablePtr readDocument(const QString &path) +{ + Document::MutablePtr doc = Document::create(path, Dialect::Qml); + QFile file(doc->fileName()); + file.open(QFile::ReadOnly | QFile::Text); + doc->setSource(file.readAll()); + file.close(); + doc->parse(); + return doc; +} + +class tst_Dependencies : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void test_data(); + void test(); + +private: + QString m_path; + QStringList m_basePaths; +}; + +void tst_Dependencies::initTestCase() +{ + QLoggingCategory::setFilterRules(QLatin1String("qtc.*.debug=false")); + m_path = QCoreApplication::applicationDirPath() + QLatin1Literal("/samples"); + + m_basePaths.append(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)); + + if (!ModelManagerInterface::instance()) + new ModelManagerInterface; + + if (!ExtensionSystem::PluginManager::instance()) + new ExtensionSystem::PluginManager; +} + +void tst_Dependencies::test_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<int>("nSemanticMessages"); + QTest::addColumn<int>("nStaticMessages"); + + QTest::newRow("ApplicationWindow") + << QString(m_path + QLatin1String("/001_ApplicationWindow.qml")) + << 0 + << 0; + QTest::newRow("Window") + << QString(m_path + QLatin1String("/002_Window.qml")) + << 0 + << 1; +} + +void tst_Dependencies::test() +{ + QFETCH(QString, filename); + QFETCH(int, nSemanticMessages); + QFETCH(int, nStaticMessages); + + ModelManagerInterface *modelManager = ModelManagerInterface::instance(); + + QFutureInterface<void> result; + PathsAndLanguages lPaths; + QStringList paths(m_basePaths); + paths << m_path; + for (auto p: paths) + lPaths.maybeInsert(Utils::FileName::fromString(p), Dialect::Qml); + ModelManagerInterface::importScan(result, ModelManagerInterface::workingCopy(), lPaths, + ModelManagerInterface::instance(), false); + + + Document::MutablePtr doc = readDocument(filename); + QVERIFY(!doc->source().isEmpty()); + + Snapshot snapshot = modelManager->snapshot(); + + QmlJSTools::SemanticInfo semanticInfo; + semanticInfo.document = doc; + semanticInfo.snapshot = snapshot; + + Link link(semanticInfo.snapshot, modelManager->defaultVContext(doc->language(), doc), modelManager->builtins(doc)); + + semanticInfo.context = link(doc, &semanticInfo.semanticMessages); + + ScopeChain *scopeChain = new ScopeChain(doc, semanticInfo.context); + semanticInfo.setRootScopeChain(QSharedPointer<const ScopeChain>(scopeChain)); + + Check checker(doc, semanticInfo.context); + semanticInfo.staticAnalysisMessages = checker(); + + QCOMPARE(semanticInfo.semanticMessages.length(), nSemanticMessages); + QCOMPARE(semanticInfo.staticAnalysisMessages.length(), nStaticMessages); +} + +QTEST_MAIN(tst_Dependencies) + +#include "tst_dependencies.moc" |