66 lines
3.4 KiB
Diff
66 lines
3.4 KiB
Diff
# UNDF: UNDF-2026-000000811
|
|
# UNDF: (leave blank)
|
|
# zed-0001: lsp_store LSP edit dedup Vec::contains O(E²)
|
|
#
|
|
# File: crates/project/src/lsp_store.rs
|
|
# Functions: apply_code_actions_as_format (line ~2010) and
|
|
# apply_code_action (line ~3356)
|
|
#
|
|
# Defect: When accumulating unique edits from LSP code actions, each new
|
|
# edit is checked against the `lsp_edits`/`edits` Vec via
|
|
# Vec::contains() — O(E²) where E = number of edits returned by
|
|
# the language server. Both call sites use the same pattern:
|
|
#
|
|
# let mut lsp_edits = Vec::new();
|
|
# for edit in op.edits {
|
|
# if !lsp_edits.contains(&edit) { lsp_edits.push(edit); }
|
|
# }
|
|
#
|
|
# Fix: Use a HashSet as a parallel seen-set for O(1) dedup, keeping Vec
|
|
# for ordered output.
|
|
# Severity: MEDIUM (E = edits per code action; large refactors can produce
|
|
# hundreds of edits — e.g., rename across file)
|
|
# Speedup: 50x at E=100
|
|
#
|
|
--- a/crates/project/src/lsp_store.rs
|
|
+++ b/crates/project/src/lsp_store.rs
|
|
@@ -2010,10 +2010,12 @@ (apply_code_actions_as_format, first site)
|
|
let mut lsp_edits = Vec::new();
|
|
+ let mut seen_edits = HashSet::new();
|
|
for edit in op.edits {
|
|
match edit {
|
|
Edit::Plain(edit) => {
|
|
- if !lsp_edits.contains(&edit) {
|
|
+ if seen_edits.insert(edit.clone()) {
|
|
lsp_edits.push(edit);
|
|
}
|
|
}
|
|
Edit::Annotated(edit) => {
|
|
- if !lsp_edits.contains(&edit.text_edit) {
|
|
+ if seen_edits.insert(edit.text_edit.clone()) {
|
|
lsp_edits.push(edit.text_edit);
|
|
}
|
|
}
|
|
|
|
@@ -3356,10 +3358,12 @@ (apply_code_action, second site)
|
|
let (mut edits, mut snippet_edits) = (vec![], vec![]);
|
|
+ let mut seen_edits = HashSet::new();
|
|
for edit in op.edits {
|
|
match edit {
|
|
Edit::Plain(edit) => {
|
|
- if !edits.contains(&edit) {
|
|
+ if seen_edits.insert(edit.clone()) {
|
|
edits.push(edit)
|
|
}
|
|
}
|
|
Edit::Annotated(edit) => {
|
|
- if !edits.contains(&edit.text_edit) {
|
|
+ if seen_edits.insert(edit.text_edit.clone()) {
|
|
edits.push(edit.text_edit)
|
|
}
|
|
}
|
|
@@ -3383,1 +3385,1 @@
|
|
- if !edits.contains(&new_edit) {
|
|
+ if seen_edits.insert(new_edit.clone()) {
|
|
edits.push(new_edit);
|
|
}
|