Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmldomexternalitems.cpp
Go to the documentation of this file.
1
// Copyright (C) 2020 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
#
include
"qqmldomtop_p.h"
5
#
include
"qqmldomoutwriter_p.h"
6
#
include
"qqmldomcomments_p.h"
7
#
include
"qqmldommock_p.h"
8
#
include
"qqmldomelements_p.h"
9
#
include
"qqmldom_utils_p.h"
10
11
#
include
<
QtQml
/
private
/
qqmljslexer_p
.
h
>
12
#
include
<
QtQml
/
private
/
qqmljsparser_p
.
h
>
13
#
include
<
QtQml
/
private
/
qqmljsengine_p
.
h
>
14
#
include
<
QtQml
/
private
/
qqmljsastvisitor_p
.
h
>
15
#
include
<
QtQml
/
private
/
qqmljsast_p
.
h
>
16
#
include
<
QtCore
/
QDir
>
17
#
include
<
QtCore
/
QScopeGuard
>
18
#
include
<
QtCore
/
QFileInfo
>
19
#
include
<
QtCore
/
QRegularExpressionMatch
>
20
21
#
include
<
algorithm
>
22
23
QT_BEGIN_NAMESPACE
24
25
using
namespace
Qt::StringLiterals;
26
27
namespace
QQmlJS
{
28
namespace
Dom
{
29
30
ExternalOwningItem
::
ExternalOwningItem
(
31
const
QString
&
filePath
,
const
QDateTime
&
lastDataUpdateAt
,
const
Path
&
path
,
32
int
derivedFrom
,
const
QString
&
code
)
33
:
OwningItem
(
derivedFrom
,
lastDataUpdateAt
),
34
m_canonicalFilePath
(
filePath
),
35
m_code
(
code
),
36
m_path
(
path
)
37
{}
38
39
QString
ExternalOwningItem
::
canonicalFilePath
(
const
DomItem
&)
const
40
{
41
return
m_canonicalFilePath
;
42
}
43
44
QString
ExternalOwningItem
::
canonicalFilePath
()
const
45
{
46
return
m_canonicalFilePath
;
47
}
48
49
Path
ExternalOwningItem
::
canonicalPath
(
const
DomItem
&)
const
50
{
51
return
m_path
;
52
}
53
54
Path
ExternalOwningItem
::
canonicalPath
()
const
55
{
56
return
m_path
;
57
}
58
59
QCborValue
pluginData
(
const
QQmlDirParser::Plugin &pl,
const
QStringList &cNames)
60
{
61
QCborArray names;
62
for
(
const
QString &n : cNames)
63
names.append(n);
64
return
QCborMap({ { QCborValue(QStringView(Fields::name)), pl.name },
65
{ QStringView(Fields::path), pl.path },
66
{ QStringView(Fields::classNames), names } });
67
}
68
69
JsFile
::
JsFile
(
70
const
QString
&
filePath
,
const
QString
&
code
,
const
QDateTime
&
lastDataUpdateAt
,
71
int
derivedFrom
)
72
:
ExternalOwningItem
(
filePath
,
lastDataUpdateAt
,
Paths
::
qmlFilePath
(
filePath
),
derivedFrom
,
73
code
)
74
{
75
m_engine
=
std
::
make_shared
<
QQmlJS
::
Engine
>();
76
LegacyDirectivesCollector
directivesCollector
(*
this
);
77
m_engine
->
setDirectives
(&
directivesCollector
);
78
79
QQmlJS
::
Lexer
lexer
(
m_engine
.
get
());
80
lexer
.
setCode
(
code
,
/*lineno = */
1,
/*qmlMode=*/
false
);
81
QQmlJS
::
Parser
parser
(
m_engine
.
get
());
82
83
bool
isESM
=
filePath
.
endsWith
(u".mjs",
Qt
::
CaseInsensitive
);
84
bool
isValid
=
isESM
?
parser
.
parseModule
() :
parser
.
parseProgram
();
85
setIsValid
(
isValid
);
86
87
const
auto
diagnostics
=
parser
.
diagnosticMessages
();
88
for
(
const
DiagnosticMessage
&
msg
:
diagnostics
) {
89
addErrorLocal
(
90
std
::
move
(
myParsingErrors
().
errorMessage
(
msg
).
withFile
(
filePath
).
withPath
(
m_path
)));
91
}
92
93
auto
astComments
=
std
::
make_shared
<
AstComments
>(
m_engine
);
94
95
CommentCollector
collector
;
96
collector
.
collectComments
(
m_engine
,
parser
.
rootNode
(),
astComments
);
97
m_script
=
std
::
make_shared
<
ScriptExpression
>(
code
,
m_engine
,
parser
.
rootNode
(),
astComments
,
98
isESM
?
ScriptExpression
::
ExpressionType
::
ESMCode
99
:
ScriptExpression
::
ExpressionType
::
JSCode
);
100
}
101
102
ErrorGroups
JsFile
::
myParsingErrors
()
103
{
104
static
ErrorGroups
res
= { {
DomItem
::
domErrorGroup
,
NewErrorGroup
(
"JsFile"
),
105
NewErrorGroup
(
"Parsing"
) } };
106
return
res
;
107
}
108
109
bool
JsFile
::
iterateDirectSubpaths
(
const
DomItem
&
self
,
DirectVisitor
visitor
)
const
110
{
111
bool
cont
=
ExternalOwningItem
::
iterateDirectSubpaths
(
self
,
visitor
);
112
cont
=
cont
&&
self
.
invokeVisitorOnField
(
visitor
,
Fields
::
fileLocationsTree
,
m_fileLocationsTree
);
113
if
(
m_script
)
114
cont
=
cont
&&
visitor
(
PathEls
::
Field
(
Fields
::
expression
), [
this
, &
self
]() {
115
return
self
.
subOwnerItem
(
PathEls
::
Field
(
Fields
::
expression
),
m_script
);
116
});
117
return
cont
;
118
}
119
120
void
JsFile
::
writeOut
(
const
DomItem
&
self
,
OutWriter
&
ow
)
const
121
{
122
writeOutDirectives
(
self
,
ow
);
123
ow
.
ensureNewline
(2);
124
if
(
DomItem
script
=
self
.
field
(
Fields
::
expression
)) {
125
ow
.
ensureNewline
();
126
script
.
writeOut
(
ow
);
127
}
128
}
129
130
void
JsFile
::
addFileImport
(
const
QString
&
jsfile
,
const
QString
&
module
)
131
{
132
LegacyImport
import
;
133
import
.
fileName
=
jsfile
;
134
import
.
asIdentifier
=
module
;
135
m_imports
.
append
(
std
::
move
(
import
));
136
}
137
138
void
JsFile
::
addModuleImport
(
const
QString
&
uri
,
const
QString
&
version
,
const
QString
&
module
)
139
{
140
LegacyImport
import
;
141
import
.
uri
=
uri
;
142
import
.
version
=
version
;
143
import
.
asIdentifier
=
module
;
144
m_imports
.
append
(
std
::
move
(
import
));
145
}
146
147
void
JsFile
::
LegacyPragmaLibrary
::
writeOut
(
const
DomItem
&
self
,
OutWriter
&
lw
)
const
148
{
149
Q_UNUSED
(
self
);
150
lw
.
write
(u".pragma").
ensureSpace
().
write
(u"library").
ensureNewline
();
151
}
152
153
void
JsFile
::
LegacyImport
::
writeOut
(
const
DomItem
&
self
,
OutWriter
&
lw
)
const
154
{
155
const
auto
fLoc
=
FileLocations
::
treeOf
(
self
);
156
// either filename or module uri must be present
157
Q_ASSERT
(!
fileName
.
isEmpty
() || !
uri
.
isEmpty
());
158
159
lw
.
write
(u".import").
ensureSpace
();
160
if
(!
uri
.
isEmpty
()) {
161
lw
.
write
(
uri
).
ensureSpace
();
162
if
(!
version
.
isEmpty
()) {
163
lw
.
write
(
version
).
ensureSpace
();
164
}
165
}
else
{
166
lw
.
write
(u"\"").
write
(
fileName
).
write
(u"\"").
ensureSpace
();
167
}
168
lw
.
writeRegion
(
fLoc
,
AsTokenRegion
).
ensureSpace
().
write
(
asIdentifier
);
169
170
lw
.
ensureNewline
();
171
}
172
173
/*!
174
* \internal JsFile::writeOutDirectives
175
* \brief Performs writeOut of the .js Directives (.import, .pragma)
176
*
177
* Watch out!
178
* Currently directives in .js files do not have representative AST::Node-s (see QTBUG-119770),
179
* which makes it hard to preserve attached comments during the WriteOut process,
180
* because currently they are being attached to the first AST::Node.
181
* In case when the first AST::Node is absent, they are not collected, hence lost.
182
*/
183
void
JsFile
::
writeOutDirectives
(
const
DomItem
&
self
,
OutWriter
&
ow
)
const
184
{
185
if
(
m_pragmaLibrary
.
has_value
()) {
186
m_pragmaLibrary
->
writeOut
(
self
,
ow
);
187
}
188
for
(
const
auto
&
import
:
m_imports
) {
189
import
.
writeOut
(
self
,
ow
);
190
}
191
}
192
193
std
::
shared_ptr
<
OwningItem
>
QmlFile
::
doCopy
(
const
DomItem
&)
const
194
{
195
auto
res
=
std
::
make_shared
<
QmlFile
>(*
this
);
196
return
res
;
197
}
198
199
/*!
200
\class QmlFile
201
202
A QmlFile, when loaded in a DomEnvironment that has the DomCreationOption::WithSemanticAnalysis,
203
will be lazily constructed. That means that its member m_lazyMembers is uninitialized, and will
204
only be populated when it is accessed (through a getter, a setter or the DomItem interface).
205
206
The reason for the laziness is that the qqmljsscopes are created lazily and at the same time as
207
the Dom QmlFile representations. So instead of eagerly generating all qqmljsscopes when
208
constructing the Dom, the QmlFile itself becomes lazy and will only be populated on demand at
209
the same time as the corresponding qqmljsscopes.
210
211
The QDeferredFactory<QQmlJSScope> will, when the qqmljsscope is populated, take care of
212
populating all fields of the QmlFile.
213
Therefore, population of the QmlFile is done by populating the qqmljsscope.
214
215
*/
216
217
QmlFile
::
QmlFile
(
218
const
QString
&
filePath
,
const
QString
&
code
,
const
QDateTime
&
lastDataUpdateAt
,
219
int
derivedFrom
,
RecoveryOption
option
)
220
:
ExternalOwningItem
(
filePath
,
lastDataUpdateAt
,
Paths
::
qmlFilePath
(
filePath
),
derivedFrom
,
221
code
),
222
m_engine
(
new
QQmlJS
::
Engine
)
223
{
224
QQmlJS
::
Lexer
lexer
(
m_engine
.
get
());
225
lexer
.
setCode
(
code
,
/*lineno = */
1,
/*qmlMode=*/
true
);
226
QQmlJS
::
Parser
parser
(
m_engine
.
get
());
227
if
(
option
==
EnableParserRecovery
) {
228
parser
.
setIdentifierInsertionEnabled
(
true
);
229
parser
.
setIncompleteBindingsEnabled
(
true
);
230
}
231
m_isValid
=
parser
.
parse
();
232
const
auto
diagnostics
=
parser
.
diagnosticMessages
();
233
for
(
const
DiagnosticMessage
&
msg
:
diagnostics
) {
234
addErrorLocal
(
235
std
::
move
(
myParsingErrors
().
errorMessage
(
msg
).
withFile
(
filePath
).
withPath
(
m_path
)));
236
}
237
m_ast
=
parser
.
ast
();
238
}
239
240
ErrorGroups
QmlFile
::
myParsingErrors
()
241
{
242
static
ErrorGroups
res
= { {
DomItem
::
domErrorGroup
,
NewErrorGroup
(
"QmlFile"
),
243
NewErrorGroup
(
"Parsing"
) } };
244
return
res
;
245
}
246
247
bool
QmlFile
::
iterateDirectSubpaths
(
const
DomItem
&
self
,
DirectVisitor
visitor
)
const
248
{
249
auto
&
members
=
lazyMembers
();
250
bool
cont
=
ExternalOwningItem
::
iterateDirectSubpaths
(
self
,
visitor
);
251
cont
=
cont
&&
self
.
invokeVisitorOnField
(
visitor
,
Fields
::
components
,
members
.
m_components
);
252
cont
=
cont
&&
self
.
invokeVisitorOnField
(
visitor
,
Fields
::
pragmas
,
members
.
m_pragmas
);
253
cont
=
cont
&&
self
.
invokeVisitorOnField
(
visitor
,
Fields
::
imports
,
members
.
m_imports
);
254
cont
=
cont
&&
self
.
invokeVisitorOnField
(
visitor
,
Fields
::
fileLocationsTree
,
255
members
.
m_fileLocationsTree
);
256
cont
=
cont
&&
self
.
invokeVisitorOnField
(
visitor
,
Fields
::
comments
,
members
.
m_comments
);
257
cont
=
cont
&&
self
.
invokeVisitorOnField
(
visitor
,
Fields
::
astComments
,
members
.
m_astComments
);
258
return
cont
;
259
}
260
261
DomItem
QmlFile
::
field
(
const
DomItem
&
self
,
QStringView
name
)
const
262
{
263
ensurePopulated
();
264
if
(
name
==
Fields
::
components
)
265
return
self
.
wrap
(
PathEls
::
Field
(
Fields
::
components
),
lazyMembers
().
m_components
);
266
return
DomBase
::
field
(
self
,
name
);
267
}
268
269
void
QmlFile
::
addError
(
const
DomItem
&
self
,
ErrorMessage
&&
msg
)
270
{
271
m_isValid
=
false
;
272
self
.
containingObject
().
addError
(
std
::
move
(
msg
));
273
}
274
275
void
QmlFile
::
writeOut
(
const
DomItem
&
self
,
OutWriter
&
ow
)
const
276
{
277
ensurePopulated
();
278
for
(
const
DomItem
&
p
:
self
.
field
(
Fields
::
pragmas
).
values
()) {
279
p
.
writeOut
(
ow
);
280
}
281
auto
imports
=
self
.
field
(
Fields
::
imports
).
values
();
282
283
if
(
ow
.
lineWriter
.
options
().
sortImports
) {
284
std
::
stable_sort
(
imports
.
begin
(),
imports
.
end
(),
285
[](
const
DomItem
&
item1
,
const
DomItem
&
item2
) {
286
const
auto
uri1
=
item1
[
Fields
::
uri
].
toString
();
287
const
auto
uri2
=
item2
[
Fields
::
uri
].
toString
();
288
return
uri1
<
uri2
;
289
});
290
}
291
292
for
(
const
DomItem
&
i
:
imports
) {
293
i
.
writeOut
(
ow
);
294
}
295
ow
.
ensureNewline
(2);
296
DomItem
mainC
=
self
.
field
(
Fields
::
components
).
key
(
QString
()).
index
(0);
297
mainC
.
writeOut
(
ow
);
298
}
299
300
}
// end namespace Dom
301
}
// end namespace QQmlJS
302
303
QT_END_NAMESPACE
QQmlJS::Dom
Definition
qqmljsimportvisitor_p.h:38
QQmlJS::Dom::pluginData
QCborValue pluginData(const QQmlDirParser::Plugin &pl, const QStringList &cNames)
Definition
qqmldomexternalitems.cpp:59
QQmlJS
Definition
qv4bytecodegenerator_p.h:27
NewErrorGroup
#define NewErrorGroup(name)
Definition
qqmldomerrormessage_p.h:43
qtdeclarative
src
qmldom
qqmldomexternalitems.cpp
Generated on
for Qt by
1.16.1