mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Merge #2942
2942: Properly select a target for auto importing r=matklad a=SomeoneToIgnore Fixes https://github.com/rust-analyzer/rust-analyzer/issues/2932 The corresponding test has the caret placed in the beggining of the document despite the import inserted, but I don't thing I should fix it here: * in real life, there's some text written before the import and for those cases the caret behaves normally * it's a separate functionality that needs to be refactored anyway later (the `auto_import_text_edit`) Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
commit
b67f695956
1 changed files with 17 additions and 29 deletions
|
@ -1,8 +1,8 @@
|
||||||
use hir::db::HirDatabase;
|
use hir::db::HirDatabase;
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SmolStr, SyntaxElement,
|
SmolStr,
|
||||||
SyntaxKind::{NAME_REF, USE_ITEM},
|
SyntaxKind::USE_ITEM,
|
||||||
SyntaxNode,
|
SyntaxNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,25 +32,28 @@ pub(crate) fn auto_import<F: ImportsLocator>(
|
||||||
ctx: AssistCtx<impl HirDatabase>,
|
ctx: AssistCtx<impl HirDatabase>,
|
||||||
imports_locator: &mut F,
|
imports_locator: &mut F,
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let path: ast::Path = ctx.find_node_at_offset()?;
|
let path_to_import: ast::Path = ctx.find_node_at_offset()?;
|
||||||
let module = path.syntax().ancestors().find_map(ast::Module::cast);
|
let path_to_import_syntax = path_to_import.syntax();
|
||||||
|
if path_to_import_syntax.ancestors().find(|ancestor| ancestor.kind() == USE_ITEM).is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast);
|
||||||
let position = match module.and_then(|it| it.item_list()) {
|
let position = match module.and_then(|it| it.item_list()) {
|
||||||
Some(item_list) => item_list.syntax().clone(),
|
Some(item_list) => item_list.syntax().clone(),
|
||||||
None => {
|
None => {
|
||||||
let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?;
|
let current_file = path_to_import_syntax.ancestors().find_map(ast::SourceFile::cast)?;
|
||||||
current_file.syntax().clone()
|
current_file.syntax().clone()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let source_analyzer = ctx.source_analyzer(&position, None);
|
let source_analyzer = ctx.source_analyzer(&position, None);
|
||||||
let module_with_name_to_import = source_analyzer.module()?;
|
let module_with_name_to_import = source_analyzer.module()?;
|
||||||
let path_to_import = ctx.covering_element().ancestors().find_map(ast::Path::cast)?;
|
|
||||||
if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() {
|
if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name_to_import = &find_applicable_name_ref(ctx.covering_element())?.syntax().to_string();
|
|
||||||
let proposed_imports = imports_locator
|
let proposed_imports = imports_locator
|
||||||
.find_imports(&name_to_import.to_string())
|
.find_imports(&path_to_import_syntax.to_string())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
|
.filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
|
||||||
.filter(|use_path| !use_path.segments.is_empty())
|
.filter(|use_path| !use_path.segments.is_empty())
|
||||||
|
@ -64,26 +67,11 @@ pub(crate) fn auto_import<F: ImportsLocator>(
|
||||||
ctx.add_assist_group(AssistId("auto_import"), "auto import", || {
|
ctx.add_assist_group(AssistId("auto_import"), "auto import", || {
|
||||||
proposed_imports
|
proposed_imports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|import| import_to_action(import, &position, &path_to_import.syntax()))
|
.map(|import| import_to_action(import, &position, &path_to_import_syntax))
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_applicable_name_ref(element: SyntaxElement) -> Option<ast::NameRef> {
|
|
||||||
if element.ancestors().find(|ancestor| ancestor.kind() == USE_ITEM).is_some() {
|
|
||||||
None
|
|
||||||
} else if element.kind() == NAME_REF {
|
|
||||||
Some(element.as_node().cloned().and_then(ast::NameRef::cast)?)
|
|
||||||
} else {
|
|
||||||
let parent = element.parent()?;
|
|
||||||
if parent.kind() == NAME_REF {
|
|
||||||
Some(ast::NameRef::cast(parent)?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder {
|
fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder {
|
||||||
let mut action_builder = ActionBuilder::default();
|
let mut action_builder = ActionBuilder::default();
|
||||||
action_builder.label(format!("Import `{}`", &import));
|
action_builder.label(format!("Import `{}`", &import));
|
||||||
|
@ -110,16 +98,16 @@ mod tests {
|
||||||
auto_import,
|
auto_import,
|
||||||
TestImportsLocator::new,
|
TestImportsLocator::new,
|
||||||
r"
|
r"
|
||||||
PubStruct<|>
|
<|>PubStruct
|
||||||
|
|
||||||
pub mod PubMod {
|
pub mod PubMod {
|
||||||
pub struct PubStruct;
|
pub struct PubStruct;
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
use PubMod::PubStruct;
|
<|>use PubMod::PubStruct;
|
||||||
|
|
||||||
PubStruct<|>
|
PubStruct
|
||||||
|
|
||||||
pub mod PubMod {
|
pub mod PubMod {
|
||||||
pub struct PubStruct;
|
pub struct PubStruct;
|
||||||
|
@ -134,7 +122,7 @@ mod tests {
|
||||||
auto_import,
|
auto_import,
|
||||||
TestImportsLocator::new,
|
TestImportsLocator::new,
|
||||||
r"
|
r"
|
||||||
PubStruct<|>
|
PubSt<|>ruct
|
||||||
|
|
||||||
pub mod PubMod1 {
|
pub mod PubMod1 {
|
||||||
pub struct PubStruct;
|
pub struct PubStruct;
|
||||||
|
@ -149,7 +137,7 @@ mod tests {
|
||||||
r"
|
r"
|
||||||
use PubMod1::PubStruct;
|
use PubMod1::PubStruct;
|
||||||
|
|
||||||
PubStruct<|>
|
PubSt<|>ruct
|
||||||
|
|
||||||
pub mod PubMod1 {
|
pub mod PubMod1 {
|
||||||
pub struct PubStruct;
|
pub struct PubStruct;
|
||||||
|
|
Loading…
Reference in a new issue