This commit is contained in:
Kirill Bulatov 2020-12-06 23:58:15 +02:00
parent 6badf705b3
commit 19cfa5802e
4 changed files with 34 additions and 35 deletions

View file

@ -141,7 +141,7 @@ pub fn resolve_completion_edits(
position: FilePosition, position: FilePosition,
full_import_path: &str, full_import_path: &str,
imported_name: &str, imported_name: &str,
) -> Option<TextEdit> { ) -> Option<Vec<TextEdit>> {
let ctx = CompletionContext::new(db, position, config)?; let ctx = CompletionContext::new(db, position, config)?;
let anchor = ctx.name_ref_syntax.as_ref()?; let anchor = ctx.name_ref_syntax.as_ref()?;
let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
@ -156,7 +156,9 @@ pub fn resolve_completion_edits(
}) })
.find(|mod_path| mod_path.to_string() == full_import_path)?; .find(|mod_path| mod_path.to_string() == full_import_path)?;
ImportEdit { import_path, import_scope, merge_behaviour: config.merge }.to_text_edit() ImportEdit { import_path, import_scope, merge_behaviour: config.merge }
.to_text_edit()
.map(|edit| vec![edit])
} }
#[cfg(test)] #[cfg(test)]

View file

@ -487,7 +487,6 @@ impl Analysis {
imported_name, imported_name,
) )
})? })?
.map(|edit| vec![edit])
.unwrap_or_default()) .unwrap_or_default())
} }

View file

@ -8,9 +8,8 @@ use std::{
}; };
use ide::{ use ide::{
CompletionConfig, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData,
HoverGotoTypeData, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit,
TextEdit,
}; };
use itertools::Itertools; use itertools::Itertools;
use lsp_server::ErrorCode; use lsp_server::ErrorCode;
@ -578,15 +577,12 @@ pub(crate) fn handle_completion(
let mut new_completion_items = let mut new_completion_items =
to_proto::completion_item(&line_index, line_endings, item.clone()); to_proto::completion_item(&line_index, line_endings, item.clone());
if snap.config.completion.resolve_additional_edits_lazily() {
for new_item in &mut new_completion_items { for new_item in &mut new_completion_items {
let _ = fill_resolve_data( let _ = fill_resolve_data(&mut new_item.data, &item, &text_document_position)
&mut new_item.data,
&item,
&snap.config.completion,
&text_document_position,
)
.take(); .take();
} }
}
new_completion_items new_completion_items
}) })
@ -600,12 +596,12 @@ pub(crate) fn handle_completion_resolve(
snap: GlobalStateSnapshot, snap: GlobalStateSnapshot,
mut original_completion: CompletionItem, mut original_completion: CompletionItem,
) -> Result<CompletionItem> { ) -> Result<CompletionItem> {
let _p = profile::span("handle_resolve_completion"); let _p = profile::span("handle_completion_resolve");
if !all_edits_are_disjoint(&original_completion, &[]) { if !all_edits_are_disjoint(&original_completion, &[]) {
return Err(LspError::new( return Err(LspError::new(
ErrorCode::InvalidParams as i32, ErrorCode::InvalidParams as i32,
"Received a completion with disjoint edits".into(), "Received a completion with overlapping edits, this is not LSP-compliant".into(),
) )
.into()); .into());
} }
@ -635,7 +631,7 @@ pub(crate) fn handle_completion_resolve(
let line_endings = snap.file_line_endings(file_id); let line_endings = snap.file_line_endings(file_id);
let offset = from_proto::offset(&line_index, resolve_data.position.position); let offset = from_proto::offset(&line_index, resolve_data.position.position);
let mut additional_edits = snap let additional_edits = snap
.analysis .analysis
.resolve_completion_edits( .resolve_completion_edits(
&snap.config.completion, &snap.config.completion,
@ -652,13 +648,14 @@ pub(crate) fn handle_completion_resolve(
if !all_edits_are_disjoint(&original_completion, &additional_edits) { if !all_edits_are_disjoint(&original_completion, &additional_edits) {
return Err(LspError::new( return Err(LspError::new(
ErrorCode::InternalError as i32, ErrorCode::InternalError as i32,
"Import edit is not disjoint with the original completion edits".into(), "Import edit overlaps with the original completion edits, this is not LSP-compliant"
.into(),
) )
.into()); .into());
} }
if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() { if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() {
original_additional_edits.extend(additional_edits.drain(..)) original_additional_edits.extend(additional_edits.into_iter())
} else { } else {
original_completion.additional_text_edits = Some(additional_edits); original_completion.additional_text_edits = Some(additional_edits);
} }
@ -1634,10 +1631,8 @@ struct CompletionResolveData {
fn fill_resolve_data( fn fill_resolve_data(
resolve_data: &mut Option<serde_json::Value>, resolve_data: &mut Option<serde_json::Value>,
item: &ide::CompletionItem, item: &ide::CompletionItem,
completion_config: &CompletionConfig,
position: &TextDocumentPositionParams, position: &TextDocumentPositionParams,
) -> Option<()> { ) -> Option<()> {
if completion_config.resolve_additional_edits_lazily() {
let import_edit = item.import_to_add()?; let import_edit = item.import_to_add()?;
let full_import_path = import_edit.import_path.to_string(); let full_import_path = import_edit.import_path.to_string();
let imported_name = import_edit.import_path.segments.clone().pop()?.to_string(); let imported_name = import_edit.import_path.segments.clone().pop()?.to_string();
@ -1649,7 +1644,6 @@ fn fill_resolve_data(
imported_name, imported_name,
}) })
.unwrap(), .unwrap(),
) );
}
Some(()) Some(())
} }

View file

@ -129,7 +129,8 @@ pub(crate) fn apply_document_changes(
} }
} }
/// Checks that the edits inside the completion and the additional edits are disjoint. /// Checks that the edits inside the completion and the additional edits do not overlap.
/// LSP explicitly forbits the additional edits to overlap both with the main edit and themselves.
pub(crate) fn all_edits_are_disjoint( pub(crate) fn all_edits_are_disjoint(
completion: &lsp_types::CompletionItem, completion: &lsp_types::CompletionItem,
additional_edits: &[lsp_types::TextEdit], additional_edits: &[lsp_types::TextEdit],
@ -150,7 +151,10 @@ pub(crate) fn all_edits_are_disjoint(
}; };
edit_ranges.extend(additional_edits.iter().map(|edit| edit.range)); edit_ranges.extend(additional_edits.iter().map(|edit| edit.range));
edit_ranges.sort_by_key(|range| (range.start, range.end)); edit_ranges.sort_by_key(|range| (range.start, range.end));
edit_ranges.iter().zip(edit_ranges.iter().skip(1)).all(|(l, r)| l.end <= r.start) edit_ranges
.iter()
.zip(edit_ranges.iter().skip(1))
.all(|(previous, next)| previous.end <= next.start)
} }
#[cfg(test)] #[cfg(test)]