Require ModPath for importing

This commit is contained in:
Kirill Bulatov 2020-02-02 14:06:51 +02:00
parent a9669a5505
commit 6dae5cbb11
6 changed files with 65 additions and 37 deletions

View file

@ -1,4 +1,4 @@
use hir::{self, db::HirDatabase}; use hir::{self, db::HirDatabase, ModPath};
use ra_syntax::{ use ra_syntax::{
ast::{self, NameOwner}, ast::{self, NameOwner},
AstNode, Direction, SmolStr, AstNode, Direction, SmolStr,
@ -21,9 +21,10 @@ pub fn auto_import_text_edit(
// The statement to use as anchor (last resort) // The statement to use as anchor (last resort)
anchor: &SyntaxNode, anchor: &SyntaxNode,
// The path to import as a sequence of strings // The path to import as a sequence of strings
target: &[SmolStr], path_to_import: &ModPath,
edit: &mut TextEditBuilder, edit: &mut TextEditBuilder,
) { ) {
let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>();
let container = position.ancestors().find_map(|n| { let container = position.ancestors().find_map(|n| {
if let Some(module) = ast::Module::cast(n.clone()) { if let Some(module) = ast::Module::cast(n.clone()) {
return module.item_list().map(|it| it.syntax().clone()); return module.item_list().map(|it| it.syntax().clone());
@ -32,8 +33,8 @@ pub fn auto_import_text_edit(
}); });
if let Some(container) = container { if let Some(container) = container {
let action = best_action_for_target(container, anchor.clone(), target); let action = best_action_for_target(container, anchor.clone(), &target);
make_assist(&action, target, edit); make_assist(&action, &target, edit);
} }
} }

View file

@ -1,7 +1,6 @@
use hir::db::HirDatabase; use hir::{db::HirDatabase, ModPath};
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
SmolStr,
SyntaxKind::USE_ITEM, SyntaxKind::USE_ITEM,
SyntaxNode, SyntaxNode,
}; };
@ -58,7 +57,6 @@ pub(crate) fn auto_import<F: ImportsLocator>(
.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())
.take(20) .take(20)
.map(|import| import.to_string())
.collect::<std::collections::BTreeSet<_>>(); .collect::<std::collections::BTreeSet<_>>();
if proposed_imports.is_empty() { if proposed_imports.is_empty() {
return None; return None;
@ -76,11 +74,10 @@ pub(crate) fn auto_import<F: ImportsLocator>(
) )
} }
fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder { fn import_to_action(import: ModPath, 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));
let import_segments = import.split("::").map(SmolStr::new).collect::<Vec<_>>(); auto_import_text_edit(position, anchor, &import, action_builder.text_edit_builder());
auto_import_text_edit(position, anchor, &import_segments, action_builder.text_edit_builder());
action_builder action_builder
} }

View file

@ -59,6 +59,7 @@ pub use hir_def::{
ModuleDefId, // FIXME this is exposed and should be used for implementing the `TestImportsLocator` in `ra_assists` only, should be removed later along with the trait and the implementation. ModuleDefId, // FIXME this is exposed and should be used for implementing the `TestImportsLocator` in `ra_assists` only, should be removed later along with the trait and the implementation.
}; };
pub use hir_expand::{ pub use hir_expand::{
name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, name::{known, Name},
HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
}; };
pub use hir_ty::{display::HirDisplay, CallableDef}; pub use hir_ty::{display::HirDisplay, CallableDef};

View file

