mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-07 23:47:39 +00:00
rename mod
This commit is contained in:
parent
b82fe73d1a
commit
bc0f79f74a
@ -1,7 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
self, Problem, source_binder,
|
self, Problem, source_binder::{
|
||||||
|
self,
|
||||||
|
module_from_declaration
|
||||||
|
}, ModuleSource,
|
||||||
};
|
};
|
||||||
use ra_db::{
|
use ra_db::{
|
||||||
FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase,
|
FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase,
|
||||||
@ -9,16 +12,16 @@ use ra_db::{
|
|||||||
};
|
};
|
||||||
use ra_ide_api_light::{self, assists, LocalEdit, Severity};
|
use ra_ide_api_light::{self, assists, LocalEdit, Severity};
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
TextRange, AstNode, SourceFile,
|
algo::find_node_at_offset, ast::{self, NameOwner}, AstNode,
|
||||||
ast::{self, NameOwner},
|
SourceFile,
|
||||||
algo::find_node_at_offset,
|
TextRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnalysisChange,
|
AnalysisChange,
|
||||||
CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit,
|
CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit,
|
||||||
Query, RootChange, SourceChange, SourceFileEdit,
|
Query, RootChange, SourceChange, SourceFileEdit,
|
||||||
symbol_index::{LibrarySymbolsQuery, FileSymbol},
|
symbol_index::{FileSymbol, LibrarySymbolsQuery},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl db::RootDatabase {
|
impl db::RootDatabase {
|
||||||
@ -110,6 +113,7 @@ impl db::RootDatabase {
|
|||||||
};
|
};
|
||||||
vec![krate.crate_id()]
|
vec![krate.crate_id()]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
|
pub(crate) fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> {
|
||||||
let file = self.source_file(position.file_id);
|
let file = self.source_file(position.file_id);
|
||||||
// Find the binding associated with the offset
|
// Find the binding associated with the offset
|
||||||
@ -230,20 +234,94 @@ impl db::RootDatabase {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec<SourceFileEdit> {
|
pub(crate) fn rename(&self, position: FilePosition, new_name: &str) -> Vec<SourceFileEdit> {
|
||||||
self.find_all_refs(position)
|
self.find_all_refs(position)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(file_id, text_range)| SourceFileEdit {
|
.map(|(file_id, text_range)| SourceFileEdit {
|
||||||
file_id: *file_id,
|
file_id: *file_id,
|
||||||
|
=======
|
||||||
|
pub(crate) fn rename(
|
||||||
|
&self,
|
||||||
|
position: FilePosition,
|
||||||
|
new_name: &str,
|
||||||
|
) -> Cancelable<Option<SourceChange>> {
|
||||||
|
let mut source_file_edits = Vec::new();
|
||||||
|
let mut file_system_edits = Vec::new();
|
||||||
|
|
||||||
|
let source_file = self.source_file(position.file_id);
|
||||||
|
let syntax = source_file.syntax();
|
||||||
|
// We are rename a mod
|
||||||
|
if let (Some(ast_module), Some(name)) = (
|
||||||
|
find_node_at_offset::<ast::Module>(syntax, position.offset),
|
||||||
|
find_node_at_offset::<ast::Name>(syntax, position.offset),
|
||||||
|
) {
|
||||||
|
if let Some(module) = module_from_declaration(self, position.file_id, &ast_module)? {
|
||||||
|
let (file_id, module_source) = module.definition_source(self)?;
|
||||||
|
match module_source {
|
||||||
|
ModuleSource::SourceFile(..) => {
|
||||||
|
let move_file = FileSystemEdit::MoveFile {
|
||||||
|
src: file_id,
|
||||||
|
dst_source_root: self.file_source_root(position.file_id),
|
||||||
|
dst_path: self
|
||||||
|
.file_relative_path(file_id)
|
||||||
|
.with_file_name(new_name)
|
||||||
|
.with_extension("rs"),
|
||||||
|
};
|
||||||
|
file_system_edits.push(move_file);
|
||||||
|
}
|
||||||
|
ModuleSource::Module(..) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let edit = SourceFileEdit {
|
||||||
|
file_id: position.file_id,
|
||||||
|
>>>>>>> rename mod
|
||||||
edit: {
|
edit: {
|
||||||
let mut builder = ra_text_edit::TextEditBuilder::default();
|
let mut builder = ra_text_edit::TextEditBuilder::default();
|
||||||
builder.replace(*text_range, new_name.into());
|
builder.replace(name.syntax().range(), new_name.into());
|
||||||
builder.finish()
|
builder.finish()
|
||||||
},
|
},
|
||||||
|
<<<<<<< HEAD
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> {
|
pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Vec<FileSymbol> {
|
||||||
|
=======
|
||||||
|
};
|
||||||
|
source_file_edits.push(edit);
|
||||||
|
}
|
||||||
|
// rename references
|
||||||
|
else {
|
||||||
|
let edit = self
|
||||||
|
.find_all_refs(position)?
|
||||||
|
.iter()
|
||||||
|
.map(|(file_id, text_range)| SourceFileEdit {
|
||||||
|
file_id: *file_id,
|
||||||
|
edit: {
|
||||||
|
let mut builder = ra_text_edit::TextEditBuilder::default();
|
||||||
|
builder.replace(*text_range, new_name.into());
|
||||||
|
builder.finish()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if edit.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
source_file_edits = edit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(Some(SourceChange {
|
||||||
|
label: "rename".to_string(),
|
||||||
|
source_file_edits,
|
||||||
|
file_system_edits,
|
||||||
|
cursor_position: None,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn index_resolve(&self, name_ref: &ast::NameRef) -> Cancelable<Vec<FileSymbol>> {
|
||||||
|
>>>>>>> rename mod
|
||||||
let name = name_ref.text();
|
let name = name_ref.text();
|
||||||
let mut query = Query::new(name.to_string());
|
let mut query = Query::new(name.to_string());
|
||||||
query.exact();
|
query.exact();
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
use ra_ide_api::{
|
||||||
|
AnalysisChange,
|
||||||
|
CrateGraph, FileId, mock_analysis::{MockAnalysis, single_file, single_file_with_position}, Query,
|
||||||
|
};
|
||||||
|
use ra_ide_api::mock_analysis::analysis_and_position;
|
||||||
use ra_syntax::TextRange;
|
use ra_syntax::TextRange;
|
||||||
use test_utils::assert_eq_text;
|
use test_utils::assert_eq_text;
|
||||||
use insta::assert_debug_snapshot_matches;
|
use insta::assert_debug_snapshot_matches;
|
||||||
|
|
||||||
use ra_ide_api::{
|
mod runnables;
|
||||||
mock_analysis::{single_file, single_file_with_position, MockAnalysis},
|
|
||||||
AnalysisChange, CrateGraph, FileId, Query
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unresolved_module_diagnostic() {
|
fn test_unresolved_module_diagnostic() {
|
||||||
@ -91,6 +93,7 @@ fn test_find_all_refs_for_fn_param() {
|
|||||||
let refs = get_all_refs(code);
|
let refs = get_all_refs(code);
|
||||||
assert_eq!(refs.len(), 2);
|
assert_eq!(refs.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rename_for_local() {
|
fn test_rename_for_local() {
|
||||||
test_rename(
|
test_rename(
|
||||||
@ -167,15 +170,35 @@ fn test_rename_for_mut_param() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rename_mod() {
|
||||||
|
let (analysis, position) = analysis_and_position(
|
||||||
|
"
|
||||||
|
//- /bar.rs
|
||||||
|
mod fo<|>o;
|
||||||
|
//- /bar/foo.rs
|
||||||
|
// emtpy
|
||||||
|
",
|
||||||
|
);
|
||||||
|
let new_name = "foo2";
|
||||||
|
let source_change = analysis.rename(position, new_name).unwrap();
|
||||||
|
assert_eq_dbg(
|
||||||
|
r#"Some(SourceChange { label: "rename", source_file_edits: [SourceFileEdit { file_id: FileId(1), edit: TextEdit { atoms: [AtomTextEdit { delete: [4; 7), insert: "foo2" }] } }], file_system_edits: [MoveFile { src: FileId(2), dst_source_root: SourceRootId(0), dst_path: "bar/foo2.rs" }], cursor_position: None })"#,
|
||||||
|
&source_change,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_rename(text: &str, new_name: &str, expected: &str) {
|
fn test_rename(text: &str, new_name: &str, expected: &str) {
|
||||||
let (analysis, position) = single_file_with_position(text);
|
let (analysis, position) = single_file_with_position(text);
|
||||||
let edits = analysis.rename(position, new_name).unwrap();
|
let source_change = analysis.rename(position, new_name).unwrap();
|
||||||
let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default();
|
let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default();
|
||||||
let mut file_id: Option<FileId> = None;
|
let mut file_id: Option<FileId> = None;
|
||||||
for edit in edits {
|
if let Some(change) = source_change {
|
||||||
file_id = Some(edit.file_id);
|
for edit in change.source_file_edits {
|
||||||
for atom in edit.edit.as_atoms() {
|
file_id = Some(edit.file_id);
|
||||||
text_edit_bulder.replace(atom.delete, atom.insert.clone());
|
for atom in edit.edit.as_atoms() {
|
||||||
|
text_edit_bulder.replace(atom.delete, atom.insert.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result = text_edit_bulder
|
let result = text_edit_bulder
|
||||||
|
@ -411,10 +411,7 @@ struct PoolDispatcher<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PoolDispatcher<'a> {
|
impl<'a> PoolDispatcher<'a> {
|
||||||
fn on<'b, R>(
|
fn on<R>(&mut self, f: fn(ServerWorld, R::Params) -> Result<R::Result>) -> Result<&mut Self>
|
||||||
&'b mut self,
|
|
||||||
f: fn(ServerWorld, R::Params) -> Result<R::Result>,
|
|
||||||
) -> Result<&'b mut Self>
|
|
||||||
where
|
where
|
||||||
R: req::Request,
|
R: req::Request,
|
||||||
R::Params: DeserializeOwned + Send + 'static,
|
R::Params: DeserializeOwned + Send + 'static,
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use gen_lsp_server::ErrorCode;
|
use gen_lsp_server::ErrorCode;
|
||||||
use lsp_types::{
|
use lsp_types::{
|
||||||
CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity,
|
CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity,
|
||||||
@ -7,7 +5,7 @@ use lsp_types::{
|
|||||||
FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent,
|
FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent,
|
||||||
MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range,
|
MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range,
|
||||||
RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit,
|
RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit,
|
||||||
WorkspaceEdit,
|
WorkspaceEdit, DocumentChanges, TextDocumentEdit, DocumentChangeOperation, ResourceOp
|
||||||
};
|
};
|
||||||
use ra_ide_api::{
|
use ra_ide_api::{
|
||||||
FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity,
|
FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity,
|
||||||
@ -467,26 +465,43 @@ pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result<Option<
|
|||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let renames = world
|
let change = world
|
||||||
.analysis()
|
.analysis()
|
||||||
.rename(FilePosition { file_id, offset }, &*params.new_name)?;
|
.rename(FilePosition { file_id, offset }, &*params.new_name)?;
|
||||||
if renames.is_empty() {
|
if change.is_none() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut changes = HashMap::new();
|
let mut source_change = change.unwrap();
|
||||||
for edit in renames {
|
let text_document_edits = source_change
|
||||||
changes
|
.source_file_edits
|
||||||
.entry(file_id.try_conv_with(&world)?)
|
.drain(..)
|
||||||
.or_insert_with(Vec::new)
|
.into_iter()
|
||||||
.extend(edit.edit.conv_with(&line_index));
|
.map(|e| e.try_conv_with(&world))
|
||||||
}
|
.collect::<Result<Vec<TextDocumentEdit>>>();
|
||||||
|
|
||||||
|
let text_document_ops = source_change
|
||||||
|
.file_system_edits
|
||||||
|
.drain(..)
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| e.try_conv_with(&world))
|
||||||
|
.collect::<Result<Vec<ResourceOp>>>();
|
||||||
|
|
||||||
|
let mut document_changes = Vec::new();
|
||||||
|
document_changes.extend(
|
||||||
|
text_document_edits?
|
||||||
|
.into_iter()
|
||||||
|
.map(DocumentChangeOperation::Edit),
|
||||||
|
);
|
||||||
|
document_changes.extend(
|
||||||
|
text_document_ops?
|
||||||
|
.into_iter()
|
||||||
|
.map(DocumentChangeOperation::Op),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(Some(WorkspaceEdit {
|
Ok(Some(WorkspaceEdit {
|
||||||
changes: Some(changes),
|
changes: None,
|
||||||
|
document_changes: Some(DocumentChanges::Operations(document_changes)),
|
||||||
// TODO: return this instead if client/server support it. See #144
|
|
||||||
document_changes: None,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user