Mitigate panic in merge conflict resolution (#29678)
We have a report of a panic when indexing into `BufferConflicts.block_ids` using the `old_range` from the `ConflictsUpdated` event, indicating that the `block_ids` array can get out of sync with the underlying `ConflictSet`. This PR adds a mitigation so that we won't panic in this situation, as a stopgap until the bug can be reproduced in a test and fixed at the root. Release Notes: - N/A
This commit is contained in:
parent
632f08d2a3
commit
ff4900c942
1 changed files with 45 additions and 5 deletions
|
@ -14,6 +14,7 @@ use ui::{
|
||||||
ActiveTheme, AnyElement, Element as _, StatefulInteractiveElement, Styled,
|
ActiveTheme, AnyElement, Element as _, StatefulInteractiveElement, Styled,
|
||||||
StyledTypography as _, div, h_flex, rems,
|
StyledTypography as _, div, h_flex, rems,
|
||||||
};
|
};
|
||||||
|
use util::{debug_panic, maybe};
|
||||||
|
|
||||||
pub(crate) struct ConflictAddon {
|
pub(crate) struct ConflictAddon {
|
||||||
buffers: HashMap<BufferId, BufferConflicts>,
|
buffers: HashMap<BufferId, BufferConflicts>,
|
||||||
|
@ -89,12 +90,22 @@ fn excerpt_for_buffer_updated(
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
let conflicts_len = conflict_set.read(cx).snapshot().conflicts.len();
|
let conflicts_len = conflict_set.read(cx).snapshot().conflicts.len();
|
||||||
|
let buffer_id = conflict_set.read(cx).snapshot().buffer_id;
|
||||||
|
let Some(buffer_conflicts) = editor
|
||||||
|
.addon_mut::<ConflictAddon>()
|
||||||
|
.unwrap()
|
||||||
|
.buffers
|
||||||
|
.get(&buffer_id)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let addon_conflicts_len = buffer_conflicts.block_ids.len();
|
||||||
conflicts_updated(
|
conflicts_updated(
|
||||||
editor,
|
editor,
|
||||||
conflict_set,
|
conflict_set,
|
||||||
&ConflictSetUpdate {
|
&ConflictSetUpdate {
|
||||||
buffer_range: None,
|
buffer_range: None,
|
||||||
old_range: 0..conflicts_len,
|
old_range: 0..addon_conflicts_len,
|
||||||
new_range: 0..conflicts_len,
|
new_range: 0..conflicts_len,
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
|
@ -174,10 +185,37 @@ fn conflicts_updated(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let old_range = maybe!({
|
||||||
|
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
||||||
|
let buffer_conflicts = conflict_addon.buffers.get(&buffer_id)?;
|
||||||
|
match buffer_conflicts.block_ids.get(event.old_range.clone()) {
|
||||||
|
Some(_) => Some(event.old_range.clone()),
|
||||||
|
None => {
|
||||||
|
debug_panic!(
|
||||||
|
"conflicts updated event old range is invalid for buffer conflicts view (block_ids len is {:?}, old_range is {:?})",
|
||||||
|
buffer_conflicts.block_ids.len(),
|
||||||
|
event.old_range,
|
||||||
|
);
|
||||||
|
if event.old_range.start <= event.old_range.end {
|
||||||
|
Some(
|
||||||
|
event.old_range.start.min(buffer_conflicts.block_ids.len())
|
||||||
|
..event.old_range.end.min(buffer_conflicts.block_ids.len()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Remove obsolete highlights and blocks
|
// Remove obsolete highlights and blocks
|
||||||
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
||||||
if let Some(buffer_conflicts) = conflict_addon.buffers.get_mut(&buffer_id) {
|
if let Some((buffer_conflicts, old_range)) = conflict_addon
|
||||||
let old_conflicts = buffer_conflicts.block_ids[event.old_range.clone()].to_owned();
|
.buffers
|
||||||
|
.get_mut(&buffer_id)
|
||||||
|
.zip(old_range.clone())
|
||||||
|
{
|
||||||
|
let old_conflicts = buffer_conflicts.block_ids[old_range].to_owned();
|
||||||
let mut removed_highlighted_ranges = Vec::new();
|
let mut removed_highlighted_ranges = Vec::new();
|
||||||
let mut removed_block_ids = HashSet::default();
|
let mut removed_block_ids = HashSet::default();
|
||||||
for (conflict_range, block_id) in old_conflicts {
|
for (conflict_range, block_id) in old_conflicts {
|
||||||
|
@ -263,9 +301,11 @@ fn conflicts_updated(
|
||||||
let new_block_ids = editor.insert_blocks(blocks, None, cx);
|
let new_block_ids = editor.insert_blocks(blocks, None, cx);
|
||||||
|
|
||||||
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
let conflict_addon = editor.addon_mut::<ConflictAddon>().unwrap();
|
||||||
if let Some(buffer_conflicts) = conflict_addon.buffers.get_mut(&buffer_id) {
|
if let Some((buffer_conflicts, old_range)) =
|
||||||
|
conflict_addon.buffers.get_mut(&buffer_id).zip(old_range)
|
||||||
|
{
|
||||||
buffer_conflicts.block_ids.splice(
|
buffer_conflicts.block_ids.splice(
|
||||||
event.old_range.clone(),
|
old_range,
|
||||||
new_conflicts
|
new_conflicts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|conflict| conflict.range.clone())
|
.map(|conflict| conflict.range.clone())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue