QmlCompiler: Tighten the constness of various method parameters

The compile passes shouldn't need to change the document, AST, or IR. At
least not accidentally. We might add interfaces to explicitly modify
things later. As a side effect, you can now use one instance of
QQmlJSTypeResolver for multiple documents by re-init()'ing it.

Change-Id: Ic3544b3ddedd30d7f8d00b1df9cee3e6292ca7de
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2021-11-18 14:24:12 +01:00
parent cb3ec010ff
commit 17bfd9c694
12 changed files with 26 additions and 23 deletions

View File

@ -74,7 +74,7 @@ class QQmlJSAotCompiler
public:
virtual ~QQmlJSAotCompiler() = default;
virtual void setDocument(QmlIR::JSCodeGen *codegen, QmlIR::Document *document) = 0;
virtual void setDocument(const QmlIR::JSCodeGen *codegen, const QmlIR::Document *document) = 0;
virtual void setScope(const QmlIR::Object *object, const QmlIR::Object *scope) = 0;
virtual std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> compileBinding(
const QV4::Compiler::Context *context,

View File

@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE
class QQmlJSShadowCheck : public QQmlJSCompilePass
{
public:
QQmlJSShadowCheck(QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
QQmlJSShadowCheck(const QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger)
: QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger)
{}

View File

@ -31,7 +31,7 @@
QT_BEGIN_NAMESPACE
QQmlJSTypePropagator::QQmlJSTypePropagator(QV4::Compiler::JSUnitGenerator *unitGenerator,
QQmlJSTypePropagator::QQmlJSTypePropagator(const QV4::Compiler::JSUnitGenerator *unitGenerator,
QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger,
QQmlJSTypeInfo *typeInfo)
: QQmlJSCompilePass(unitGenerator, typeResolver, logger), m_typeInfo(typeInfo)

View File

@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
struct QQmlJSTypePropagator : public QQmlJSCompilePass
{
QQmlJSTypePropagator(QV4::Compiler::JSUnitGenerator *unitGenerator,
QQmlJSTypePropagator(const QV4::Compiler::JSUnitGenerator *unitGenerator,
QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger,
QQmlJSTypeInfo *typeInfo = nullptr);

View File

@ -63,8 +63,7 @@ static bool searchBaseAndExtensionTypes(const QQmlJSScope::ConstPtr type, const
return false;
}
QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer, QQmlJSLogger *logger)
: m_logger(logger)
QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
{
const QHash<QString, QQmlJSScope::ConstPtr> builtinTypes = importer->builtinInternalNames();
m_voidType = builtinTypes[u"void"_qs];
@ -114,6 +113,13 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer, QQmlJSLogger *l
*/
void QQmlJSTypeResolver::init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *program)
{
m_logger = visitor->logger();
m_objectsById.clear();
m_objectsByLocation.clear();
m_imports.clear();
m_signalHandlers.clear();
program->accept(visitor);
m_objectsById = visitor->addressableScopes();

View File

@ -62,7 +62,7 @@ public:
QString setter;
};
QQmlJSTypeResolver(QQmlJSImporter *importer, QQmlJSLogger *logger);
QQmlJSTypeResolver(QQmlJSImporter *importer);
// Note: must be called after the construction to read the QML program
void init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *program);

View File

@ -47,11 +47,10 @@ Codegen::Codegen(const QString &fileName, const QStringList &qmltypesFiles, QQml
{
}
void Codegen::setDocument(QmlIR::JSCodeGen *codegen, QmlIR::Document *document)
void Codegen::setDocument(const QmlIR::JSCodeGen *codegen, const QmlIR::Document *document)
{
Q_UNUSED(codegen);
m_document = document;
m_pool = document->jsParserEngine.pool();
m_unitGenerator = &document->jsGenerator;
m_entireSourceCodeLines = document->code.split(u'\n');
}
@ -164,19 +163,20 @@ Codegen::compileBinding(const QV4::Compiler::Context *context, const QmlIR::Bind
m_currentObject->functionsAndExpressions->slowAt(irBinding.value.compiledScriptIndex)
->node;
auto ast = astNode->asFunctionDefinition();
QQmlJS::MemoryPool pool;
if (!ast) {
QQmlJS::AST::Statement *stmt = astNode->statementCast();
if (!stmt) {
Q_ASSERT(astNode->expressionCast());
QQmlJS::AST::ExpressionNode *expr = astNode->expressionCast();
stmt = new (m_pool) QQmlJS::AST::ExpressionStatement(expr);
stmt = new (&pool) QQmlJS::AST::ExpressionStatement(expr);
}
auto body = new (m_pool) QQmlJS::AST::StatementList(stmt);
auto body = new (&pool) QQmlJS::AST::StatementList(stmt);
body = body->finish();
QString name = u"binding for "_qs; // ####
ast = new (m_pool) QQmlJS::AST::FunctionDeclaration(m_pool->newString(name),
/*formals*/ nullptr, body);
ast = new (&pool) QQmlJS::AST::FunctionDeclaration(
pool.newString(name), /*formals*/ nullptr, body);
ast->lbraceToken = astNode->firstSourceLocation();
ast->functionToken = ast->lbraceToken;
ast->rbraceToken = astNode->lastSourceLocation();

View File

@ -62,7 +62,7 @@ public:
Codegen(const QString &fileName, const QStringList &qmltypesFiles,
QQmlJSLogger *logger, QQmlJSTypeInfo *typeInfo, const QString &m_code);
void setDocument(QmlIR::JSCodeGen *codegen, QmlIR::Document *document) override;
void setDocument(const QmlIR::JSCodeGen *codegen, const QmlIR::Document *document) override;
void setScope(const QmlIR::Object *object, const QmlIR::Object *scope) override;
std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage>
compileBinding(const QV4::Compiler::Context *context, const QmlIR::Binding &irBinding) override;
@ -85,11 +85,10 @@ private:
const QStringList m_resourceFiles;
const QStringList m_qmltypesFiles;
QQmlJS::MemoryPool *m_pool = nullptr;
const QmlIR::Object *m_currentObject = nullptr;
QQmlJSScope::ConstPtr m_scopeType;
QQmlJSScope::ConstPtr m_objectType;
QV4::Compiler::JSUnitGenerator *m_unitGenerator = nullptr;
const QV4::Compiler::JSUnitGenerator *m_unitGenerator = nullptr;
QStringList m_entireSourceCodeLines;
QQmlJSLogger *m_logger;
QQmlJSTypeInfo *m_typeInfo;

View File

@ -185,7 +185,7 @@ bool QQmlLinter::lintFile(const QString &filename, const QString *fileContents,
}
std::unique_ptr<QQmlJSTypeResolver> typeResolver
= std::make_unique<QQmlJSTypeResolver>(&m_importer, m_logger.get());
= std::make_unique<QQmlJSTypeResolver>(&m_importer);
// Type resolving is using document parent mode here so that it produces fewer false positives
// on the "parent" property of QQuickItem. It does produce a few false negatives this way

View File

@ -85,7 +85,7 @@ class tst_qqmljsscope : public QQmlDataTest
QQmlJSImporter importer { importPaths, /* resource file mapper */ nullptr };
QQmlJSLogger logger(url, sourceCode, /* silent */ true);
QQmlJSImportVisitor visitor(&importer, &logger, dataDirectory());
QQmlJSTypeResolver typeResolver { &importer, &logger };
QQmlJSTypeResolver typeResolver { &importer };
typeResolver.init(&visitor, document.program);
return visitor.result();
}

View File

@ -173,8 +173,9 @@ int main(int argc, char **argv)
QQmlJSLogger logger(url, sourceCode, /* silent */ false);
setupLogger(logger);
QmltcVisitor visitor(&importer, &logger, implicitImportDirectory, qmltypesFiles);
QmltcTypeResolver typeResolver { &importer, &logger };
QmltcTypeResolver typeResolver { &importer };
typeResolver.init(&visitor, document.program);
if (logger.hasWarnings() || logger.hasErrors())
return EXIT_FAILURE;

View File

@ -39,10 +39,7 @@ QT_BEGIN_NAMESPACE
class QmltcTypeResolver : public QQmlJSTypeResolver
{
public:
QmltcTypeResolver(QQmlJSImporter *importer, QQmlJSLogger *logger)
: QQmlJSTypeResolver(importer, logger)
{
}
QmltcTypeResolver(QQmlJSImporter *importer) : QQmlJSTypeResolver(importer) {}
};
QT_END_NAMESPACE