1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qqmljslintercodegen_p.h"
5
6#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
7#include <QtQmlCompiler/private/qqmljsshadowcheck_p.h>
8#include <QtQmlCompiler/private/qqmljsstoragegeneralizer_p.h>
9#include <QtQmlCompiler/private/qqmljstypepropagator_p.h>
10#include <QtQmlCompiler/private/qqmljsfunctioninitializer_p.h>
11
12#include <QFileInfo>
13
14QT_BEGIN_NAMESPACE
15
16using namespace Qt::StringLiterals;
17
18QQmlJSLinterCodegen::QQmlJSLinterCodegen(QQmlJSImporter *importer, const QString &fileName,
19 const QStringList &qmldirFiles, QQmlJSLogger *logger)
20 : QQmlJSAotCompiler(importer, fileName, qmldirFiles, logger)
21{
22}
23
24void QQmlJSLinterCodegen::setDocument(const QmlIR::JSCodeGen *codegen,
25 const QmlIR::Document *document)
26{
27 Q_UNUSED(codegen);
28 m_document = document;
29 m_unitGenerator = &document->jsGenerator;
30}
31
32std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage>
33QQmlJSLinterCodegen::compileBinding(const QV4::Compiler::Context *context,
34 const QmlIR::Binding &irBinding, QQmlJS::AST::Node *astNode)
35{
36 QQmlJSFunctionInitializer initializer(
37 &m_typeResolver, m_currentObject->location, m_currentScope->location);
38
39 QQmlJS::DiagnosticMessage initializationError;
40 const QString name = m_document->stringAt(index: irBinding.propertyNameIndex);
41 QQmlJSCompilePass::Function function =
42 initializer.run(context, propertyName: name, astNode, irBinding, error: &initializationError);
43 if (initializationError.isValid())
44 diagnose(message: initializationError.message, type: initializationError.type, location: initializationError.loc);
45
46 QQmlJS::DiagnosticMessage analyzeError;
47 if (!analyzeFunction(context, function: &function, error: &analyzeError)) {
48 // If it's a signal and the function just returns a closure, it's harmless.
49 // Otherwise promote the message to warning level.
50 return diagnose(message: u"Could not compile binding for %1: %2"_s.arg(args: name, args&: analyzeError.message),
51 type: (function.isSignalHandler && analyzeError.type == QtDebugMsg)
52 ? QtDebugMsg
53 : QtWarningMsg,
54 location: analyzeError.loc);
55 }
56
57 return QQmlJSAotFunction {};
58}
59
60std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage>
61QQmlJSLinterCodegen::compileFunction(const QV4::Compiler::Context *context,
62 const QString &name, QQmlJS::AST::Node *astNode)
63{
64 QQmlJS::DiagnosticMessage initializationError;
65 QQmlJSFunctionInitializer initializer(
66 &m_typeResolver, m_currentObject->location, m_currentScope->location);
67 QQmlJSCompilePass::Function function =
68 initializer.run(context, functionName: name, astNode, error: &initializationError);
69 if (initializationError.isValid())
70 diagnose(message: initializationError.message, type: initializationError.type, location: initializationError.loc);
71
72 QQmlJS::DiagnosticMessage analyzeError;
73 if (!analyzeFunction(context, function: &function, error: &analyzeError)) {
74 return diagnose(message: u"Could not compile function %1: %2"_s.arg(args: name, args&: analyzeError.message),
75 type: QtWarningMsg, location: analyzeError.loc);
76 }
77
78 return QQmlJSAotFunction {};
79}
80
81bool QQmlJSLinterCodegen::analyzeFunction(const QV4::Compiler::Context *context,
82 QQmlJSCompilePass::Function *function,
83 QQmlJS::DiagnosticMessage *error)
84{
85 QQmlJSTypePropagator propagator(m_unitGenerator, &m_typeResolver, m_logger,
86 m_passManager);
87 QQmlJSCompilePass::InstructionAnnotations annotations = propagator.run(m_function: function, error);
88 if (!error->isValid()) {
89 QQmlJSShadowCheck shadowCheck(m_unitGenerator, &m_typeResolver, m_logger);
90 shadowCheck.run(annotations: &annotations, function, error);
91 }
92
93 if (!error->isValid()) {
94 QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger);
95 generalizer.run(annotations, function, error);
96 }
97
98 if (error->isValid()) {
99 error->type = context->returnsClosure ? QtDebugMsg : QtWarningMsg;
100 return false;
101 }
102
103 return true;
104}
105
106QT_END_NAMESPACE
107

source code of qtdeclarative/src/qmlcompiler/qqmljslintercodegen.cpp