aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-04-16 16:31:47 +0100
committerLukas Wirth <[email protected]>2021-04-18 11:44:00 +0100
commitc447a795abecbf9a4138778bab44197250b2dc4a (patch)
treec35a00f004f09c01f41714ca44e3a0a045a19ea1 /crates
parent75371eb0fa015ba8834ae2b66cda68eba5d83874 (diff)
Prevent being able to rename items that are not part of the workspace
Diffstat (limited to 'crates')
-rw-r--r--crates/ide/src/lib.rs6
-rw-r--r--crates/rust-analyzer/src/config.rs11
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs1
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs6
-rw-r--r--crates/rust-analyzer/src/to_proto.rs78
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
340pub enum HoverRequest {} 346pub 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.
2use std::{ 2use 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
693fn outside_workspace_annotation(snap: &GlobalStateSnapshot) -> Option<String> {
694 snap.config.change_annotation_support().then(|| String::from("OutsideWorkspace"))
695}
696
691pub(crate) fn snippet_text_document_edit( 697pub(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
841impl 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}