aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmllint
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/qmllint
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/qmllint')
-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/importedmembersvisitor.cpp170
-rw-r--r--tools/qmllint/importedmembersvisitor.h74
-rw-r--r--tools/qmllint/qmllint.pro2
6 files changed, 14 insertions, 328 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/importedmembersvisitor.cpp b/tools/qmllint/importedmembersvisitor.cpp
deleted file mode 100644
index 7bc58dee24..0000000000
--- a/tools/qmllint/importedmembersvisitor.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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 "importedmembersvisitor.h"
-#include "scopetree.h"
-
-using namespace QQmlJS::AST;
-
-ScopeTree::Ptr ImportedMembersVisitor::result(const QString &scopeName) const
-{
- ScopeTree::Ptr result = ScopeTree::create();
- result->setClassName(scopeName);
- result->setSuperclassName(m_rootObject->superclassName());
- const auto properties = m_rootObject->properties();
- for (auto property : properties) {
- if (property.isAlias()) {
- const auto it = m_objects.find(property.typeName());
- if (it != m_objects.end())
- property.setType(*it);
- result->addProperty(property);
- } else {
- result->addProperty(property);
- }
- }
-
- for (const auto &method : m_rootObject->methods())
- result->addMethod(method);
-
- for (const auto &enumerator : m_rootObject->enums())
- result->addEnum(enumerator);
-
- return result;
-}
-
-bool ImportedMembersVisitor::visit(UiObjectDefinition *definition)
-{
- ScopeTree::Ptr scope = ScopeTree::create();
- QString superType;
- for (auto segment = definition->qualifiedTypeNameId; segment; segment = segment->next) {
- if (!superType.isEmpty())
- superType.append('.');
- superType.append(segment->name.toString());
- }
- scope->setSuperclassName(superType);
- if (!m_rootObject)
- m_rootObject = scope;
- m_currentObjects.append(scope);
- return true;
-}
-
-void ImportedMembersVisitor::endVisit(UiObjectDefinition *)
-{
- m_currentObjects.pop_back();
-}
-
-bool ImportedMembersVisitor::visit(UiPublicMember *publicMember)
-{
- switch (publicMember->type) {
- case UiPublicMember::Signal: {
- UiParameterList *param = publicMember->parameters;
- MetaMethod method;
- method.setMethodType(MetaMethod::Signal);
- method.setMethodName(publicMember->name.toString());
- while (param) {
- method.addParameter(param->name.toString(), param->type->name.toString());
- param = param->next;
- }
- currentObject()->addMethod(method);
- break;
- }
- case UiPublicMember::Property: {
- auto typeName = publicMember->memberType->name;
- const bool isAlias = (typeName == QLatin1String("alias"));
- if (isAlias) {
- const auto expression = cast<ExpressionStatement *>(publicMember->statement);
- if (const auto idExpression = cast<IdentifierExpression *>(expression->expression))
- typeName = idExpression->name;
- }
- MetaProperty prop {
- publicMember->name.toString(),
- typeName.toString(),
- false,
- false,
- false,
- isAlias,
- 0
- };
- currentObject()->addProperty(prop);
- break;
- }
- }
- return true;
-}
-
-bool ImportedMembersVisitor::visit(UiSourceElement *sourceElement)
-{
- if (FunctionExpression *fexpr = sourceElement->sourceElement->asFunctionDefinition()) {
- MetaMethod method;
- method.setMethodName(fexpr->name.toString());
- method.setMethodType(MetaMethod::Method);
- FormalParameterList *parameters = fexpr->formals;
- while (parameters) {
- method.addParameter(parameters->element->bindingIdentifier.toString(), "");
- parameters = parameters->next;
- }
- currentObject()->addMethod(method);
- } else if (ClassExpression *clexpr = sourceElement->sourceElement->asClassDefinition()) {
- MetaProperty prop { clexpr->name.toString(), "", false, false, false, false, 1 };
- currentObject()->addProperty(prop);
- } else if (cast<VariableStatement *>(sourceElement->sourceElement)) {
- // nothing to do
- } else {
- const auto loc = sourceElement->firstSourceLocation();
- m_colorOut->writeUncolored(
- "unsupportedd sourceElement at "
- + QString::fromLatin1("%1:%2: ").arg(loc.startLine).arg(loc.startColumn)
- + QString::number(sourceElement->sourceElement->kind));
- }
- return true;
-}
-
-bool ImportedMembersVisitor::visit(UiScriptBinding *scriptBinding)
-{
- if (scriptBinding->qualifiedId->name == QLatin1String("id")) {
- const auto *statement = cast<ExpressionStatement *>(scriptBinding->statement);
- const auto *idExprension = cast<IdentifierExpression *>(statement->expression);
- m_objects.insert(idExprension->name.toString(), currentObject());
- }
- return true;
-}
-
-bool ImportedMembersVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
-{
- MetaEnum qmlEnum(uied->name.toString());
- for (const auto *member = uied->members; member; member = member->next)
- qmlEnum.addKey(member->member.toString());
- currentObject()->addEnum(qmlEnum);
- return true;
-}
-
-void ImportedMembersVisitor::throwRecursionDepthError()
-{
- m_colorOut->write(QStringLiteral("Error"), Error);
- m_colorOut->write(QStringLiteral("Maximum statement or expression depth exceeded"), Error);
-}
diff --git a/tools/qmllint/importedmembersvisitor.h b/tools/qmllint/importedmembersvisitor.h
deleted file mode 100644
index 023e58df73..0000000000
--- a/tools/qmllint/importedmembersvisitor.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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 IMPORTEDMEMBERSVISITOR_H
-#define IMPORTEDMEMBERSVISITOR_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 "qcoloroutput.h"
-
-#include <private/qqmljsast_p.h>
-
-class ImportedMembersVisitor : public QQmlJS::AST::Visitor
-{
-public:
- ImportedMembersVisitor(ColorOutput *colorOut) :
- m_colorOut(colorOut)
- {}
-
- ScopeTree::Ptr result(const QString &scopeName) const;
-
-private:
- bool visit(QQmlJS::AST::UiObjectDefinition *) override;
- void endVisit(QQmlJS::AST::UiObjectDefinition *) override;
- bool visit(QQmlJS::AST::UiPublicMember *) override;
- bool visit(QQmlJS::AST::UiSourceElement *) override;
- bool visit(QQmlJS::AST::UiScriptBinding *) override;
- bool visit(QQmlJS::AST::UiEnumDeclaration *uied) override;
- void throwRecursionDepthError() override;
-
- ScopeTree::Ptr currentObject() const { return m_currentObjects.back(); }
-
- QVector<ScopeTree::Ptr> m_currentObjects;
- ScopeTree::ConstPtr m_rootObject;
- QHash<QString, ScopeTree::Ptr> m_objects;
-
- ColorOutput *m_colorOut = nullptr;
-};
-
-#endif // IMPORTEDMEMBERSVISITOR_H
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