aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-10-09 12:02:22 +0200
committerUlf Hermann <ulf.hermann@qt.io>2020-10-15 10:44:25 +0200
commit678d4ec4b68d43d0c748a8ec62a13716f83a27cf (patch)
tree863c228d5f0c46d494f2aee24e65f7ef21ee9e77
parentf98c961da6d039621ae40ab6c1a79c4b06efb83f (diff)
Unify QQmlJSImportVisitor and FindWarningsVisitor
They are both pretty much doing the same thing, except that the import visitor is not as thorough. We need the full analysis in QtQmlCompiler, so we successively move the code over. Change-Id: If7fb47f88165fd8b61f4ccc408ccfbb7dad533e6 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp195
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h36
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp20
-rw-r--r--src/qmlcompiler/qqmljstypereader.cpp36
-rw-r--r--src/qmlcompiler/qqmljstypereader_p.h18
-rw-r--r--tools/qmllint/checkidentifiers.cpp4
-rw-r--r--tools/qmllint/findwarnings.cpp168
-rw-r--r--tools/qmllint/findwarnings.h30
-rw-r--r--tools/qmllint/main.cpp3
9 files changed, 220 insertions, 290 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 0cb5632d40..ac21c7715e 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -28,21 +28,46 @@
#include "qqmljsimportvisitor_p.h"
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+
QT_BEGIN_NAMESPACE
using namespace QQmlJS::AST;
-QQmlJSScope::Ptr QQmlJSImportVisitor::result(const QString &scopeName) const
+QQmlJSImportVisitor::QQmlJSImportVisitor(
+ QQmlJSImporter *importer, const QString &implicitImportDirectory,
+ const QStringList &qmltypesFiles)
+ : m_implicitImportDirectory(implicitImportDirectory)
+ , m_qmltypesFiles(qmltypesFiles)
+ , m_currentScope(QQmlJSScope::create(QQmlJSScope::JSFunctionScope))
+ , m_importer(importer)
+{
+ m_globalScope = m_currentScope;
+}
+
+void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QString &name)
+{
+ m_currentScope = QQmlJSScope::create(type, m_currentScope);
+ m_currentScope->setBaseTypeName(name);
+ m_currentScope->setIsComposite(true);
+}
+
+void QQmlJSImportVisitor::leaveEnvironment()
+{
+ m_currentScope = m_currentScope->parentScope();
+}
+
+QQmlJSScope::Ptr QQmlJSImportVisitor::result() const
{
QQmlJSScope::Ptr result = QQmlJSScope::create();
result->setIsComposite(true);
- result->setInternalName(scopeName);
- result->setBaseTypeName(m_rootObject->baseTypeName());
- const auto properties = m_rootObject->properties();
+ result->setBaseTypeName(m_qmlRootScope->baseTypeName());
+ const auto properties = m_qmlRootScope->properties();
for (auto property : properties) {
if (property.isAlias()) {
- const auto it = m_objects.find(property.typeName());
- if (it != m_objects.end())
+ const auto it = m_scopesById.find(property.typeName());
+ if (it != m_scopesById.end())
property.setType(QQmlJSScope::ConstPtr(*it));
result->addProperty(property);
} else {
@@ -50,34 +75,47 @@ QQmlJSScope::Ptr QQmlJSImportVisitor::result(const QString &scopeName) const
}
}
- for (const auto &method : m_rootObject->methods())
+ for (const auto &method : m_qmlRootScope->methods())
result->addMethod(method);
- for (const auto &enumerator : m_rootObject->enums())
+ for (const auto &enumerator : m_qmlRootScope->enums())
result->addEnum(enumerator);
+ result->resolveTypes(m_rootScopeImports);
return result;
}
+bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiProgram *)
+{
+ m_rootScopeImports = m_importer->importBuiltins();
+
+ if (!m_qmltypesFiles.isEmpty())
+ m_rootScopeImports.insert(m_importer->importQmltypes(m_qmltypesFiles));
+
+ m_rootScopeImports.insert(m_importer->importDirectory(m_implicitImportDirectory));
+
+ m_errors.append(m_importer->takeWarnings());
+ return true;
+}
+
bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
{
- QQmlJSScope::Ptr scope = QQmlJSScope::create();
QString superType;
for (auto segment = definition->qualifiedTypeNameId; segment; segment = segment->next) {
if (!superType.isEmpty())
superType.append(u'.');
superType.append(segment->name.toString());
}
- scope->setBaseTypeName(superType);
- if (!m_rootObject)
- m_rootObject = scope;
- m_currentObjects.append(scope);
+ enterEnvironment(QQmlJSScope::QMLScope, superType);
+ if (!m_qmlRootScope)
+ m_qmlRootScope = m_currentScope;
+
return true;
}
void QQmlJSImportVisitor::endVisit(UiObjectDefinition *)
{
- m_currentObjects.pop_back();
+ leaveEnvironment();
}
bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
@@ -92,7 +130,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
method.addParameter(param->name.toString(), param->type->name.toString());
param = param->next;
}
- currentObject()->addMethod(method);
+ m_currentScope->addMethod(method);
break;
}
case UiPublicMember::Property: {
@@ -112,48 +150,81 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
isAlias,
0
};
- currentObject()->addProperty(prop);
+ m_currentScope->addProperty(prop);
break;
}
}
return true;
}
-bool QQmlJSImportVisitor::visit(UiSourceElement *sourceElement)
+void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr)
{
- if (FunctionExpression *fexpr = sourceElement->sourceElement->asFunctionDefinition()) {
- QQmlJSMetaMethod method;
- method.setMethodName(fexpr->name.toString());
- method.setMethodType(QQmlJSMetaMethod::Method);
- FormalParameterList *parameters = fexpr->formals;
- while (parameters) {
- method.addParameter(parameters->element->bindingIdentifier.toString(), QString());
- parameters = parameters->next;
+ using namespace QQmlJS::AST;
+ auto name = fexpr->name.toString();
+ if (!name.isEmpty()) {
+ if (m_currentScope->scopeType() == QQmlJSScope::QMLScope) {
+ QQmlJSMetaMethod method(name, QStringLiteral("void"));
+ method.setMethodType(QQmlJSMetaMethod::Method);
+ FormalParameterList *parameters = fexpr->formals;
+ while (parameters) {
+ method.addParameter(parameters->element->bindingIdentifier.toString(), QString());
+ parameters = parameters->next;
+ }
+ m_currentScope->addMethod(method);
+ } else {
+ m_currentScope->insertJSIdentifier(
+ name, {
+ QQmlJSScope::JavaScriptIdentifier::LexicalScoped,
+ fexpr->firstSourceLocation()
+ });
}
- currentObject()->addMethod(method);
- } else if (ClassExpression *clexpr = sourceElement->sourceElement->asClassDefinition()) {
- QQmlJSMetaProperty prop { clexpr->name.toString(), QString(), false, false, false, false, 1 };
- currentObject()->addProperty(prop);
- } else if (cast<VariableStatement *>(sourceElement->sourceElement)) {
- // nothing to do
+ enterEnvironment(QQmlJSScope::JSFunctionScope, name);
} else {
- const auto loc = sourceElement->firstSourceLocation();
- m_errors.append({
- QStringLiteral("unsupportedd sourceElement %1")
- .arg(sourceElement->sourceElement->kind),
- QtWarningMsg,
- loc
- });
+ enterEnvironment(QQmlJSScope::JSFunctionScope, QStringLiteral("<anon>"));
}
+}
+
+bool QQmlJSImportVisitor::visit(QQmlJS::AST::FunctionExpression *fexpr)
+{
+ visitFunctionExpressionHelper(fexpr);
+ return true;
+}
+
+void QQmlJSImportVisitor::endVisit(QQmlJS::AST::FunctionExpression *)
+{
+ leaveEnvironment();
+}
+
+bool QQmlJSImportVisitor::visit(QQmlJS::AST::FunctionDeclaration *fdecl)
+{
+ visitFunctionExpressionHelper(fdecl);
+ return true;
+}
+
+void QQmlJSImportVisitor::endVisit(QQmlJS::AST::FunctionDeclaration *)
+{
+ leaveEnvironment();
+}
+
+bool QQmlJSImportVisitor::visit(QQmlJS::AST::ClassExpression *ast)
+{
+ QQmlJSMetaProperty prop { ast->name.toString(), QString(), false, false, false, false, 1 };
+ m_currentScope->addProperty(prop);
+ enterEnvironment(QQmlJSScope::JSFunctionScope, ast->name.toString());
return true;
}
+void QQmlJSImportVisitor::endVisit(QQmlJS::AST::ClassExpression *)
+{
+ leaveEnvironment();
+}
+
bool QQmlJSImportVisitor::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());
+ m_scopesById.insert(idExprension->name.toString(), m_currentScope);
}
return true;
}
@@ -163,7 +234,51 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
QQmlJSMetaEnum qmlEnum(uied->name.toString());
for (const auto *member = uied->members; member; member = member->next)
qmlEnum.addKey(member->member.toString());
- currentObject()->addEnum(qmlEnum);
+ m_currentScope->addEnum(qmlEnum);
+ return true;
+}
+
+bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
+{
+ // construct path
+ QString prefix = QLatin1String("");
+ if (import->asToken.isValid()) {
+ prefix += import->importId;
+ }
+ auto filename = import->fileName.toString();
+ if (!filename.isEmpty()) {
+ const QFileInfo file(filename);
+ const QFileInfo path(file.isRelative() ? QDir(m_implicitImportDirectory).filePath(filename)
+ : filename);
+ if (path.isDir()) {
+ m_rootScopeImports.insert(m_importer->importDirectory(path.canonicalFilePath(), prefix));
+ } else if (path.isFile()) {
+ const auto scope = m_importer->importFile(path.canonicalFilePath());
+ m_rootScopeImports.insert(prefix.isEmpty() ? scope->internalName() : prefix, scope);
+ }
+
+ }
+
+ QString path {};
+ if (!import->importId.isEmpty()) {
+ // TODO: do not put imported ids into the same space as qml IDs
+ const QString importId = import->importId.toString();
+ m_scopesById.insert(importId, m_rootScopeImports.value(importId));
+ }
+ auto uri = import->importUri;
+ while (uri) {
+ path.append(uri->name);
+ path.append(u'/');
+ uri = uri->next;
+ }
+ path.chop(1);
+
+ const auto imported = m_importer->importModule(
+ path, prefix, import->version ? import->version->version : QTypeRevision());
+
+ m_rootScopeImports.insert(imported);
+
+ m_errors.append(m_importer->takeWarnings());
return true;
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index 8f0d937968..1d50881441 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -43,31 +43,51 @@
#include <private/qqmljsast_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmljsimporter_p.h>
QT_BEGIN_NAMESPACE
class QQmlJSImportVisitor : public QQmlJS::AST::Visitor
{
public:
- QQmlJSScope::Ptr result(const QString &scopeName) const;
+ QQmlJSImportVisitor(QQmlJSImporter *importer, const QString &implicitImportDirectory,
+ const QStringList &qmltypesFiles = QStringList());
+
+ QQmlJSScope::Ptr result() const;
QList<QQmlJS::DiagnosticMessage> errors() const { return m_errors; }
-private:
+protected:
+ bool visit(QQmlJS::AST::UiProgram *) override;
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;
+ bool visit(QQmlJS::AST::FunctionExpression *fexpr) override;
+ void endVisit(QQmlJS::AST::FunctionExpression *) override;
+ bool visit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
+ void endVisit(QQmlJS::AST::FunctionDeclaration *) override;
+ bool visit(QQmlJS::AST::ClassExpression *ast) override;
+ void endVisit(QQmlJS::AST::ClassExpression *) override;
+ bool visit(QQmlJS::AST::UiImport *import) override;
void throwRecursionDepthError() override;
- QQmlJSScope::Ptr currentObject() const { return m_currentObjects.back(); }
-
- QVector<QQmlJSScope::Ptr> m_currentObjects;
- QQmlJSScope::ConstPtr m_rootObject;
- QHash<QString, QQmlJSScope::Ptr> m_objects;
+ QString m_implicitImportDirectory;
+ QStringList m_qmltypesFiles;
+ QQmlJSScope::Ptr m_currentScope;
+ QQmlJSScope::ConstPtr m_qmlRootScope;
+ QQmlJSScope::ConstPtr m_globalScope;
+ QHash<QString, QQmlJSScope::ConstPtr> m_scopesById;
+ QHash<QString, QQmlJSScope::ConstPtr> m_rootScopeImports;
+ QQmlJSImporter *m_importer;
QList<QQmlJS::DiagnosticMessage> m_errors;
+
+ void enterEnvironment(QQmlJSScope::ScopeType type, const QString &name);
+ void leaveEnvironment();
+
+private:
+ void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
};
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index e515431758..ed434c17e7 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -44,13 +44,8 @@ QQmlJSScope::QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope)
QQmlJSScope::Ptr QQmlJSScope::create(ScopeType type, const QQmlJSScope::Ptr &parentScope)
{
QSharedPointer<QQmlJSScope> childScope(new QQmlJSScope{type, parentScope});
- if (parentScope) {
- Q_ASSERT(type != QQmlJSScope::QMLScope
- || !parentScope->m_parentScope
- || parentScope->parentScope()->m_scopeType == QQmlJSScope::QMLScope
- || parentScope->parentScope()->m_internalName == QLatin1String("global"));
+ if (parentScope)
parentScope->m_childScopes.push_back(childScope);
- }
return childScope;
}
@@ -188,19 +183,10 @@ bool QQmlJSScope::Export::isValid() const
QQmlJSScope QDeferredFactory<QQmlJSScope>::create() const
{
- QQmlJSTypeReader typeReader(m_filePath);
+ QQmlJSTypeReader typeReader(m_importer, m_filePath);
QQmlJSScope::Ptr result = typeReader();
-
m_importer->m_warnings.append(typeReader.errors());
-
- QQmlJSImporter::AvailableTypes types;
- types.qmlNames.insert(m_importer->importDirectory(QFileInfo(m_filePath).canonicalPath()));
-
- const auto imports = typeReader.imports();
- for (const auto &import : imports)
- m_importer->importHelper(import.module, &types, import.prefix, import.version);
-
- result->resolveTypes(types.qmlNames);
+ result->setInternalName(QFileInfo(m_filePath).baseName());
return std::move(*result);
}
diff --git a/src/qmlcompiler/qqmljstypereader.cpp b/src/qmlcompiler/qqmljstypereader.cpp
index 0e12c8de95..578b0378c3 100644
--- a/src/qmlcompiler/qqmljstypereader.cpp
+++ b/src/qmlcompiler/qqmljstypereader.cpp
@@ -40,34 +40,6 @@
QT_BEGIN_NAMESPACE
-static QList<QQmlJSTypeReader::Import> parseHeaders(QQmlJS::AST::UiHeaderItemList *header)
-{
- using namespace QQmlJS::AST;
- QList<QQmlJSTypeReader::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(u'.');
- 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 QQmlJSScope::Ptr parseProgram(QQmlJS::AST::Program *program, const QString &name)
{
using namespace QQmlJS::AST;
@@ -126,11 +98,11 @@ QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
if (!isJavaScript) {
QQmlJS::AST::UiProgram *program = parser.ast();
- m_imports = parseHeaders(program->headers);
- QQmlJSImportVisitor membersVisitor;
- program->members->accept(&membersVisitor);
+ QQmlJSImportVisitor membersVisitor(m_importer, QFileInfo(m_file).canonicalPath(),
+ m_qmltypesFiles);
+ program->accept(&membersVisitor);
m_errors = membersVisitor.errors();
- return membersVisitor.result(scopeName);
+ return membersVisitor.result();
}
// TODO: Anything special to do with ES modules here?
diff --git a/src/qmlcompiler/qqmljstypereader_p.h b/src/qmlcompiler/qqmljstypereader_p.h
index 4a6c2c2cd0..4e9d26c08c 100644
--- a/src/qmlcompiler/qqmljstypereader_p.h
+++ b/src/qmlcompiler/qqmljstypereader_p.h
@@ -40,6 +40,7 @@
// We mean it.
#include "qqmljsscope_p.h"
+#include "qqmljsimporter_p.h"
#include <QtQml/private/qqmljsastfwd_p.h>
#include <QtQml/private/qqmljsdiagnosticmessage_p.h>
@@ -52,21 +53,20 @@ QT_BEGIN_NAMESPACE
class QQmlJSTypeReader
{
public:
- struct Import {
- QString module;
- QTypeRevision version;
- QString prefix;
- };
-
- QQmlJSTypeReader(const QString &file) : m_file(file) {}
+ QQmlJSTypeReader(QQmlJSImporter *importer, const QString &file,
+ const QStringList &qmltypesFiles = QStringList())
+ : m_importer(importer)
+ , m_file(file)
+ , m_qmltypesFiles(qmltypesFiles)
+ {}
QQmlJSScope::Ptr operator()();
- QList<Import> imports() const { return m_imports; }
QList<QQmlJS::DiagnosticMessage> errors() const { return m_errors; }
private:
+ QQmlJSImporter *m_importer;
QString m_file;
- QList<Import> m_imports;
+ QStringList m_qmltypesFiles;
QList<QQmlJS::DiagnosticMessage> m_errors;
};
diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp
index b7d331521c..09c39ddd63 100644
--- a/tools/qmllint/checkidentifiers.cpp
+++ b/tools/qmllint/checkidentifiers.cpp
@@ -373,8 +373,8 @@ bool CheckIdentifiers::operator()(
printContext(m_code, m_colorOut, location);
- // root(JS) --> program(qml) --> (first element)
- const auto firstElement = root->childScopes()[0]->childScopes()[0];
+ // root(JS) --> (first element)
+ const auto firstElement = root->childScopes()[0];
if (firstElement->properties().contains(memberAccessBase.m_name)
|| firstElement->methods().contains(memberAccessBase.m_name)
|| firstElement->enums().contains(memberAccessBase.m_name)) {
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index 962ccaa1c6..6f8c64aabc 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -43,18 +43,6 @@
#include <QtCore/qdiriterator.h>
#include <QtCore/qscopedvaluerollback.h>
-void FindWarningVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QString &name)
-{
- m_currentScope = QQmlJSScope::create(type, m_currentScope);
- m_currentScope->setBaseTypeName(name);
- m_currentScope->setIsComposite(true);
-}
-
-void FindWarningVisitor::leaveEnvironment()
-{
- m_currentScope = m_currentScope->parentScope();
-}
-
void FindWarningVisitor::importExportedNames(QQmlJSScope::ConstPtr scope)
{
QList<QQmlJSScope::ConstPtr> scopes;
@@ -123,47 +111,10 @@ void FindWarningVisitor::flushPendingSignalParameters()
void FindWarningVisitor::throwRecursionDepthError()
{
- m_errors.append({
- QStringLiteral("Maximum statement or expression depth exceeded"),
- QtCriticalMsg,
- QQmlJS::SourceLocation()
- });
+ QQmlJSImportVisitor::throwRecursionDepthError();
m_visitFailed = true;
}
-bool FindWarningVisitor::visit(QQmlJS::AST::UiProgram *)
-{
- enterEnvironment(QQmlJSScope::QMLScope, "program");
- m_rootScopeImports = m_importer.importBuiltins();
-
- if (!m_qmltypesFiles.isEmpty()) {
- const auto baseTypes = m_importer.importQmltypes(m_qmltypesFiles);
- m_rootScopeImports.insert(baseTypes);
- }
-
- const auto imported = m_importer.importDirectory(QFileInfo(m_filePath).canonicalPath());
- m_rootScopeImports.insert(imported);
-
- m_errors.append(m_importer.takeWarnings());
- return true;
-}
-
-void FindWarningVisitor::endVisit(QQmlJS::AST::UiProgram *)
-{
- leaveEnvironment();
-}
-
-bool FindWarningVisitor::visit(QQmlJS::AST::ClassExpression *ast)
-{
- enterEnvironment(QQmlJSScope::JSFunctionScope, ast->name.toString());
- return true;
-}
-
-void FindWarningVisitor::endVisit(QQmlJS::AST::ClassExpression *)
-{
- leaveEnvironment();
-}
-
bool FindWarningVisitor::visit(QQmlJS::AST::ClassDeclaration *ast)
{
enterEnvironment(QQmlJSScope::JSFunctionScope, ast->name.toString());
@@ -301,14 +252,12 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
// found id
auto expstat = cast<ExpressionStatement *>(uisb->statement);
auto identexp = cast<IdentifierExpression *>(expstat->expression);
- m_qmlid2scope.insert(identexp->name.toString(), m_currentScope);
+ m_scopesById.insert(identexp->name.toString(), m_currentScope);
// Figure out whether the current scope is the root scope.
if (auto parentScope = m_currentScope->parentScope()) {
- if (auto grandParentScope = parentScope->parentScope()) {
- if (!grandParentScope->parentScope())
- m_rootId = identexp->name.toString();
- }
+ if (!parentScope->parentScope())
+ m_rootId = identexp->name.toString();
}
} else {
const QString signal = signalName(name);
@@ -389,21 +338,18 @@ bool FindWarningVisitor::visit(QQmlJS::AST::IdentifierExpression *idexp)
}
FindWarningVisitor::FindWarningVisitor(
- QStringList qmlImportPaths, QStringList qmltypesFiles, QString code, QString fileName,
+ QQmlJSImporter *importer, QStringList qmltypesFiles, QString code, QString fileName,
bool silent, bool warnUnqualified, bool warnWithStatement, bool warnInheritanceCycle)
- : m_rootScope(QQmlJSScope::create(QQmlJSScope::JSFunctionScope)),
- m_qmltypesFiles(std::move(qmltypesFiles)),
+ : QQmlJSImportVisitor(importer, QFileInfo {fileName}.canonicalPath(), qmltypesFiles),
m_code(std::move(code)),
m_rootId(QLatin1String("<id>")),
m_filePath(std::move(fileName)),
m_colorOut(silent),
m_warnUnqualified(warnUnqualified),
m_warnWithStatement(warnWithStatement),
- m_warnInheritanceCycle(warnInheritanceCycle),
- m_importer(qmlImportPaths)
+ m_warnInheritanceCycle(warnInheritanceCycle)
{
- m_rootScope->setInternalName("global");
- m_currentScope = m_rootScope;
+ m_currentScope->setInternalName("global");
// setup color output
m_colorOut.insertMapping(Error, ColorOutput::RedForeground);
@@ -472,7 +418,7 @@ bool FindWarningVisitor::check()
// now that all ids are known, revisit any Connections whose target were perviously unknown
for (auto const &outstandingConnection: m_outstandingConnections) {
- auto targetScope = m_qmlid2scope[outstandingConnection.targetName];
+ auto targetScope = m_scopesById[outstandingConnection.targetName];
if (outstandingConnection.scope && !targetScope.isNull())
outstandingConnection.scope->addMethods(targetScope->methods());
QScopedValueRollback<QQmlJSScope::Ptr> rollback(m_currentScope, outstandingConnection.scope);
@@ -483,7 +429,7 @@ bool FindWarningVisitor::check()
return true;
CheckIdentifiers check(&m_colorOut, m_code, m_rootScopeImports, m_filePath);
- return check(m_qmlid2scope, m_signalHandlers, m_memberAccessChains, m_rootScope, m_rootId);
+ return check(m_scopesById, m_signalHandlers, m_memberAccessChains, m_globalScope, m_rootId);
}
bool FindWarningVisitor::visit(QQmlJS::AST::VariableDeclarationList *vdl)
@@ -502,48 +448,6 @@ bool FindWarningVisitor::visit(QQmlJS::AST::VariableDeclarationList *vdl)
return true;
}
-void FindWarningVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr)
-{
- using namespace QQmlJS::AST;
- auto name = fexpr->name.toString();
- if (!name.isEmpty()) {
- if (m_currentScope->scopeType() == QQmlJSScope::QMLScope) {
- m_currentScope->addMethod(QQmlJSMetaMethod(name, QLatin1String("void")));
- } else {
- m_currentScope->insertJSIdentifier(
- name, {
- QQmlJSScope::JavaScriptIdentifier::LexicalScoped,
- fexpr->firstSourceLocation()
- });
- }
- enterEnvironment(QQmlJSScope::JSFunctionScope, name);
- } else {
- enterEnvironment(QQmlJSScope::JSFunctionScope, QLatin1String("<anon>"));
- }
-}
-
-bool FindWarningVisitor::visit(QQmlJS::AST::FunctionExpression *fexpr)
-{
- visitFunctionExpressionHelper(fexpr);
- return true;
-}
-
-void FindWarningVisitor::endVisit(QQmlJS::AST::FunctionExpression *)
-{
- leaveEnvironment();
-}
-
-bool FindWarningVisitor::visit(QQmlJS::AST::FunctionDeclaration *fdecl)
-{
- visitFunctionExpressionHelper(fdecl);
- return true;
-}
-
-void FindWarningVisitor::endVisit(QQmlJS::AST::FunctionDeclaration *)
-{
- leaveEnvironment();
-}
-
bool FindWarningVisitor::visit(QQmlJS::AST::FormalParameterList *fpl)
{
for (auto const &boundName : fpl->boundNames()) {
@@ -556,50 +460,6 @@ bool FindWarningVisitor::visit(QQmlJS::AST::FormalParameterList *fpl)
return true;
}
-bool FindWarningVisitor::visit(QQmlJS::AST::UiImport *import)
-{
- // construct path
- QString prefix = QLatin1String("");
- if (import->asToken.isValid()) {
- prefix += import->importId;
- }
- auto filename = import->fileName.toString();
- if (!filename.isEmpty()) {
- const QFileInfo file(filename);
- const QFileInfo path(file.isRelative() ? QFileInfo(m_filePath).dir().filePath(filename)
- : filename);
- if (path.isDir()) {
- m_rootScopeImports.insert(m_importer.importDirectory(path.canonicalFilePath(), prefix));
- } else if (path.isFile()) {
- const auto scope = m_importer.importFile(path.canonicalFilePath());
- m_rootScopeImports.insert(prefix.isEmpty() ? scope->internalName() : prefix, scope);
- }
-
- }
-
- QString path {};
- if (!import->importId.isEmpty()) {
- // TODO: do not put imported ids into the same space as qml IDs
- const QString importId = import->importId.toString();
- m_qmlid2scope.insert(importId, m_rootScopeImports.value(importId));
- }
- auto uri = import->importUri;
- while (uri) {
- path.append(uri->name);
- path.append("/");
- uri = uri->next;
- }
- path.chop(1);
-
- const auto imported = m_importer.importModule(
- path, prefix, import->version ? import->version->version : QTypeRevision());
-
- m_rootScopeImports.insert(imported);
-
- m_errors.append(m_importer.takeWarnings());
- return true;
-}
-
bool FindWarningVisitor::visit(QQmlJS::AST::UiEnumDeclaration *uied)
{
QQmlJSMetaEnum qmlEnum(uied->name.toString());
@@ -689,8 +549,8 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiObjectDefinition *uiod)
targetScope = m_rootScopeImports.value(scope->baseTypeName());
} else {
// there was a target, check if we already can find it
- auto scopeIt = m_qmlid2scope.find(target);
- if (scopeIt != m_qmlid2scope.end()) {
+ auto scopeIt = m_scopesById.find(target);
+ if (scopeIt != m_scopesById.end()) {
targetScope = *scopeIt;
} else {
m_outstandingConnections.push_back({target, m_currentScope, uiod});
@@ -727,8 +587,8 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *)
auto childScope = m_currentScope;
leaveEnvironment();
- if (m_currentScope->baseTypeName() == QStringLiteral("Component")
- || m_currentScope->baseTypeName() == QStringLiteral("program")) {
+ if (m_currentScope == m_globalScope
+ || m_currentScope->baseTypeName() == QStringLiteral("Component")) {
return;
}
diff --git a/tools/qmllint/findwarnings.h b/tools/qmllint/findwarnings.h
index 7d07114b32..da32f4c9d5 100644
--- a/tools/qmllint/findwarnings.h
+++ b/tools/qmllint/findwarnings.h
@@ -45,6 +45,7 @@
#include <QtQmlCompiler/private/qqmljstypedescriptionreader_p.h>
#include <QtQmlCompiler/private/qqmljsscope_p.h>
#include <QtQmlCompiler/private/qqmljsimporter_p.h>
+#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
#include <QtQml/private/qqmldirparser_p.h>
#include <QtQml/private/qqmljsastvisitor_p.h>
@@ -52,34 +53,27 @@
#include <QtCore/qscopedpointer.h>
-class FindWarningVisitor : public QQmlJS::AST::Visitor
+class FindWarningVisitor : public QQmlJSImportVisitor
{
Q_DISABLE_COPY_MOVE(FindWarningVisitor)
public:
explicit FindWarningVisitor(
- QStringList qmlImportPaths, QStringList qmltypesFiles, QString code, QString fileName,
+ QQmlJSImporter *importer, QStringList qmltypesFiles, QString code, QString fileName,
bool silent, bool warnUnqualified, bool warnWithStatement, bool warnInheritanceCycle);
~FindWarningVisitor() override = default;
bool check();
private:
- QQmlJSImporter::ImportedTypes m_rootScopeImports;
-
QHash<QQmlJS::SourceLocation, SignalHandler> m_signalHandlers;
QQmlJS::SourceLocation m_pendingSingalHandler;
MemberAccessChains m_memberAccessChains;
- QQmlJSScope::Ptr m_rootScope;
- QQmlJSScope::Ptr m_currentScope;
QQmlJS::AST::ExpressionNode *m_fieldMemberBase = nullptr;
- QStringList m_qmltypesFiles;
QString m_code;
- QHash<QString, QQmlJSScope::ConstPtr> m_qmlid2scope;
QString m_rootId;
QString m_filePath;
QSet<QString> m_unknownImports;
- QList<QQmlJS::DiagnosticMessage> m_errors;
ColorOutput m_colorOut;
bool m_visitFailed = false;
@@ -96,11 +90,6 @@ private:
QVarLengthArray<OutstandingConnection, 3> m_outstandingConnections; // Connections whose target we have not encountered
- QQmlJSImporter m_importer;
-
- void enterEnvironment(QQmlJSScope::ScopeType type, const QString &name);
- void leaveEnvironment();
-
void importExportedNames(QQmlJSScope::ConstPtr scope);
void parseHeaders(QQmlJS::AST::UiHeaderItemList *headers);
@@ -110,12 +99,6 @@ private:
void throwRecursionDepthError() override;
// start block/scope handling
- bool visit(QQmlJS::AST::UiProgram *ast) override;
- void endVisit(QQmlJS::AST::UiProgram *ast) override;
-
- bool visit(QQmlJS::AST::ClassExpression *ast) override;
- void endVisit(QQmlJS::AST::ClassExpression *ast) override;
-
bool visit(QQmlJS::AST::ClassDeclaration *ast) override;
void endVisit(QQmlJS::AST::ClassDeclaration *ast) override;
@@ -140,18 +123,11 @@ private:
bool visit(QQmlJS::AST::WithStatement *withStatement) override;
void endVisit(QQmlJS::AST::WithStatement *ast) override;
- void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
- bool visit(QQmlJS::AST::FunctionExpression *fexpr) override;
- void endVisit(QQmlJS::AST::FunctionExpression *fexpr) override;
-
- bool visit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
- void endVisit(QQmlJS::AST::FunctionDeclaration *fdecl) override;
/* --- end block handling --- */
bool visit(QQmlJS::AST::VariableDeclarationList *vdl) override;
bool visit(QQmlJS::AST::FormalParameterList *fpl) override;
- bool visit(QQmlJS::AST::UiImport *import) override;
bool visit(QQmlJS::AST::UiEnumDeclaration *uied) override;
bool visit(QQmlJS::AST::UiObjectBinding *uiob) override;
void endVisit(QQmlJS::AST::UiObjectBinding *uiob) override;
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 1112f64d7c..a877b20335 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -86,7 +86,8 @@ static bool lint_file(const QString &filename, const bool silent, const bool war
if (success && !isJavaScript) {
auto root = parser.rootNode();
- FindWarningVisitor v { qmlImportPaths, qmltypesFiles, code, filename, silent,
+ QQmlJSImporter importer(qmlImportPaths);
+ FindWarningVisitor v { &importer, qmltypesFiles, code, filename, silent,
warnUnqualified, warnWithStatement, warnInheritanceCycle };
root->accept(&v);
success = v.check();