@ -16,13 +16,13 @@ use ra_syntax::ast;
use crate::{type_ref::TypeRef, InFile}; use crate::{type_ref::TypeRef, InFile};
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModPath { pub struct ModPath {
pub kind: PathKind, pub kind: PathKind,
pub segments: Vec<Name>, pub segments: Vec<Name>,
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PathKind { pub enum PathKind {
Plain, Plain,
/// `self::` is `Super(0)` /// `self::` is `Super(0)`

View file

@ -143,6 +143,9 @@ pub mod known {
std, std,
core, core,
alloc, alloc,
hash,
fmt,
io,
iter, iter,
ops, ops,
future, future,
@ -167,6 +170,9 @@ pub mod known {
Neg, Neg,
Not, Not,
Index, Index,
Display,
Iterator,
Hasher,
// Builtin macros // Builtin macros
file, file,
column, column,

View file

@ -6,6 +6,7 @@ use ra_text_edit::TextEditBuilder;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};
use hir::{ModPath, PathKind};
pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
if !ctx.is_trivial_path { if !ctx.is_trivial_path {
@ -54,58 +55,80 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
} }
} }
fn build_import_label(name: &str, path: &[SmolStr]) -> String { fn build_import_label(name: &str, path: &ModPath) -> String {
let mut buf = String::with_capacity(64); let mut buf = String::with_capacity(64);
buf.push_str(name); buf.push_str(name);
buf.push_str(" ("); buf.push_str(" (");
fmt_import_path(path, &mut buf); buf.push_str(&path.to_string());
buf.push_str(")"); buf.push_str(")");
buf buf
} }
fn fmt_import_path(path: &[SmolStr], buf: &mut String) {
let mut segments = path.iter();
if let Some(s) = segments.next() {
buf.push_str(&s);
}
for s in segments {
buf.push_str("::");
buf.push_str(&s);
}
}
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub(crate) struct ImportResolver { pub(crate) struct ImportResolver {
// todo: use fst crate or something like that // todo: use fst crate or something like that
dummy_names: Vec<(SmolStr, Vec<SmolStr>)>, dummy_names: Vec<(SmolStr, ModPath)>,
} }
impl ImportResolver { impl ImportResolver {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
let dummy_names = vec![ let dummy_names = vec![
(SmolStr::new("fmt"), vec![SmolStr::new("std"), SmolStr::new("fmt")]), (
(SmolStr::new("io"), vec![SmolStr::new("std"), SmolStr::new("io")]), SmolStr::new("fmt"),
(SmolStr::new("iter"), vec![SmolStr::new("std"), SmolStr::new("iter")]), ModPath { kind: PathKind::Plain, segments: vec![hir::known::std, hir::known::fmt] },
(SmolStr::new("hash"), vec![SmolStr::new("std"), SmolStr::new("hash")]), ),
(
SmolStr::new("io"),
ModPath { kind: PathKind::Plain, segments: vec![hir::known::std, hir::known::io] },
),
(
SmolStr::new("iter"),
ModPath {
kind: PathKind::Plain,
segments: vec![hir::known::std, hir::known::iter],
},
),
(
SmolStr::new("hash"),
ModPath {
kind: PathKind::Plain,
segments: vec![hir::known::std, hir::known::hash],
},
),
( (
SmolStr::new("Debug"), SmolStr::new("Debug"),
vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Debug")], ModPath {
kind: PathKind::Plain,
segments: vec![hir::known::std, hir::known::fmt, hir::known::Debug],
},
), ),
( (
SmolStr::new("Display"), SmolStr::new("Display"),
vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Display")], ModPath {
kind: PathKind::Plain,
segments: vec![hir::known::std, hir::known::fmt, hir::known::Display],
},
), ),
( (
SmolStr::new("Hash"), SmolStr::new("Hash"),
vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hash")], ModPath {
kind: PathKind::Plain,
segments: vec![hir::known::std, hir::known::hash, hir::known::Hash],
},
), ),
( (
SmolStr::new("Hasher"), SmolStr::new("Hasher"),
vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hasher")], ModPath {
kind: PathKind::Plain,
segments: vec![hir::known::std, hir::known::hash, hir::known::Hasher],
},
), ),
( (
SmolStr::new("Iterator"), SmolStr::new("Iterator"),
vec![SmolStr::new("std"), SmolStr::new("iter"), SmolStr::new("Iterator")], ModPath {
kind: PathKind::Plain,
segments: vec![hir::known::std, hir::known::iter, hir::known::Iterator],
},
), ),
]; ];
@ -115,7 +138,7 @@ impl ImportResolver {
// Returns a map of importable items filtered by name. // Returns a map of importable items filtered by name.
// The map associates item name with its full path. // The map associates item name with its full path.
// todo: should return Resolutions // todo: should return Resolutions
pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, Vec<SmolStr>> { pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, ModPath> {
if name.len() > 1 { if name.len() > 1 {
self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect() self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect()
} else { } else {