125 const QQmlSA::Element &,
const QQmlSA::Element &,
126 QQmlSA::SourceLocation location)
128 static constexpr std::array forbiddenAssignments = {
"baseline"_L1,
135 "horizontalCenter"_L1,
136 "horizontalCenterOffset"_L1,
148 "verticalCenterOffset"_L1,
153 Q_ASSERT(std::is_sorted(forbiddenAssignments.cbegin(), forbiddenAssignments.cend()));
154 if (std::find(forbiddenAssignments.cbegin(), forbiddenAssignments.cend(), propertyName)
155 != forbiddenAssignments.cend()) {
156 emitWarning(
"Imperative JavaScript assignments can break the visual tooling in Qt Design "
158 WarnImperativeCodeNotEditableInVisualDesigner, location);
163 const QString &propertyName,
164 const QQmlSA::Element &readScope,
165 QQmlSA::SourceLocation location)
169 const QQmlSA::Element globalJSObject = resolveBuiltinType(u"GlobalObject");
170 if (element != globalJSObject)
173 constexpr std::array translationFunctions = {
175 "QT_TRANSLATE_NOOP"_L1,
180 constexpr std::array idTranslationFunctions = {
185 const bool isTranslation =
186 std::find(translationFunctions.cbegin(), translationFunctions.cend(), propertyName)
187 != translationFunctions.cend();
188 const bool isIdTranslation =
189 std::find(idTranslationFunctions.cbegin(), idTranslationFunctions.cend(), propertyName)
190 != idTranslationFunctions.cend();
192 if (!isTranslation && !isIdTranslation)
195 const TranslationType current = isTranslation ? Normal : IdBased;
197 if (m_lastTranslationFunction == None) {
198 m_lastTranslationFunction = current;
202 if (m_lastTranslationFunction != current) {
203 emitWarning(
"Do not mix translation functions", qmlTranslationFunctionMismatch, location);
209 if (!rootElement.filePath().endsWith(u".ui.qml"))
212 manager->registerPropertyPass(std::make_shared<FunctionCallValidator>(manager),
213 QAnyStringView(), QAnyStringView());
214 manager->registerPropertyPass(std::make_shared<QdsBindingValidator>(manager, rootElement),
215 QAnyStringView(), QAnyStringView());
216 manager->registerPropertyPass(std::make_unique<QQmlJSTranslationFunctionMismatchCheck>(manager),
217 QString(), QString(), QString());
218 manager->registerElementPass(std::make_unique<QdsElementValidator>(manager));
222 const Element &readScope, SourceLocation location)
224 auto currentQmlScope = QQmlJSScope::findCurrentQMLScope(QQmlJSScope::scope(readScope));
227 if (currentQmlScope && currentQmlScope->inherits(QQmlJSScope::scope(m_connectionsType)))
231 const Element globalJSObject = resolveBuiltinType(u"GlobalObject");
232 const Element mathObjectType = globalJSObject.property(u"Math"_s).type();
233 if (element.inherits(mathObjectType))
236 const Element qjsValue = resolveBuiltinType(u"QJSValue");
237 if (element.inherits(qjsValue)) {
242 const std::array<QStringView, 4> dateMethodmethods{ u"now", u"parse", u"prototype",
244 if (
auto it = std::find(dateMethodmethods.cbegin(), dateMethodmethods.cend(), propertyName);
245 it != dateMethodmethods.cend())
249 static const std::vector<std::pair<Element, std::unordered_set<QString>>>
250 whiteListedFunctions = {
260 u"isNaN"_s, u"isFinite"_s,
261 u"qsTr"_s, u"qsTrId"_s, u"qsTranslate"_s,
262 u"QT_TRANSLATE_NOOP"_s, u"QT_TRID_NOOP"_s, u"QT_TR_NOOP"_s,
265 { resolveBuiltinType(u"ArrayPrototype"_s), { u"indexOf"_s, u"lastIndexOf"_s } },
266 { resolveBuiltinType(u"NumberPrototype"_s),
275 { resolveBuiltinType(u"StringPrototype"_s),
279 u"toLocaleLowerCase"_s,
281 u"toLocaleUpperCase"_s,
291 { resolveType(u"QtQml"_s, u"Qt"_s),
292 { u"lighter"_s, u"darker"_s, u"rgba"_s, u"tint"_s, u"hsla"_s, u"hsva"_s,
293 u"point"_s, u"rect"_s, u"size"_s, u"vector2d"_s, u"vector3d"_s, u"vector4d"_s,
294 u"quaternion"_s, u"matrix4x4"_s, u"formatDate"_s, u"formatDateTime"_s,
295 u"formatTime"_s, u"resolvedUrl"_s } },
298 for (
const auto &[currentElement, methods] : whiteListedFunctions) {
299 if ((!currentElement || element.inherits(currentElement)) && methods.count(propertyName)) {
305 emitWarning(u"Arbitrary functions and function calls outside of a Connections object are not "
306 u"supported in a UI file (.ui.qml)",
307 ErrFunctionsNotSupportedInQmlUi, location);
312 auto loadTypes = [&manager,
this](QSpan<
const UnsupportedName> names, QSpan<Element> output) {
313 for (qsizetype i = 0; i < qsizetype(names.size()); ++i) {
314 if (!manager->hasImportedModule(names[i].first))
316 output[i] = resolveType(names[i].first, names[i].second);
319 loadTypes(s_unsupportedElementNames, m_unsupportedElements);
320 loadTypes(s_unsupportedRootNames, m_unsupportedRootElements);
321 m_qtObject = resolveType(
"QtQml"_L1,
"QtObject"_L1);
322 m_supportFunctions = { resolveType(
"QtQml"_L1,
"Connections"_L1),
323 resolveType(
"QtQuick"_L1,
"ScriptAction"_L1) };
350 enum WarningType { ForElements, ForRootElements };
351 auto warnIfElementIsUnsupported = [
this, &element](WarningType warningType) {
352 QSpan<
const Element> unsupportedComponents = warningType == ForElements
353 ? QSpan<
const Element>(m_unsupportedElements)
354 : QSpan<
const Element>(m_unsupportedRootElements);
355 const QStringView message = warningType == ForElements
356 ? u"This type (%1) is not supported in a UI file (.ui.qml)."_sv
357 : u"This type (%1) is not supported as a root element of a UI file (.ui.qml)."_sv;
358 const LoggerWarningId &id = warningType == ForElements ? ErrUnsupportedTypeInQmlUi
359 : ErrUnsupportedRootTypeInQmlUi;
361 for (
const auto &unsupportedElement : unsupportedComponents) {
362 if (!unsupportedElement || !element.inherits(unsupportedElement))
365 emitWarning(message.arg(element.baseTypeName()), id, element.sourceLocation());
371 if (warningType == ForRootElements && element.baseType() == m_qtObject)
372 emitWarning(message.arg(element.baseTypeName()), id, element.sourceLocation());
375 if (element.isFileRootComponent())
376 warnIfElementIsUnsupported(ForRootElements);
377 warnIfElementIsUnsupported(ForElements);
379 if (QString id = resolveElementToId(element, element); !id.isEmpty()) {
380 static constexpr std::array unsupportedNames = {
381 "action"_L1,
"alias"_L1,
"anchors"_L1,
"as"_L1,
"baseState"_L1,
382 "bool"_L1,
"border"_L1,
"bottom"_L1,
"break"_L1,
"case"_L1,
383 "catch"_L1,
"clip"_L1,
"color"_L1,
"continue"_L1,
"data"_L1,
384 "date"_L1,
"debugger"_L1,
"default"_L1,
"delete"_L1,
"do"_L1,
385 "double"_L1,
"else"_L1,
"enabled"_L1,
"enumeration"_L1,
"finally"_L1,
386 "flow"_L1,
"focus"_L1,
"font"_L1,
"for"_L1,
"function"_L1,
387 "height"_L1,
"id"_L1,
"if"_L1,
"import"_L1,
"in"_L1,
388 "instanceof"_L1,
"int"_L1,
"item"_L1,
"layer"_L1,
"left"_L1,
389 "list"_L1,
"margin"_L1,
"matrix4x4"_L1,
"new"_L1,
"opacity"_L1,
390 "padding"_L1,
"parent"_L1,
"point"_L1,
"print"_L1,
"quaternion"_L1,
391 "real"_L1,
"rect"_L1,
"return"_L1,
"right"_L1,
"scale"_L1,
392 "shaderInfo"_L1,
"size"_L1,
"source"_L1,
"sprite"_L1,
"spriteSequence"_L1,
393 "state"_L1,
"string"_L1,
"switch"_L1,
"text"_L1,
"texture"_L1,
394 "this"_L1,
"throw"_L1,
"time"_L1,
"top"_L1,
"try"_L1,
395 "typeof"_L1,
"url"_L1,
"var"_L1,
"variant"_L1,
"vector"_L1,
396 "vector2d"_L1,
"vector3d"_L1,
"vector4d"_L1,
"visible"_L1,
"void"_L1,
397 "while"_L1,
"width"_L1,
"with"_L1,
"x"_L1,
"y"_L1,
401 Q_ASSERT(std::is_sorted(unsupportedNames.begin(), unsupportedNames.end()));
402 if (std::binary_search(unsupportedNames.cbegin(), unsupportedNames.cend(), id)) {
404 u"This id (%1) might be ambiguous and is not supported in a UI file (.ui.qml)."_s
406 ErrInvalidIdeInVisualDesigner, element.idSourceLocation());
410 if (std::none_of(m_supportFunctions.cbegin(), m_supportFunctions.cend(),
411 [&element](
const Element &base) {
return base && element.inherits(base); })) {
412 complainAboutFunctions(element);
void onWrite(const QQmlSA::Element &element, const QString &propertyName, const QQmlSA::Element &value, const QQmlSA::Element &writeScope, QQmlSA::SourceLocation location) override
Executes whenever a property is written to.