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
qqmljscontextproperties.cpp
Go to the documentation of this file.
1
// Copyright (C) 2025 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
// Qt-Security score:significant
4
5
#
include
"qqmljscontextproperties_p.h"
6
7
#
include
<
private
/
qtqmlglobal_p
.
h
>
8
9
#
include
<
QtCore
/
qtconfigmacros
.
h
>
10
#
include
<
QtCore
/
qregularexpression
.
h
>
11
#
include
<
QtCore
/
qdirlisting
.
h
>
12
#
include
<
QtCore
/
qfile
.
h
>
13
14
#
if
QT_CONFIG
(
qmlcontextpropertydump
)
15
#
include
<
QtCore
/
qsettings
.
h
>
16
#
endif
17
18
#
if
QT_CONFIG
(
process
)
19
#
include
<
QtCore
/
qprocess
.
h
>
20
#
endif
21
22
QT_BEGIN_NAMESPACE
23
24
namespace
QQmlJS
{
25
26
using
namespace
Qt
::
StringLiterals
;
27
28
// There are many ways to set context properties without triggering the regexp in s_pattern,
29
// but its supposed to catch most context properties set via "setContextProperty".
30
static
constexpr
QLatin1StringView
s_pattern
=
31
R"x((\.|->)setContextProperty\s*\(\s*(QStringLiteral\s*\(|QString\s*\(|QLatin1String(View)?\s*\(|u)?\s*"([^"]*)")x"_L1;
32
static
constexpr
int
s_contextPropertyNameIdxInPattern
= 4;
33
34
// TODO: use a central list of file extensions that can also be used by qmetatypesjsonprocessor.cpp
35
// (that needs header file extensions) and Qt6QmlMacros.cmake.
36
static
constexpr
std
::
array
s_fileFilters
= {
37
"*.cpp"_L1
,
"*.cxx"_L1
,
"*.cc"_L1
,
"*.c"_L1
,
"*.c++"_L1
,
38
"*.hpp"_L1
,
"*.hxx"_L1
,
"*.hh"_L1
,
"*.h"_L1
,
"*.h++"_L1
,
39
};
40
41
static
const
QRegularExpression
s_matchSetContextProperty
{
s_pattern
,
42
QRegularExpression
::
MultilineOption
};
43
44
QList
<
HeuristicContextProperty
>
45
HeuristicContextProperties
::
definitionsForName
(
const
QString
&
name
)
const
46
{
47
const
auto
it
=
m_properties
.
find
(
name
);
48
if
(
it
!=
m_properties
.
end
())
49
return
it
.
value
();
50
return
{};
51
}
52
53
void
HeuristicContextProperties
::
add
(
const
QString
&
name
,
const
HeuristicContextProperty
&
property
)
54
{
55
if
(
const
auto
it
=
m_properties
.
find
(
name
);
it
!=
m_properties
.
end
()) {
56
it
.
value
().
append
(
property
);
57
return
;
58
}
59
m_properties
.
insert
(
name
, {
property
});
60
}
61
62
void
HeuristicContextProperties
::
collectFromFile
(
const
QString
&
filePath
)
63
{
64
QFile
file
(
filePath
);
65
if
(!
file
.
open
(
QIODevice
::
ReadOnly
|
QIODevice
::
Text
))
66
return
;
67
68
const
QString
fileContent
=
QString
::
fromUtf8
(
file
.
readAll
());
69
for
(
const
auto
&
match
:
s_matchSetContextProperty
.
globalMatch
(
fileContent
)) {
70
const
quint32
offset
=
match
.
capturedStart
(
s_contextPropertyNameIdxInPattern
);
71
const
quint32
length
=
match
.
capturedLength
(
s_contextPropertyNameIdxInPattern
);
72
const
auto
[
row
,
column
] =
QQmlJS
::
SourceLocation
::
rowAndColumnFrom
(
fileContent
,
offset
);
73
const
QQmlJS
::
SourceLocation
sourceLocation
{
offset
,
length
,
row
,
column
};
74
75
add
(
match
.
captured
(
s_contextPropertyNameIdxInPattern
),
76
HeuristicContextProperty
{
filePath
,
sourceLocation
});
77
}
78
}
79
80
void
HeuristicContextProperties
::
grepFallback
(
const
QList
<
QString
> &
rootUrls
)
81
{
82
const
QStringList
fileFilters
{
s_fileFilters
.
begin
(),
s_fileFilters
.
end
() };
83
84
for
(
const
QString
&
url
:
rootUrls
) {
85
for
(
const
auto
&
dirEntry
:
QDirListing
{
url
,
fileFilters
,
86
QDirListing
::
IteratorFlag
::
Recursive
87
|
QDirListing
::
IteratorFlag
::
FilesOnly
}) {
88
89
const
QString
filePath
=
dirEntry
.
filePath
();
90
collectFromFile
(
filePath
);
91
}
92
}
93
}
94
95
#
if
QT_CONFIG
(
process
)
&&
!
defined
(
Q_OS_WINDOWS
)
96
void
HeuristicContextProperties
::
parseGrepOutput
(
const
QString
&
output
)
97
{
98
for
(
const
auto
line
:
QStringTokenizer
{
output
,
"\n"_L1
,
Qt
::
SkipEmptyParts
})
99
collectFromFile
(
line
.
toString
());
100
}
101
#
endif
102
103
HeuristicContextProperties
104
HeuristicContextProperties
::
collectFromCppSourceDirs
(
const
QList
<
QString
> &
cppSourceDirs
)
105
{
106
HeuristicContextProperties
result
;
107
result
.
collectFromDirs
(
cppSourceDirs
);
108
return
result
;
109
}
110
111
/*!
112
\internal
113
Uses grep to find files that have setContextProperty()-calls, and then search matching files
114
with QRegularExpression to extract the location and name of the found context properties.
115
*/
116
void
HeuristicContextProperties
::
collectFromDirs
(
const
QList
<
QString
> &
dirs
)
117
{
118
if
(
dirs
.
isEmpty
())
119
return
;
120
121
#
if
QT_CONFIG
(
process
)
&&
!
defined
(
Q_OS_WINDOWS
)
122
if
(
qEnvironmentVariableIsSet
(
"QT_QML_NO_GREP"
)) {
123
grepFallback
(
dirs
);
124
return
;
125
}
126
127
QProcess
grep
;
128
QStringList
arguments
{
"--recursive"_L1
,
129
"--null-data"_L1
,
// match multiline patterns
130
"--files-with-matches"_L1
,
131
"--extended-regexp"_L1
,
// the pattern is "extended"
132
"-e"_L1
,
133
s_pattern
};
134
135
// don't search non-cpp files
136
for
(
const
auto
fileFilter
:
s_fileFilters
)
137
arguments
<<
"--include"_L1
<<
fileFilter
;
138
139
arguments
.
append
(
dirs
);
140
grep
.
start
(
"grep"_L1
,
arguments
);
141
grep
.
waitForFinished
();
142
if
(
grep
.
exitStatus
() ==
QProcess
::
NormalExit
) {
143
switch
(
grep
.
exitCode
()) {
144
case
0: {
// success
145
const
QString
output
=
QString
::
fromUtf8
(
grep
.
readAllStandardOutput
());
146
parseGrepOutput
(
output
);
147
return
;
148
}
149
case
1:
// success but no context properties found
150
return
;
151
default
:
// grep error
152
break
;
153
}
154
}
155
#
endif
156
grepFallback
(
dirs
);
157
}
158
159
#
if
QT_CONFIG
(
qmlcontextpropertydump
)
160
static
SourceLocation
deserializeSourceLocation
(
const
QString
&
string
)
161
{
162
constexpr
int
size
= 4;
163
const
QStringList
bits
=
string
.
split
(u',',
Qt
::
SkipEmptyParts
);
164
if
(
bits
.
length
() !=
size
)
165
return
SourceLocation
{};
166
167
SourceLocation
result
;
168
quint32
*
destination
[
size
] = { &
result
.
offset
, &
result
.
length
, &
result
.
startLine
,
169
&
result
.
startColumn
};
170
171
bool
everythingOk
=
true
;
172
for
(
int
i
= 0;
i
<
size
; ++
i
) {
173
bool
ok
=
false
;
174
*
destination
[
i
] =
bits
[
i
].
toInt
(&
ok
);
175
everythingOk
&=
ok
;
176
}
177
178
if
(
everythingOk
)
179
return
result
;
180
return
SourceLocation
{};
181
}
182
183
static
QString
serializeSourceLocation
(
const
SourceLocation
&
location
)
184
{
185
QString
result
;
186
result
.
append
(
QString
::
number
(
location
.
offset
)).
append
(u',');
187
result
.
append
(
QString
::
number
(
location
.
length
)).
append
(u',');
188
result
.
append
(
QString
::
number
(
location
.
startLine
)).
append
(u',');
189
result
.
append
(
QString
::
number
(
location
.
startColumn
));
190
return
result
;
191
}
192
#
endif
193
194
static
constexpr
auto
cachedHeuristicListKey
=
"cachedHeuristicList"_L1
;
195
196
HeuristicContextProperties
HeuristicContextProperties
::
collectFrom
(
QSettings
*
settings
)
197
{
198
#
if
QT_CONFIG
(
qmlcontextpropertydump
)
199
HeuristicContextProperties
result
;
200
std
::
vector
<
QString
>
names
;
201
202
const
int
size
=
settings
->
beginReadArray
(
cachedHeuristicListKey
);
203
for
(
int
i
= 0;
i
<
size
; ++
i
) {
204
settings
->
setArrayIndex
(
i
);
205
names
.
push_back
(
settings
->
value
(
"name"
).
toString
());
206
}
207
settings
->
endArray
();
208
209
for
(
const
auto
&
name
:
names
) {
210
const
int
size
=
settings
->
beginReadArray
(u"property_"_s.
append
(
name
));
211
for
(
int
i
= 0;
i
<
size
; ++
i
) {
212
settings
->
setArrayIndex
(
i
);
213
result
.
add
(
214
name
,
215
HeuristicContextProperty
{
216
settings
->
value
(
"fileName"
).
toString
(),
217
deserializeSourceLocation
(
settings
->
value
(
"sourceLocation"
).
toString
()),
218
});
219
}
220
settings
->
endArray
();
221
}
222
return
result
;
223
#
else
224
Q_UNUSED
(
settings
);
225
return
HeuristicContextProperties
{};
226
#
endif
227
}
228
229
void
HeuristicContextProperties
::
writeCache
(
const
QString
&
folder
)
const
230
{
231
#
if
QT_CONFIG
(
qmlcontextpropertydump
)
232
QSettings
settings
(
folder
+
"/.qt/contextPropertyDump.ini"_L1
,
QSettings
::
IniFormat
);
233
settings
.
beginWriteArray
(
cachedHeuristicListKey
);
234
int
index
= 0;
235
for
(
const
auto
&[
name
,
_
] :
m_properties
) {
236
settings
.
setArrayIndex
(
index
++);
237
settings
.
setValue
(
"name"
,
name
);
238
}
239
settings
.
endArray
();
240
241
for
(
const
auto
&[
name
,
definitions
] :
m_properties
) {
242
settings
.
beginWriteArray
(u"property_"_s.
append
(
name
));
243
for
(
int
i
= 0;
i
<
definitions
.
size
(); ++
i
) {
244
settings
.
setArrayIndex
(
i
);
245
settings
.
setValue
(
"fileName"
,
definitions
[
i
].
filename
);
246
settings
.
setValue
(
"sourceLocation"
,
serializeSourceLocation
(
definitions
[
i
].
location
));
247
}
248
settings
.
endArray
();
249
}
250
#
else
251
Q_UNUSED
(
folder
);
252
#
endif
253
}
254
}
// namespace QQmlJS
255
256
QT_END_NAMESPACE
QPlatformGraphicsBufferHelper
\inmodule QtGui
QQmlJS
Definition
qv4bytecodegenerator_p.h:26
QQmlJS::s_matchSetContextProperty
static const QRegularExpression s_matchSetContextProperty
Definition
qqmljscontextproperties.cpp:41
QQmlJS::cachedHeuristicListKey
static constexpr auto cachedHeuristicListKey
Definition
qqmljscontextproperties.cpp:194
QQmlJS::s_pattern
static constexpr QLatin1StringView s_pattern
Definition
qqmljscontextproperties.cpp:30
QQmlJS::s_contextPropertyNameIdxInPattern
static constexpr int s_contextPropertyNameIdxInPattern
Definition
qqmljscontextproperties.cpp:32
QQmlJS::s_fileFilters
static constexpr std::array s_fileFilters
Definition
qqmljscontextproperties.cpp:36
qtdeclarative
src
qmlcompiler
qqmljscontextproperties.cpp
Generated on
for Qt by
1.14.0