move auto-imoprter into IDE

auto-import is purely an IDE concern, so it should be done outside of
HIR
This commit is contained in:
Aleksey Kladov 2019-04-22 15:56:28 +03:00
parent 200032852b
commit e01052d1f0
7 changed files with 68 additions and 92 deletions

View File

@ -492,7 +492,6 @@ fn apply_auto_import(
}
}
#[allow(unused)]
pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> {
let mut ps = Vec::<SmolStr>::with_capacity(10);
match path.kind {
@ -503,7 +502,7 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> {
hir::PathKind::Super => ps.push("super".into()),
}
for s in path.segments.iter() {
ps.push(s.name.to_smolstr());
ps.push(s.name.to_string().into());
}
ps
}
@ -511,7 +510,6 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> {
// This function produces sequence of text edits into edit
// to import the target path in the most appropriate scope given
// the cursor position
#[allow(unused)]
pub fn auto_import_text_edit(
// Ideally the position of the cursor, used to
position: &SyntaxNode,

View File

@ -52,7 +52,7 @@ use crate::{
db::{HirDatabase, DefDatabase},
name::{AsName, KnownName},
source_id::{FileAstId, AstId},
resolve::Resolver, resolve::ImportResolver,
resolve::Resolver,
};
pub use self::{

View File

@ -46,8 +46,17 @@ impl Name {
Name::new(idx.to_string().into())
}
pub fn to_smolstr(&self) -> SmolStr {
self.text.clone()
// There's should be no way to extract a string out of `Name`: `Name` in the
// future, `Name` will include hygiene information, and you can't encode
// hygiene into a String.
//
// If you need to compare something with `Name`, compare `Name`s directly.
//
// If you need to render `Name` for the user, use the `Display` impl, but be
// aware that it strips hygiene info.
#[deprecated(note = "use to_string instead")]
pub fn as_smolstr(&self) -> &SmolStr {
&self.text
}
pub(crate) fn as_known_name(&self) -> Option<KnownName> {

View File

@ -23,12 +23,6 @@ pub(crate) struct Resolver {
scopes: Vec<Scope>,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct ImportResolver {
// todo: use fst crate or something like that
dummy_names: Vec<(SmolStr, Vec<SmolStr>)>,
}
// FIXME how to store these best
#[derive(Debug, Clone)]
pub(crate) struct ModuleItemMap {
@ -317,56 +311,3 @@ impl Scope {
}
}
}
impl ImportResolver {
pub(crate) fn new() -> Self {
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("iter"), vec![SmolStr::new("std"), SmolStr::new("iter")]),
(SmolStr::new("hash"), vec![SmolStr::new("std"), SmolStr::new("hash")]),
(
SmolStr::new("Debug"),
vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Debug")],
),
(
SmolStr::new("Display"),
vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Display")],
),
(
SmolStr::new("Hash"),
vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hash")],
),
(
SmolStr::new("Hasher"),
vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hasher")],
),
(
SmolStr::new("Iterator"),
vec![SmolStr::new("std"), SmolStr::new("iter"), SmolStr::new("Iterator")],
),
];
ImportResolver { dummy_names }
}
// Returns a map of importable items filtered by name.
// The map associates item name with its full path.
// todo: should return Resolutions
pub(crate) fn all_names(
&self,
_db: &impl HirDatabase,
name: &Name,
) -> FxHashMap<SmolStr, Vec<SmolStr>> {
let name = name.to_smolstr();
if name.len() > 1 {
self.dummy_names
.iter()
.filter(|(n, _)| n.as_str().contains(name.as_str()))
.cloned()
.collect()
} else {
FxHashMap::default()
}
}
}

View File

@ -14,12 +14,11 @@ use ra_syntax::{
ast::{self, AstNode, NameOwner},
algo::find_node_at_offset,
SyntaxKind::*,
SmolStr,
};
use crate::{
HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name,
AsName, Module, HirFileId, Crate, Trait, Resolver, Ty, ImportResolver,
AsName, Module, HirFileId, Crate, Trait, Resolver, Ty,
expr::{BodySourceMap, scope::{ScopeId, ExprScopes}},
ids::LocationCtx,
expr, AstId,
@ -171,7 +170,6 @@ fn def_with_body_from_child_node(
#[derive(Debug)]
pub struct SourceAnalyzer {
resolver: Resolver,
import_resolver: ImportResolver,
body_source_map: Option<Arc<BodySourceMap>>,
infer: Option<Arc<crate::ty::InferenceResult>>,
scopes: Option<Arc<crate::expr::ExprScopes>>,
@ -219,7 +217,6 @@ impl SourceAnalyzer {
offset: Option<TextUnit>,
) -> SourceAnalyzer {
let def_with_body = def_with_body_from_child_node(db, file_id, node);
let import_resolver = ImportResolver::new();
if let Some(def) = def_with_body {
let source_map = def.body_source_map(db);
let scopes = db.expr_scopes(def);
@ -230,7 +227,6 @@ impl SourceAnalyzer {
let resolver = expr::resolver_for_scope(def.body(db), db, scope);
SourceAnalyzer {
resolver,
import_resolver,
body_source_map: Some(source_map),
infer: Some(def.infer(db)),
scopes: Some(scopes),
@ -241,7 +237,6 @@ impl SourceAnalyzer {
.ancestors()
.find_map(|node| try_get_resolver_for_node(db, file_id, node))
.unwrap_or_default(),
import_resolver,
body_source_map: None,
infer: None,
scopes: None,
@ -328,14 +323,6 @@ impl SourceAnalyzer {
self.resolver.all_names(db)
}
pub fn all_import_names(
&self,
db: &impl HirDatabase,
name: &Name,
) -> FxHashMap<SmolStr, Vec<SmolStr>> {
self.import_resolver.all_names(db, name)
}
pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
// FIXME: at least, this should work with any DefWithBody, but ideally
// this should be hir-based altogether

View File

@ -1,6 +1,8 @@
use rustc_hash::FxHashMap;
use ra_text_edit::TextEditBuilder;
use ra_syntax::SmolStr;
use ra_assists::auto_import;
use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext};
pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
@ -10,7 +12,8 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
}
if let Some(name) = ctx.path_ident.as_ref() {
let import_names = ctx.analyzer.all_import_names(ctx.db, name);
let import_resolver = ImportResolver::new();
let import_names = import_resolver.all_names(&name.to_string());
import_names.into_iter().for_each(|(name, path)| {
let edit = {
let mut builder = TextEditBuilder::default();
@ -64,6 +67,56 @@ fn fmt_import_path(path: &Vec<SmolStr>, buf: &mut String) {
}
}
#[derive(Debug, Clone, Default)]
pub(crate) struct ImportResolver {
// todo: use fst crate or something like that
dummy_names: Vec<(SmolStr, Vec<SmolStr>)>,
}
impl ImportResolver {
pub(crate) fn new() -> Self {
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("iter"), vec![SmolStr::new("std"), SmolStr::new("iter")]),
(SmolStr::new("hash"), vec![SmolStr::new("std"), SmolStr::new("hash")]),
(
SmolStr::new("Debug"),
vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Debug")],
),
(
SmolStr::new("Display"),
vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Display")],
),
(
SmolStr::new("Hash"),
vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hash")],
),
(
SmolStr::new("Hasher"),
vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hasher")],
),
(
SmolStr::new("Iterator"),
vec![SmolStr::new("std"), SmolStr::new("iter"), SmolStr::new("Iterator")],
),
];
ImportResolver { dummy_names }
}
// Returns a map of importable items filtered by name.
// The map associates item name with its full path.
// todo: should return Resolutions
pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, Vec<SmolStr>> {
if name.len() > 1 {
self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect()
} else {
FxHashMap::default()
}
}
}
#[cfg(test)]
mod tests {
use crate::completion::{CompletionKind, check_completion};

View File

@ -86,18 +86,6 @@ impl<'a> CompletionContext<'a> {
}
fn fill(&mut self, original_file: &'a SourceFile, offset: TextUnit) {
// We heed the original NameRef before the "intellijRulezz" hack
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(original_file.syntax(), offset)
{
if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
if let Some(path) = hir::Path::from_ast(path) {
if let Some(ident) = path.as_ident() {
self.path_ident = Some(ident.clone());
}
}
}
}
// Insert a fake ident to get a valid parse tree. We will use this file
// to determine context, though the original_file will be used for
// actual completion.