aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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();