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: u"Could not determine signature of binding for %1: %2"_s
45 .arg(args: name, args&: initializationError.message),
46 type: initializationError.type, location: initializationError.loc);
47 }
48
49 QQmlJS::DiagnosticMessage analyzeError;
50 if (!analyzeFunction(context, function: &function, error: &analyzeError)) {
51 // If it's a signal and the function just returns a closure, it's harmless.
52 // Otherwise promote the message to warning level.
53 return diagnose(message: u"Could not compile binding for %1: %2"_s.arg(args: name, args&: analyzeError.message),
54 type: (function.isSignalHandler && analyzeError.type == QtDebugMsg)
55 ? QtDebugMsg
56 : QtWarningMsg,
57 location: analyzeError.loc);
58 }
59
60 return QQmlJSAotFunction {};
61}
62
63std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage>
64QQmlJSLinterCodegen::compileFunction(const QV4::Compiler::Context *context,
65 const QString &name, QQmlJS::AST::Node *astNode)
66{
67 QQmlJS::DiagnosticMessage initializationError;
68 QQmlJSFunctionInitializer initializer(
69 &m_typeResolver, m_currentObject->location, m_currentScope->location);
70 QQmlJSCompilePass::Function function =
71 initializer.run(context, functionName: name, astNode, error: &initializationError);
72 if (initializationError.isValid()) {
73 diagnose(message: u"Could not determine signature of function %1: %2"_s
74 .arg(args: name, args&: initializationError.message),
75 type: initializationError.type, location: initializationError.loc);
76 }
77
78 QQmlJS::DiagnosticMessage analyzeError;
79 if (!analyzeFunction(context, function: &function, error: &analyzeError)) {
80 return diagnose(message: u"Could not compile function %1: %2"_s.arg(args: name, args&: analyzeError.message),
81 type: QtWarningMsg, location: analyzeError.loc);
82 }
83
84 return QQmlJSAotFunction {};
85}
86
87void QQmlJSLinterCodegen::setPassManager(QQmlSA::PassManager *passManager)
88{
89 m_passManager = passManager;
90 auto managerPriv = QQmlSA::PassManagerPrivate::get(manager: passManager);
91 managerPriv->m_typeResolver = typeResolver();
92}
93
94bool QQmlJSLinterCodegen::analyzeFunction(const QV4::Compiler::Context *context,
95 QQmlJSCompilePass::Function *function,
96 QQmlJS::DiagnosticMessage *error)
97{
98 QQmlJSTypePropagator propagator(m_unitGenerator, &m_typeResolver, m_logger,
99 {}, {}, m_passManager);
100 auto [basicBlocks, annotations] = propagator.run(m_function: function, error);
101 if (!error->isValid()) {
102 QQmlJSShadowCheck shadowCheck(m_unitGenerator, &m_typeResolver, m_logger, basicBlocks,
103 annotations);
104 shadowCheck.run(function, error);
105 }
106
107 if (!error->isValid()) {
108 QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger,
109 basicBlocks, annotations);
110 generalizer.run(function, error);
111 }
112
113 if (error->isValid()) {
114 error->type = context->returnsClosure ? QtDebugMsg : QtWarningMsg;
115 return false;
116 }
117
118 return true;
119}
120
121QT_END_NAMESPACE
122

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