aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-08-12 12:36:15 +0200
committerUlf Hermann <ulf.hermann@qt.io>2020-08-13 14:00:59 +0200
commit9a79791e7975de811102f89686a5d631eeac9d16 (patch)
tree07ad3c63b4b0bc7cd72d1bb083effd0c4fd74053 /tools
parent1a3738dfa85d6aa6771893c2a2b3cf874b492524 (diff)
Move functionality to read types from QML files out of qmllint
We want to re-use this in other tools. Change-Id: I2a8cd104d54c1fa9b2898213b0b9e09719e42bca Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qmllint/.prev_CMakeLists.txt3
-rw-r--r--tools/qmllint/CMakeLists.txt3
-rw-r--r--tools/qmllint/findwarnings.cpp90
-rw-r--r--tools/qmllint/qmllint.pro2
-rw-r--r--tools/shared/importedmembersvisitor.cpp (renamed from tools/qmllint/importedmembersvisitor.cpp)5
-rw-r--r--tools/shared/importedmembersvisitor.h (renamed from tools/qmllint/importedmembersvisitor.h)7
-rw-r--r--tools/shared/qmljstypereader.cpp131
-rw-r--r--tools/shared/qmljstypereader.h70
-rw-r--r--tools/shared/shared.pri4
9 files changed, 223 insertions, 92 deletions
diff --git a/tools/qmllint/.prev_CMakeLists.txt b/tools/qmllint/.prev_CMakeLists.txt
index 2bb98260f6..8e4affe73c 100644
--- a/tools/qmllint/.prev_CMakeLists.txt
+++ b/tools/qmllint/.prev_CMakeLists.txt
@@ -9,12 +9,13 @@ qt_add_tool(${target_name}
TARGET_DESCRIPTION "QML Syntax Verifier"
SOURCES
../shared/componentversion.cpp ../shared/componentversion.h
+ ../shared/importedmembersvisitor.cpp ../shared/importedmembersvisitor.h
../shared/metatypes.h
+ ../shared/qmljstypereader.cpp ../shared/qmljstypereader.h
../shared/scopetree.cpp ../shared/scopetree.h
../shared/typedescriptionreader.cpp ../shared/typedescriptionreader.h
checkidentifiers.cpp checkidentifiers.h
findwarnings.cpp findwarnings.h
- importedmembersvisitor.cpp importedmembersvisitor.h
main.cpp
qcoloroutput.cpp qcoloroutput.h
INCLUDE_DIRECTORIES
diff --git a/tools/qmllint/CMakeLists.txt b/tools/qmllint/CMakeLists.txt
index 03b7854682..663bcb9cbf 100644
--- a/tools/qmllint/CMakeLists.txt
+++ b/tools/qmllint/CMakeLists.txt
@@ -10,12 +10,13 @@ qt_add_tool(${target_name}
TOOLS_TARGET Qml # special case
SOURCES
../shared/componentversion.cpp ../shared/componentversion.h
+ ../shared/importedmembersvisitor.cpp ../shared/importedmembersvisitor.h
../shared/metatypes.h
+ ../shared/qmljstypereader.cpp ../shared/qmljstypereader.h
../shared/scopetree.cpp ../shared/scopetree.h
../shared/typedescriptionreader.cpp ../shared/typedescriptionreader.h
checkidentifiers.cpp checkidentifiers.h
findwarnings.cpp findwarnings.h
- importedmembersvisitor.cpp importedmembersvisitor.h
main.cpp
qcoloroutput.cpp qcoloroutput.h
INCLUDE_DIRECTORIES
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index 25dccfa046..b18cd82047 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -31,6 +31,7 @@
#include "scopetree.h"
#include "typedescriptionreader.h"
#include "checkidentifiers.h"
+#include "qmljstypereader.h"
#include <QtQml/private/qqmljsast_p.h>
#include <QtQml/private/qqmljslexer_p.h>
@@ -67,47 +68,6 @@ void FindWarningVisitor::leaveEnvironment()
m_currentScope = m_currentScope->parentScope();
}
-void FindWarningVisitor::parseHeaders(QQmlJS::AST::UiHeaderItemList *header)
-{
- using namespace QQmlJS::AST;
-
- while (header) {
- if (auto import = cast<UiImport *>(header->headerItem)) {
- if (import->version) {
- QString path;
- auto uri = import->importUri;
- while (uri) {
- path.append(uri->name);
- path.append("/");
- uri = uri->next;
- }
- path.chop(1);
- importHelper(path,
- import->asToken.isValid() ? import->importId.toString() : QString(),
- import->version->version);
- }
- }
- header = header->next;
- }
-}
-
-ScopeTree::Ptr FindWarningVisitor::parseProgram(QQmlJS::AST::Program *program,
- const QString &name)
-{
- using namespace QQmlJS::AST;
- ScopeTree::Ptr result = ScopeTree::create(ScopeType::JSLexicalScope, name);
- for (auto *statement = program->statements; statement; statement = statement->next) {
- if (auto *function = cast<FunctionDeclaration *>(statement->statement)) {
- MetaMethod method(function->name.toString());
- method.setMethodType(MetaMethod::Method);
- for (auto *parameters = function->formals; parameters; parameters = parameters->next)
- method.addParameter(parameters->element->bindingIdentifier.toString(), "");
- result->addMethod(method);
- }
- }
- return result;
-}
-
static const QLatin1String SlashQmldir = QLatin1String("/qmldir");
static const QLatin1String SlashPluginsDotQmltypes = QLatin1String("/plugins.qmltypes");
@@ -258,48 +218,18 @@ void FindWarningVisitor::importHelper(const QString &module, const QString &pref
ScopeTree::Ptr FindWarningVisitor::localFile2ScopeTree(const QString &filePath)
{
- using namespace QQmlJS::AST;
- const QFileInfo info { filePath };
- QString baseName = info.baseName();
- const QString scopeName = baseName.endsWith(".ui") ? baseName.chopped(3) : baseName;
+ QmlJSTypeReader typeReader(filePath);
+ ScopeTree::Ptr result = typeReader();
- QQmlJS::Engine engine;
- QQmlJS::Lexer lexer(&engine);
-
- const QString lowerSuffix = info.suffix().toLower();
- const bool isESModule = lowerSuffix == QLatin1String("mjs");
- const bool isJavaScript = isESModule || lowerSuffix == QLatin1String("js");
-
- QFile file(filePath);
- if (!file.open(QFile::ReadOnly)) {
- return ScopeTree::create(isJavaScript ? ScopeType::JSLexicalScope : ScopeType::QMLScope,
- scopeName);
- }
+ const QStringList errors = typeReader.errors();
+ for (const QString &error : errors)
+ m_colorOut.write(error, Error);
- QString code = file.readAll();
- file.close();
+ const auto imports = typeReader.imports();
+ for (const auto &import : imports)
+ importHelper(import.path, import.prefix, import.version);
- lexer.setCode(code, /*line = */ 1, /*qmlMode=*/ !isJavaScript);
- QQmlJS::Parser parser(&engine);
-
- const bool success = isJavaScript ? (isESModule ? parser.parseModule()
- : parser.parseProgram())
- : parser.parse();
- if (!success) {
- return ScopeTree::create(isJavaScript ? ScopeType::JSLexicalScope : ScopeType::QMLScope,
- scopeName);
- }
-
- if (!isJavaScript) {
- QQmlJS::AST::UiProgram *program = parser.ast();
- parseHeaders(program->headers);
- ImportedMembersVisitor membersVisitor(&m_colorOut);
- program->members->accept(&membersVisitor);
- return membersVisitor.result(scopeName);
- }
-
- // TODO: Anything special to do with ES modules here?
- return parseProgram(QQmlJS::AST::cast<QQmlJS::AST::Program *>(parser.rootNode()), scopeName);
+ return result;
}
void FindWarningVisitor::importFileOrDirectory(const QString &fileOrDirectory,
diff --git a/tools/qmllint/qmllint.pro b/tools/qmllint/qmllint.pro
index 620e5c3277..44bf2e7ce5 100644
--- a/tools/qmllint/qmllint.pro
+++ b/tools/qmllint/qmllint.pro
@@ -9,7 +9,6 @@ SOURCES += \
checkidentifiers.cpp \
main.cpp \
findwarnings.cpp \
- importedmembersvisitor.cpp \
qcoloroutput.cpp
QMAKE_TARGET_DESCRIPTION = QML Syntax Verifier
@@ -20,5 +19,4 @@ HEADERS += \
$$METATYPEREADER_HEADERS \
checkidentifiers.h \
findwarnings.h \
- importedmembersvisitor.h \
qcoloroutput.h
diff --git a/tools/qmllint/importedmembersvisitor.cpp b/tools/shared/importedmembersvisitor.cpp
index 7bc58dee24..2162044f99 100644
--- a/tools/qmllint/importedmembersvisitor.cpp
+++ b/tools/shared/importedmembersvisitor.cpp
@@ -136,7 +136,7 @@ bool ImportedMembersVisitor::visit(UiSourceElement *sourceElement)
// nothing to do
} else {
const auto loc = sourceElement->firstSourceLocation();
- m_colorOut->writeUncolored(
+ m_errors.append(
"unsupportedd sourceElement at "
+ QString::fromLatin1("%1:%2: ").arg(loc.startLine).arg(loc.startColumn)
+ QString::number(sourceElement->sourceElement->kind));
@@ -165,6 +165,5 @@ bool ImportedMembersVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
void ImportedMembersVisitor::throwRecursionDepthError()
{
- m_colorOut->write(QStringLiteral("Error"), Error);
- m_colorOut->write(QStringLiteral("Maximum statement or expression depth exceeded"), Error);
+ m_errors.append(QStringLiteral("Maximum statement or expression depth exceeded"));
}
diff --git a/tools/qmllint/importedmembersvisitor.h b/tools/shared/importedmembersvisitor.h
index 023e58df73..ab44deda9b 100644
--- a/tools/qmllint/importedmembersvisitor.h
+++ b/tools/shared/importedmembersvisitor.h
@@ -47,11 +47,8 @@
class ImportedMembersVisitor : public QQmlJS::AST::Visitor
{
public:
- ImportedMembersVisitor(ColorOutput *colorOut) :
- m_colorOut(colorOut)
- {}
-
ScopeTree::Ptr result(const QString &scopeName) const;
+ QStringList errors() const { return m_errors; }
private:
bool visit(QQmlJS::AST::UiObjectDefinition *) override;
@@ -68,7 +65,7 @@ private:
ScopeTree::ConstPtr m_rootObject;
QHash<QString, ScopeTree::Ptr> m_objects;
- ColorOutput *m_colorOut = nullptr;
+ QStringList m_errors;
};
#endif // IMPORTEDMEMBERSVISITOR_H
diff --git a/tools/shared/qmljstypereader.cpp b/tools/shared/qmljstypereader.cpp
new file mode 100644
index 0000000000..3825535d44
--- /dev/null
+++ b/tools/shared/qmljstypereader.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmljstypereader.h"
+#include "importedmembersvisitor.h"
+
+#include <QtQml/private/qqmljsast_p.h>
+#include <QtQml/private/qqmljsengine_p.h>
+#include <QtQml/private/qqmljslexer_p.h>
+#include <QtQml/private/qqmljsparser_p.h>
+#include <QtQml/private/qqmlimportresolver_p.h>
+
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdebug.h>
+
+static QList<QmlJSTypeReader::Import> parseHeaders(QQmlJS::AST::UiHeaderItemList *header)
+{
+ using namespace QQmlJS::AST;
+ QList<QmlJSTypeReader::Import> imports;
+
+ for (; header; header = header->next) {
+ auto import = cast<UiImport *>(header->headerItem);
+ if (!import)
+ continue;
+
+ QString path;
+ auto uri = import->importUri;
+ while (uri) {
+ path.append(uri->name);
+ path.append(QLatin1Char('/'));
+ uri = uri->next;
+ }
+ path.chop(1);
+ imports.append({
+ path,
+ import->version ? import->version->version : QTypeRevision(),
+ import->asToken.isValid() ? import->importId.toString() : QString()
+ });
+ }
+
+ return imports;
+}
+
+static ScopeTree::Ptr parseProgram(QQmlJS::AST::Program *program, const QString &name)
+{
+ using namespace QQmlJS::AST;
+ ScopeTree::Ptr result = ScopeTree::create(ScopeType::JSLexicalScope, name);
+ for (auto *statement = program->statements; statement; statement = statement->next) {
+ if (auto *function = cast<FunctionDeclaration *>(statement->statement)) {
+ MetaMethod method(function->name.toString());
+ method.setMethodType(MetaMethod::Method);
+ for (auto *parameters = function->formals; parameters; parameters = parameters->next)
+ method.addParameter(parameters->element->bindingIdentifier.toString(), QString());
+ result->addMethod(method);
+ }
+ }
+ return result;
+}
+
+ScopeTree::Ptr QmlJSTypeReader::operator()()
+{
+ using namespace QQmlJS::AST;
+ const QFileInfo info { m_file };
+ QString baseName = info.baseName();
+ const QString scopeName = baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
+ : baseName;
+
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+
+ const QString lowerSuffix = info.suffix().toLower();
+ const bool isESModule = lowerSuffix == QLatin1String("mjs");
+ const bool isJavaScript = isESModule || lowerSuffix == QLatin1String("js");
+
+ QFile file(m_file);
+ if (!file.open(QFile::ReadOnly)) {
+ return ScopeTree::create(isJavaScript ? ScopeType::JSLexicalScope : ScopeType::QMLScope,
+ scopeName);
+ }
+
+ QString code = QString::fromUtf8(file.readAll());
+ file.close();
+
+ lexer.setCode(code, /*line = */ 1, /*qmlMode=*/ !isJavaScript);
+ QQmlJS::Parser parser(&engine);
+
+ const bool success = isJavaScript ? (isESModule ? parser.parseModule()
+ : parser.parseProgram())
+ : parser.parse();
+ if (!success) {
+ return ScopeTree::create(isJavaScript ? ScopeType::JSLexicalScope : ScopeType::QMLScope,
+ scopeName);
+ }
+
+ if (!isJavaScript) {
+ QQmlJS::AST::UiProgram *program = parser.ast();
+ m_imports = parseHeaders(program->headers);
+ ImportedMembersVisitor membersVisitor;
+ program->members->accept(&membersVisitor);
+ m_errors = membersVisitor.errors();
+ return membersVisitor.result(scopeName);
+ }
+
+ // TODO: Anything special to do with ES modules here?
+ return parseProgram(QQmlJS::AST::cast<QQmlJS::AST::Program *>(parser.rootNode()), scopeName);
+}
diff --git a/tools/shared/qmljstypereader.h b/tools/shared/qmljstypereader.h
new file mode 100644
index 0000000000..8485f6be6b
--- /dev/null
+++ b/tools/shared/qmljstypereader.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLJSTYPERADER_H
+#define QMLJSTYPERADER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#include "scopetree.h"
+
+#include <QtQml/private/qqmljsastfwd_p.h>
+
+#include <QtCore/qpair.h>
+#include <QtCore/qset.h>
+
+class QmlJSTypeReader
+{
+public:
+ struct Import {
+ QString path;
+ QTypeRevision version;
+ QString prefix;
+ };
+
+ QmlJSTypeReader(const QString &file) : m_file(file) {}
+
+ ScopeTree::Ptr operator()();
+ QList<Import> imports() const { return m_imports; }
+ QStringList errors() const { return m_errors; }
+
+private:
+ QString m_file;
+ QList<Import> m_imports;
+ QStringList m_errors;
+};
+
+#endif // QMLJSTYPEREADER_H
diff --git a/tools/shared/shared.pri b/tools/shared/shared.pri
index 1b3cd4d37b..4ee3704bfb 100644
--- a/tools/shared/shared.pri
+++ b/tools/shared/shared.pri
@@ -11,11 +11,15 @@ RESOURCEFILEMAPPER_HEADERS = \
METATYPEREADER_SOURCES = \
$$PWD/componentversion.cpp \
+ $$PWD/importedmembersvisitor.cpp \
+ $$PWD/qmljstypereader.cpp \
$$PWD/scopetree.cpp \
$$PWD/typedescriptionreader.cpp
METATYPEREADER_HEADERS = \
$$PWD/componentversion.h \
+ $$PWD/importedmembersvisitor.h \
+ $$PWD/qmljstypereader.h \
$$PWD/metatypes.h \
$$PWD/scopetree.h \
$$PWD/typedescriptionreader.h