diff options
author | Lukas Wirth <[email protected]> | 2021-04-16 16:31:47 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-04-18 11:44:00 +0100 |
commit | c447a795abecbf9a4138778bab44197250b2dc4a (patch) | |
tree | c35a00f004f09c01f41714ca44e3a0a045a19ea1 /crates | |
parent | 75371eb0fa015ba8834ae2b66cda68eba5d83874 (diff) |
Prevent being able to rename items that are not part of the workspace
Diffstat (limited to 'crates')
10 files changed, 92 insertions, 15 deletions
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index b24c664ba..99e45633e 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -244,6 +244,12 @@ impl Analysis { | |||
244 | self.with_db(|db| db.parse(file_id).tree()) | 244 | self.with_db(|db| db.parse(file_id).tree()) |
245 | } | 245 | } |
246 | 246 | ||
247 | /// Returns true if this file belongs to an immutable library. | ||
248 | pub fn is_library_file(&self, file_id: FileId) -> Cancelable<bool> { | ||
249 | use ide_db::base_db::SourceDatabaseExt; | ||
250 | self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library) | ||
251 | } | ||
252 | |||
247 | /// Gets the file's `LineIndex`: data structure to convert between absolute | 253 | /// Gets the file's `LineIndex`: data structure to convert between absolute |
248 | /// offsets and line/column representation. | 254 | /// offsets and line/column representation. |
249 | pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> { | 255 | pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> { |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1edaa394a..7ddea22c8 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -400,6 +400,17 @@ impl Config { | |||
400 | pub fn will_rename(&self) -> bool { | 400 | pub fn will_rename(&self) -> bool { |
401 | try_or!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?, false) | 401 | try_or!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?, false) |
402 | } | 402 | } |
403 | pub fn change_annotation_support(&self) -> bool { | ||
404 | try_!(self | ||
405 | .caps | ||
406 | .workspace | ||
407 | .as_ref()? | ||
408 | .workspace_edit | ||
409 | .as_ref()? | ||
410 | .change_annotation_support | ||
411 | .as_ref()?) | ||
412 | .is_some() | ||
413 | } | ||
403 | pub fn code_action_resolve(&self) -> bool { | 414 | pub fn code_action_resolve(&self) -> bool { |
404 | try_or!( | 415 | try_or!( |
405 | self.caps | 416 | self.caps |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt index 23ec2efba..227d96d51 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt | |||
@@ -326,6 +326,7 @@ | |||
326 | }, | 326 | }, |
327 | ), | 327 | ), |
328 | document_changes: None, | 328 | document_changes: None, |
329 | change_annotations: None, | ||
329 | }, | 330 | }, |
330 | ), | 331 | ), |
331 | is_preferred: Some( | 332 | is_preferred: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt index b6acb5f42..f8adfad3b 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt | |||
@@ -179,6 +179,7 @@ | |||
179 | }, | 179 | }, |
180 | ), | 180 | ), |
181 | document_changes: None, | 181 | document_changes: None, |
182 | change_annotations: None, | ||
182 | }, | 183 | }, |
183 | ), | 184 | ), |
184 | is_preferred: Some( | 185 | is_preferred: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt index d765257c4..5a70d2ed7 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt | |||
@@ -179,6 +179,7 @@ | |||
179 | }, | 179 | }, |
180 | ), | 180 | ), |
181 | document_changes: None, | 181 | document_changes: None, |
182 | change_annotations: None, | ||
182 | }, | 183 | }, |
183 | ), | 184 | ), |
184 | is_preferred: Some( | 185 | is_preferred: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt index 6b0d94878..04ca0c9c2 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt | |||
@@ -179,6 +179,7 @@ | |||
179 | }, | 179 | }, |
180 | ), | 180 | ), |
181 | document_changes: None, | 181 | document_changes: None, |
182 | change_annotations: None, | ||
182 | }, | 183 | }, |
183 | ), | 184 | ), |
184 | is_preferred: Some( | 185 | is_preferred: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt index a0cfb8d33..57d2f1ae3 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt | |||
@@ -339,6 +339,7 @@ | |||
339 | }, | 339 | }, |
340 | ), | 340 | ), |
341 | document_changes: None, | 341 | document_changes: None, |
342 | change_annotations: None, | ||
342 | }, | 343 | }, |
343 | ), | 344 | ), |
344 | is_preferred: Some( | 345 | is_preferred: Some( |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index e2f319f6b..ca18997e4 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -136,6 +136,7 @@ fn map_rust_child_diagnostic( | |||
136 | // FIXME: there's no good reason to use edit_map here.... | 136 | // FIXME: there's no good reason to use edit_map here.... |
137 | changes: Some(edit_map), | 137 | changes: Some(edit_map), |
138 | document_changes: None, | 138 | document_changes: None, |
139 | change_annotations: None, | ||
139 | }), | 140 | }), |
140 | is_preferred: Some(true), | 141 | is_preferred: Some(true), |
141 | data: None, | 142 | data: None, |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index d648cda32..b8835a534 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -312,6 +312,9 @@ pub struct SnippetWorkspaceEdit { | |||
312 | pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>, | 312 | pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>, |
313 | #[serde(skip_serializing_if = "Option::is_none")] | 313 | #[serde(skip_serializing_if = "Option::is_none")] |
314 | pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>, | 314 | pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>, |
315 | #[serde(skip_serializing_if = "Option::is_none")] | ||
316 | pub change_annotations: | ||
317 | Option<HashMap<lsp_types::ChangeAnnotationIdentifier, lsp_types::ChangeAnnotation>>, | ||
315 | } | 318 | } |
316 | 319 | ||
317 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] | 320 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] |
@@ -335,6 +338,9 @@ pub struct SnippetTextEdit { | |||
335 | pub new_text: String, | 338 | pub new_text: String, |
336 | #[serde(skip_serializing_if = "Option::is_none")] | 339 | #[serde(skip_serializing_if = "Option::is_none")] |
337 | pub insert_text_format: Option<lsp_types::InsertTextFormat>, | 340 | pub insert_text_format: Option<lsp_types::InsertTextFormat>, |
341 | /// The annotation id if this is an annotated | ||
342 | #[serde(skip_serializing_if = "Option::is_none")] | ||
343 | pub annotation_id: Option<lsp_types::ChangeAnnotationIdentifier>, | ||
338 | } | 344 | } |
339 | 345 | ||
340 | pub enum HoverRequest {} | 346 | pub enum HoverRequest {} |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 1a1f65f3b..13de11df1 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! Conversion of rust-analyzer specific types to lsp_types equivalents. | 1 | //! Conversion of rust-analyzer specific types to lsp_types equivalents. |
2 | use std::{ | 2 | use std::{ |
3 | collections::HashMap, | ||
3 | path::{self, Path}, | 4 | path::{self, Path}, |
4 | sync::atomic::{AtomicU32, Ordering}, | 5 | sync::atomic::{AtomicU32, Ordering}, |
5 | }; | 6 | }; |
@@ -174,6 +175,7 @@ pub(crate) fn snippet_text_edit( | |||
174 | range: text_edit.range, | 175 | range: text_edit.range, |
175 | new_text: text_edit.new_text, | 176 | new_text: text_edit.new_text, |
176 | insert_text_format, | 177 | insert_text_format, |
178 | annotation_id: None, | ||
177 | } | 179 | } |
178 | } | 180 | } |
179 | 181 | ||
@@ -688,6 +690,10 @@ pub(crate) fn goto_definition_response( | |||
688 | } | 690 | } |
689 | } | 691 | } |
690 | 692 | ||
693 | fn outside_workspace_annotation(snap: &GlobalStateSnapshot) -> Option<String> { | ||
694 | snap.config.change_annotation_support().then(|| String::from("OutsideWorkspace")) | ||
695 | } | ||
696 | |||
691 | pub(crate) fn snippet_text_document_edit( | 697 | pub(crate) fn snippet_text_document_edit( |
692 | snap: &GlobalStateSnapshot, | 698 | snap: &GlobalStateSnapshot, |
693 | is_snippet: bool, | 699 | is_snippet: bool, |
@@ -696,7 +702,19 @@ pub(crate) fn snippet_text_document_edit( | |||
696 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { | 702 | ) -> Result<lsp_ext::SnippetTextDocumentEdit> { |
697 | let text_document = optional_versioned_text_document_identifier(snap, file_id); | 703 | let text_document = optional_versioned_text_document_identifier(snap, file_id); |
698 | let line_index = snap.file_line_index(file_id)?; | 704 | let line_index = snap.file_line_index(file_id)?; |
699 | let edits = edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect(); | 705 | let outside_workspace_annotation = snap |
706 | .analysis | ||
707 | .is_library_file(file_id)? | ||
708 | .then(|| outside_workspace_annotation(snap)) | ||
709 | .flatten(); | ||
710 | let edits = edit | ||
711 | .into_iter() | ||
712 | .map(|it| { | ||
713 | let mut edit = snippet_text_edit(&line_index, is_snippet, it); | ||
714 | edit.annotation_id = outside_workspace_annotation.clone(); | ||
715 | edit | ||
716 | }) | ||
717 | .collect(); | ||
700 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 718 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
701 | } | 719 | } |
702 | 720 | ||
@@ -721,6 +739,7 @@ pub(crate) fn snippet_text_document_ops( | |||
721 | range: lsp_types::Range::default(), | 739 | range: lsp_types::Range::default(), |
722 | new_text: initial_contents, | 740 | new_text: initial_contents, |
723 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), | 741 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), |
742 | annotation_id: None, | ||
724 | }; | 743 | }; |
725 | let edit_file = | 744 | let edit_file = |
726 | lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] }; | 745 | lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] }; |
@@ -734,7 +753,12 @@ pub(crate) fn snippet_text_document_ops( | |||
734 | old_uri, | 753 | old_uri, |
735 | new_uri, | 754 | new_uri, |
736 | options: None, | 755 | options: None, |
737 | annotation_id: None, | 756 | annotation_id: snap |
757 | .analysis | ||
758 | .is_library_file(src) | ||
759 | .unwrap() | ||
760 | .then(|| outside_workspace_annotation(snap)) | ||
761 | .flatten(), | ||
738 | }); | 762 | }); |
739 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file)) | 763 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file)) |
740 | } | 764 | } |
@@ -747,6 +771,7 @@ pub(crate) fn snippet_workspace_edit( | |||
747 | source_change: SourceChange, | 771 | source_change: SourceChange, |
748 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { | 772 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { |
749 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); | 773 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); |
774 | |||
750 | for op in source_change.file_system_edits { | 775 | for op in source_change.file_system_edits { |
751 | let ops = snippet_text_document_ops(snap, op); | 776 | let ops = snippet_text_document_ops(snap, op); |
752 | document_changes.extend_from_slice(&ops); | 777 | document_changes.extend_from_slice(&ops); |
@@ -755,8 +780,24 @@ pub(crate) fn snippet_workspace_edit( | |||
755 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, file_id, edit)?; | 780 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, file_id, edit)?; |
756 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); | 781 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); |
757 | } | 782 | } |
758 | let workspace_edit = | 783 | let change_annotations = outside_workspace_annotation(snap).map(|annotation| { |
759 | lsp_ext::SnippetWorkspaceEdit { changes: None, document_changes: Some(document_changes) }; | 784 | use std::iter::FromIterator; |
785 | HashMap::from_iter(Some(( | ||
786 | annotation, | ||
787 | lsp_types::ChangeAnnotation { | ||
788 | label: String::from("Edit outside of the workspace"), | ||
789 | needs_confirmation: Some(true), | ||
790 | description: Some(String::from( | ||
791 | "This edit lies outside of the workspace and may affect dependencies", | ||
792 | )), | ||
793 | }, | ||
794 | ))) | ||
795 | }); | ||
796 | let workspace_edit = lsp_ext::SnippetWorkspaceEdit { | ||
797 | changes: None, | ||
798 | document_changes: Some(document_changes), | ||
799 | change_annotations, | ||
800 | }; | ||
760 | Ok(workspace_edit) | 801 | Ok(workspace_edit) |
761 | } | 802 | } |
762 | 803 | ||
@@ -784,16 +825,7 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit { | |||
784 | lsp_types::DocumentChangeOperation::Edit( | 825 | lsp_types::DocumentChangeOperation::Edit( |
785 | lsp_types::TextDocumentEdit { | 826 | lsp_types::TextDocumentEdit { |
786 | text_document: edit.text_document, | 827 | text_document: edit.text_document, |
787 | edits: edit | 828 | edits: edit.edits.into_iter().map(From::from).collect(), |
788 | .edits | ||
789 | .into_iter() | ||
790 | .map(|edit| { | ||
791 | lsp_types::OneOf::Left(lsp_types::TextEdit { | ||
792 | range: edit.range, | ||
793 | new_text: edit.new_text, | ||
794 | }) | ||
795 | }) | ||
796 | .collect(), | ||
797 | }, | 829 | }, |
798 | ) | 830 | ) |
799 | } | 831 | } |
@@ -801,7 +833,23 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit { | |||
801 | .collect(), | 833 | .collect(), |
802 | ) | 834 | ) |
803 | }), | 835 | }), |
804 | change_annotations: None, | 836 | change_annotations: snippet_workspace_edit.change_annotations, |
837 | } | ||
838 | } | ||
839 | } | ||
840 | |||
841 | impl From<lsp_ext::SnippetTextEdit> | ||
842 | for lsp_types::OneOf<lsp_types::TextEdit, lsp_types::AnnotatedTextEdit> | ||
843 | { | ||
844 | fn from( | ||
845 | lsp_ext::SnippetTextEdit { annotation_id, insert_text_format:_, new_text, range }: lsp_ext::SnippetTextEdit, | ||
846 | ) -> Self { | ||
847 | match annotation_id { | ||
848 | Some(annotation_id) => lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit { | ||
849 | text_edit: lsp_types::TextEdit { range, new_text }, | ||
850 | annotation_id, | ||
851 | }), | ||
852 | None => lsp_types::OneOf::Left(lsp_types::TextEdit { range, new_text }), | ||
805 | } | 853 | } |
806 | } | 854 | } |
807 | } | 855 | } |