mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-18 19:21:38 +00:00
Warn the user when a rename will change the meaning of the program
Specifically, when a rename of a local will change some code that refers it to refer another local, or some code that refer another local to refer to it. We do it by introducing a dummy edit with an annotation. I'm not a fond of this approach, but I don't think LSP has a better way.
This commit is contained in:
parent
bd0289e0e9
commit
62e7d2851b
12 changed files with 509 additions and 59 deletions
|
|
@ -3,7 +3,7 @@
|
|||
//!
|
||||
//! It can be viewed as a dual for `Change`.
|
||||
|
||||
use std::{collections::hash_map::Entry, iter, mem};
|
||||
use std::{collections::hash_map::Entry, fmt, iter, mem};
|
||||
|
||||
use crate::text_edit::{TextEdit, TextEditBuilder};
|
||||
use crate::{assists::Command, syntax_helpers::tree_diff::diff, SnippetCap};
|
||||
|
|
@ -18,23 +18,33 @@ use syntax::{
|
|||
AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
|
||||
};
|
||||
|
||||
/// An annotation ID associated with an indel, to describe changes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ChangeAnnotationId(u32);
|
||||
|
||||
impl fmt::Display for ChangeAnnotationId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChangeAnnotation {
|
||||
pub label: String,
|
||||
pub needs_confirmation: bool,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct SourceChange {
|
||||
pub source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>,
|
||||
pub file_system_edits: Vec<FileSystemEdit>,
|
||||
pub is_snippet: bool,
|
||||
pub annotations: FxHashMap<ChangeAnnotationId, ChangeAnnotation>,
|
||||
next_annotation_id: u32,
|
||||
}
|
||||
|
||||
impl SourceChange {
|
||||
/// Creates a new SourceChange with the given label
|
||||
/// from the edits.
|
||||
pub fn from_edits(
|
||||
source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>,
|
||||
file_system_edits: Vec<FileSystemEdit>,
|
||||
) -> Self {
|
||||
SourceChange { source_file_edits, file_system_edits, is_snippet: false }
|
||||
}
|
||||
|
||||
pub fn from_text_edit(file_id: impl Into<FileId>, edit: TextEdit) -> Self {
|
||||
SourceChange {
|
||||
source_file_edits: iter::once((file_id.into(), (edit, None))).collect(),
|
||||
|
|
@ -42,6 +52,13 @@ impl SourceChange {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn insert_annotation(&mut self, annotation: ChangeAnnotation) -> ChangeAnnotationId {
|
||||
let id = ChangeAnnotationId(self.next_annotation_id);
|
||||
self.next_annotation_id += 1;
|
||||
self.annotations.insert(id, annotation);
|
||||
id
|
||||
}
|
||||
|
||||
/// Inserts a [`TextEdit`] for the given [`FileId`]. This properly handles merging existing
|
||||
/// edits for a file if some already exist.
|
||||
pub fn insert_source_edit(&mut self, file_id: impl Into<FileId>, edit: TextEdit) {
|
||||
|
|
@ -120,7 +137,12 @@ impl From<IntMap<FileId, TextEdit>> for SourceChange {
|
|||
fn from(source_file_edits: IntMap<FileId, TextEdit>) -> SourceChange {
|
||||
let source_file_edits =
|
||||
source_file_edits.into_iter().map(|(file_id, edit)| (file_id, (edit, None))).collect();
|
||||
SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false }
|
||||
SourceChange {
|
||||
source_file_edits,
|
||||
file_system_edits: Vec::new(),
|
||||
is_snippet: false,
|
||||
..SourceChange::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -482,6 +504,7 @@ impl From<FileSystemEdit> for SourceChange {
|
|||
source_file_edits: Default::default(),
|
||||
file_system_edits: vec![edit],
|
||||
is_snippet: false,
|
||||
..SourceChange::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue