Prevent being able to rename items that are not part of the workspace

This commit is contained in:
Lukas Wirth 2021-04-16 17:31:47 +02:00
parent 75371eb0fa
commit c447a795ab
10 changed files with 92 additions and 15 deletions

View file

@ -244,6 +244,12 @@ impl Analysis {
self.with_db(|db| db.parse(file_id).tree())
}
/// Returns true if this file belongs to an immutable library.
pub fn is_library_file(&self, file_id: FileId) -> Cancelable<bool> {
use ide_db::base_db::SourceDatabaseExt;
self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
}
/// Gets the file's `LineIndex`: data structure to convert between absolute
/// offsets and line/column representation.
pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> {

View file

@ -400,6 +400,17 @@ impl Config {
pub fn will_rename(&self) -> bool {
try_or!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?, false)
}
pub fn change_annotation_support(&self) -> bool {
try_!(self
.caps
.workspace
.as_ref()?
.workspace_edit
.as_ref()?
.change_annotation_support
.as_ref()?)
.is_some()
}
pub fn code_action_resolve(&self) -> bool {
try_or!(
self.caps

View file

@ -326,6 +326,7 @@
},
),
document_changes: None,
change_annotations: None,
},
),
is_preferred: Some(

View file

@ -179,6 +179,7 @@
},
),
document_changes: None,
change_annotations: None,
},
),
is_preferred: Some(

View file

@ -179,6 +179,7 @@
},
),
document_changes: None,
change_annotations: None,
},
),
is_preferred: Some(

View file

@ -179,6 +179,7 @@
},
),
document_changes: None,
change_annotations: None,
},
),
is_preferred: Some(

View file

@ -339,6 +339,7 @@
},
),
document_changes: None,
change_annotations: None,
},
),
is_preferred: Some(

View file

@ -136,6 +136,7 @@ fn map_rust_child_diagnostic(
// FIXME: there's no good reason to use edit_map here....
changes: Some(edit_map),
document_changes: None,
change_annotations: None,
}),
is_preferred: Some(true),
data: None,

View file

@ -312,6 +312,9 @@ pub struct SnippetWorkspaceEdit {
pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub change_annotations:
Option<HashMap<lsp_types::ChangeAnnotationIdentifier, lsp_types::ChangeAnnotation>>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
@ -335,6 +338,9 @@ pub struct SnippetTextEdit {
pub new_text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub insert_text_format: Option<lsp_types::InsertTextFormat>,
/// The annotation id if this is an annotated
#[serde(skip_serializing_if = "Option::is_none")]
pub annotation_id: Option<lsp_types::ChangeAnnotationIdentifier>,
}
pub enum HoverRequest {}

View file

@ -1,5 +1,6 @@
//! Conversion of rust-analyzer specific types to lsp_types equivalents.
use std::{
collections::HashMap,
path::{self, Path},
sync::atomic::{AtomicU32, Ordering},
};
@ -174,6 +175,7 @@ pub(crate) fn snippet_text_edit(
range: text_edit.range,
new_text: text_edit.new_text,
insert_text_format,
annotation_id: None,
}
}
@ -688,6 +690,10 @@ pub(crate) fn goto_definition_response(
}
}
fn outside_workspace_annotation(snap: &GlobalStateSnapshot) -> Option<String> {
snap.config.change_annotation_support().then(|| String::from("OutsideWorkspace"))
}
pub(crate) fn snippet_text_document_edit(
snap: &GlobalStateSnapshot,
is_snippet: bool,
@ -696,7 +702,19 @@ pub(crate) fn snippet_text_document_edit(
) -> Result<lsp_ext::SnippetTextDocumentEdit> {
let text_document = optional_versioned_text_document_identifier(snap, file_id);
let line_index = snap.file_line_index(file_id)?;
let edits = edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect();
let outside_workspace_annotation = snap
.analysis
.is_library_file(file_id)?
.then(|| outside_workspace_annotation(snap))
.flatten();
let edits = edit
.into_iter()
.map(|it| {
let mut edit = snippet_text_edit(&line_index, is_snippet, it);
edit.annotation_id = outside_workspace_annotation.clone();
edit
})
.collect();
Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits })
}
@ -721,6 +739,7 @@ pub(crate) fn snippet_text_document_ops(
range: lsp_types::Range::default(),
new_text: initial_contents,
insert_text_format: Some(lsp_types::InsertTextFormat::PlainText),
annotation_id: None,
};
let edit_file =
lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] };
@ -734,7 +753,12 @@ pub(crate) fn snippet_text_document_ops(
old_uri,
new_uri,
options: None,
annotation_id: None,
annotation_id: snap
.analysis
.is_library_file(src)
.unwrap()
.then(|| outside_workspace_annotation(snap))
.flatten(),
});
ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file))
}
@ -747,6 +771,7 @@ pub(crate) fn snippet_workspace_edit(
source_change: SourceChange,
) -> Result<lsp_ext::SnippetWorkspaceEdit> {
let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
for op in source_change.file_system_edits {
let ops = snippet_text_document_ops(snap, op);
document_changes.extend_from_slice(&ops);
@ -755,8 +780,24 @@ pub(crate) fn snippet_workspace_edit(
let edit = snippet_text_document_edit(&snap, source_change.is_snippet, file_id, edit)?;
document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit));
}
let workspace_edit =
lsp_ext::SnippetWorkspaceEdit { changes: None, document_changes: Some(document_changes) };
let change_annotations = outside_workspace_annotation(snap).map(|annotation| {
use std::iter::FromIterator;
HashMap::from_iter(Some((
annotation,
lsp_types::ChangeAnnotation {
label: String::from("Edit outside of the workspace"),
needs_confirmation: Some(true),
description: Some(String::from(
"This edit lies outside of the workspace and may affect dependencies",
)),
},
)))
});
let workspace_edit = lsp_ext::SnippetWorkspaceEdit {
changes: None,
document_changes: Some(document_changes),
change_annotations,
};
Ok(workspace_edit)
}
@ -784,16 +825,7 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
lsp_types::DocumentChangeOperation::Edit(
lsp_types::TextDocumentEdit {
text_document: edit.text_document,
edits: edit
.edits
.into_iter()
.map(|edit| {
lsp_types::OneOf::Left(lsp_types::TextEdit {
range: edit.range,
new_text: edit.new_text,
})
})
.collect(),
edits: edit.edits.into_iter().map(From::from).collect(),
},
)
}
@ -801,7 +833,23 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
.collect(),
)
}),
change_annotations: None,
change_annotations: snippet_workspace_edit.change_annotations,
}
}
}
impl From<lsp_ext::SnippetTextEdit>
for lsp_types::OneOf<lsp_types::TextEdit, lsp_types::AnnotatedTextEdit>
{
fn from(
lsp_ext::SnippetTextEdit { annotation_id, insert_text_format:_, new_text, range }: lsp_ext::SnippetTextEdit,
) -> Self {
match annotation_id {
Some(annotation_id) => lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit {
text_edit: lsp_types::TextEdit { range, new_text },
annotation_id,
}),
None => lsp_types::OneOf::Left(lsp_types::TextEdit { range, new_text }),
}
}
}