QmlJsEditor: Fix crash when updating outline view

If the outline view is set to not show all bindings, it can crash after
writing code that temporarily produces an element after the cursor that
is interpreted as the child of a NonElementBindingType. In the bug
report that is a temporary structure of

* Window (element)
  * ...
  * Rectangle (element)
    * ...
    * y (non-element binding)
      * y (element binding)
        * Text (element) <- this gets selected in the global outline

When an element is selected in the global outline, the outline view
searches for the first element in the parent hierarchy for which the
source index is successfully mapped to its filtermodel.
(QmlJSOutlineWidget::updateSelectionInTree)

Since filterAcceptsRow only explicitly filters out items that are non-
element bindings, the "Text" element in the above example is "not
filtered out", and is set as the selection in the outline view, even
though it is not visible because one of its parents is filtered out.
That leads to a crash later on.

Make sure that filterAcceptsRow explicitly filters out any item that has
a NonElementBindingType in its parent hierarchy.

Fixes: QTCREATORBUG-28862
Change-Id: I1091daae140f13ea7fea7bb637953f51348c3b63
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Eike Ziller
2023-11-06 15:51:31 +01:00
parent 5b8f7c315a
commit 1058ece953

View File

@@ -44,9 +44,13 @@ bool QmlJSOutlineFilterModel::filterAcceptsRow(int sourceRow,
{ {
if (m_filterBindings) { if (m_filterBindings) {
QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
QVariant itemType = sourceIndex.data(QmlOutlineModel::ItemTypeRole); while (sourceIndex.isValid()) {
if (itemType == QmlOutlineModel::NonElementBindingType) if (sourceIndex.data(QmlOutlineModel::ItemTypeRole)
return false; == QmlOutlineModel::NonElementBindingType) {
return false;
}
sourceIndex = sourceIndex.parent();
}
} }
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
} }