From 0e0ae47b47f80e30fca366e5922c19ff81b0a2e2 Mon Sep 17 00:00:00 2001 From: Andrea Pretto Date: Tue, 19 Feb 2019 17:54:00 +0100 Subject: auto_import: use TextEditBuilder instead of AssistBuilder to make it more reusable --- crates/ra_assists/src/assist_ctx.rs | 4 ++++ crates/ra_assists/src/auto_import.rs | 40 ++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index e80e35738..17a9041c5 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -144,6 +144,10 @@ impl AssistBuilder { self.replace(node.range(), replace_with) } + pub(crate) fn set_edit_builder(&mut self, edit: TextEditBuilder) { + self.edit = edit; + } + #[allow(unused)] pub(crate) fn delete(&mut self, range: TextRange) { self.edit.delete(range) diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index 3fdf6b0d9..6bc5caf76 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs @@ -1,3 +1,4 @@ +use ra_text_edit::TextEditBuilder; use hir::db::HirDatabase; use ra_syntax::{ @@ -374,7 +375,7 @@ fn best_action_for_target<'b, 'a: 'b>( } } -fn make_assist(action: &ImportAction, target: &[&ast::PathSegment], edit: &mut AssistBuilder) { +fn make_assist(action: &ImportAction, target: &[&ast::PathSegment], edit: &mut TextEditBuilder) { match action { ImportAction::AddNewUse { anchor, add_after_anchor } => { make_assist_add_new_use(anchor, *add_after_anchor, target, edit) @@ -408,7 +409,7 @@ fn make_assist_add_new_use( anchor: &Option<&SyntaxNode>, after: bool, target: &[&ast::PathSegment], - edit: &mut AssistBuilder, + edit: &mut TextEditBuilder, ) { if let Some(anchor) = anchor { let indent = ra_fmt::leading_indent(anchor); @@ -437,7 +438,7 @@ fn make_assist_add_in_tree_list( tree_list: &ast::UseTreeList, target: &[&ast::PathSegment], add_self: bool, - edit: &mut AssistBuilder, + edit: &mut TextEditBuilder, ) { let last = tree_list.use_trees().last(); if let Some(last) = last { @@ -466,7 +467,7 @@ fn make_assist_add_nested_import( first_segment_to_split: &Option<&ast::PathSegment>, target: &[&ast::PathSegment], add_self: bool, - edit: &mut AssistBuilder, + edit: &mut TextEditBuilder, ) { let use_tree = path.syntax().ancestors().find_map(ast::UseTree::cast); if let Some(use_tree) = use_tree { @@ -491,7 +492,7 @@ fn make_assist_add_nested_import( buf.push_str(", "); } edit.insert(start, buf); - edit.insert(end, "}"); + edit.insert(end, "}".to_string()); } } @@ -499,7 +500,7 @@ fn apply_auto_import<'a>( container: &SyntaxNode, path: &ast::Path, target: &[&'a ast::PathSegment], - edit: &mut AssistBuilder, + edit: &mut TextEditBuilder, ) { let action = best_action_for_target(container, path, target); make_assist(&action, target, edit); @@ -513,6 +514,25 @@ fn apply_auto_import<'a>( } } +pub fn auto_import_text_edit<'a>( + position: &SyntaxNode, + path: &ast::Path, + target: &[&'a ast::PathSegment], + edit: &mut TextEditBuilder, +) { + let container = position.ancestors().find_map(|n| { + if let Some(module) = ast::Module::cast(n) { + return module.item_list().map(ast::AstNode::syntax); + } + ast::SourceFile::cast(n).map(ast::AstNode::syntax) + }); + + if let Some(container) = container { + let action = best_action_for_target(container, path, target); + make_assist(&action, target, edit); + } +} + pub(crate) fn auto_import(mut ctx: AssistCtx) -> Option { let path: &ast::Path = ctx.node_at_offset()?; // We don't want to mess with use statements @@ -531,7 +551,9 @@ pub(crate) fn auto_import(mut ctx: AssistCtx) -> Option) -> Option Date: Tue, 19 Feb 2019 22:32:00 +0100 Subject: auto_import: make auto import working with target as a list of SmolStr instead of ast::Path --- crates/ra_assists/src/auto_import.rs | 128 ++++++++++++++++++----------------- crates/ra_hir/src/name.rs | 4 ++ 2 files changed, 69 insertions(+), 63 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index 6bc5caf76..7527d805d 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs @@ -1,21 +1,15 @@ use ra_text_edit::TextEditBuilder; -use hir::db::HirDatabase; +use hir::{ self, db::HirDatabase}; use ra_syntax::{ - ast::{ self, NameOwner }, AstNode, SyntaxNode, Direction, TextRange, + ast::{ self, NameOwner }, AstNode, SyntaxNode, Direction, TextRange, SmolStr, SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA } }; use crate::{ AssistId, - assist_ctx::{AssistCtx, Assist, AssistBuilder}, + assist_ctx::{AssistCtx, Assist}, }; -fn collect_path_segments(path: &ast::Path) -> Option> { - let mut v = Vec::new(); - collect_path_segments_raw(&mut v, path)?; - return Some(v); -} - fn collect_path_segments_raw<'a>( segments: &mut Vec<&'a ast::PathSegment>, mut path: &'a ast::Path, @@ -46,59 +40,43 @@ fn collect_path_segments_raw<'a>( return Some(segments.len() - oldlen); } -fn fmt_segments(segments: &[&ast::PathSegment]) -> String { +fn fmt_segments(segments: &[SmolStr]) -> String { let mut buf = String::new(); fmt_segments_raw(segments, &mut buf); return buf; } -fn fmt_segments_raw(segments: &[&ast::PathSegment], buf: &mut String) { - let mut first = true; - for s in segments { - if !first { - buf.push_str("::"); - } - match s.kind() { - Some(ast::PathSegmentKind::Name(nameref)) => buf.push_str(nameref.text()), - Some(ast::PathSegmentKind::SelfKw) => buf.push_str("self"), - Some(ast::PathSegmentKind::SuperKw) => buf.push_str("super"), - Some(ast::PathSegmentKind::CrateKw) => buf.push_str("crate"), - None => {} - } - first = false; +fn fmt_segments_raw(segments: &[SmolStr], buf: &mut String) { + let mut iter = segments.iter(); + if let Some(s) = iter.next() { + buf.push_str(s); + } + for s in iter { + buf.push_str("::"); + buf.push_str(s); } } // Returns the numeber of common segments. -fn compare_path_segments(left: &[&ast::PathSegment], right: &[&ast::PathSegment]) -> usize { +fn compare_path_segments(left: &[SmolStr], right: &[&ast::PathSegment]) -> usize { return left.iter().zip(right).filter(|(l, r)| compare_path_segment(l, r)).count(); } -fn compare_path_segment(a: &ast::PathSegment, b: &ast::PathSegment) -> bool { - if let (Some(ka), Some(kb)) = (a.kind(), b.kind()) { - match (ka, kb) { - (ast::PathSegmentKind::Name(nameref_a), ast::PathSegmentKind::Name(nameref_b)) => { - nameref_a.text() == nameref_b.text() - } - (ast::PathSegmentKind::SelfKw, ast::PathSegmentKind::SelfKw) => true, - (ast::PathSegmentKind::SuperKw, ast::PathSegmentKind::SuperKw) => true, - (ast::PathSegmentKind::CrateKw, ast::PathSegmentKind::CrateKw) => true, - (_, _) => false, +fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool { + if let Some(kb) = b.kind() { + match kb { + ast::PathSegmentKind::Name(nameref_b) => a == nameref_b.text(), + ast::PathSegmentKind::SelfKw => a == "self", + ast::PathSegmentKind::SuperKw => a == "super", + ast::PathSegmentKind::CrateKw => a == "crate", } } else { false } } -fn compare_path_segment_with_name(a: &ast::PathSegment, b: &ast::Name) -> bool { - if let Some(ka) = a.kind() { - return match (ka, b) { - (ast::PathSegmentKind::Name(nameref_a), _) => nameref_a.text() == b.text(), - (_, _) => false, - }; - } else { - false - } +fn compare_path_segment_with_name(a: &SmolStr, b: &ast::Name) -> bool { + a == b.text() } #[derive(Copy, Clone)] @@ -190,7 +168,7 @@ fn walk_use_tree_for_best_action<'a>( current_path_segments: &mut Vec<&'a ast::PathSegment>, // buffer containing path segments current_parent_use_tree_list: Option<&'a ast::UseTreeList>, // will be Some value if we are in a nested import current_use_tree: &'a ast::UseTree, // the use tree we are currently examinating - target: &[&'a ast::PathSegment], // the path we want to import + target: &[SmolStr], // the path we want to import ) -> ImportAction<'a> { // We save the number of segments in the buffer so we can restore the correct segments // before returning. Recursive call will add segments so we need to delete them. @@ -216,7 +194,7 @@ fn walk_use_tree_for_best_action<'a>( // This can happen only if current_use_tree is a direct child of a UseItem if let Some(name) = alias.and_then(ast::NameOwner::name) { - if compare_path_segment_with_name(target[0], name) { + if compare_path_segment_with_name(&target[0], name) { return ImportAction::Nothing; } } @@ -345,8 +323,8 @@ fn walk_use_tree_for_best_action<'a>( fn best_action_for_target<'b, 'a: 'b>( container: &'a SyntaxNode, - path: &'a ast::Path, - target: &'b [&'a ast::PathSegment], + anchor: &'a SyntaxNode, + target: &'b [SmolStr], ) -> ImportAction<'a> { let mut storage = Vec::with_capacity(16); // this should be the only allocation let best_action = container @@ -368,14 +346,14 @@ fn best_action_for_target<'b, 'a: 'b>( .children() .find_map(ast::ModuleItem::cast) .map(AstNode::syntax) - .or(Some(path.syntax())); + .or(Some(anchor)); return ImportAction::add_new_use(anchor, false); } } } -fn make_assist(action: &ImportAction, target: &[&ast::PathSegment], edit: &mut TextEditBuilder) { +fn make_assist(action: &ImportAction, target: &[SmolStr], edit: &mut TextEditBuilder) { match action { ImportAction::AddNewUse { anchor, add_after_anchor } => { make_assist_add_new_use(anchor, *add_after_anchor, target, edit) @@ -408,7 +386,7 @@ fn make_assist(action: &ImportAction, target: &[&ast::PathSegment], edit: &mut T fn make_assist_add_new_use( anchor: &Option<&SyntaxNode>, after: bool, - target: &[&ast::PathSegment], + target: &[SmolStr], edit: &mut TextEditBuilder, ) { if let Some(anchor) = anchor { @@ -436,7 +414,7 @@ fn make_assist_add_new_use( fn make_assist_add_in_tree_list( tree_list: &ast::UseTreeList, - target: &[&ast::PathSegment], + target: &[SmolStr], add_self: bool, edit: &mut TextEditBuilder, ) { @@ -465,7 +443,7 @@ fn make_assist_add_in_tree_list( fn make_assist_add_nested_import( path: &ast::Path, first_segment_to_split: &Option<&ast::PathSegment>, - target: &[&ast::PathSegment], + target: &[SmolStr], add_self: bool, edit: &mut TextEditBuilder, ) { @@ -496,28 +474,51 @@ fn make_assist_add_nested_import( } } -fn apply_auto_import<'a>( +fn apply_auto_import( container: &SyntaxNode, path: &ast::Path, - target: &[&'a ast::PathSegment], + target: &[SmolStr], edit: &mut TextEditBuilder, ) { - let action = best_action_for_target(container, path, target); + let action = best_action_for_target(container, path.syntax(), target); make_assist(&action, target, edit); - if let (Some(first), Some(last)) = (target.first(), target.last()) { + if let Some(last) = path.segment() { // Here we are assuming the assist will provide a correct use statement // so we can delete the path qualifier edit.delete(TextRange::from_to( - first.syntax().range().start(), + path.syntax().range().start(), last.syntax().range().start(), )); } } -pub fn auto_import_text_edit<'a>( +#[allow(unused)] +pub fn collect_hir_path_segments(path: &hir::Path) -> Vec { + let mut ps = Vec::::with_capacity(10); + match path.kind { + hir::PathKind::Abs => ps.push("".into()), + hir::PathKind::Crate => ps.push("crate".into()), + hir::PathKind::Plain => {}, + hir::PathKind::Self_ => ps.push("self".into()), + hir::PathKind::Super => ps.push("super".into()) + } + for s in path.segments.iter() { + ps.push(s.name.to_smolstr()); + } + ps +} + +// 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, - path: &ast::Path, - target: &[&'a ast::PathSegment], + // The statement to use as anchor (last resort) + anchor: &SyntaxNode, + // The path to import as a sequence of strings + target: &[SmolStr], edit: &mut TextEditBuilder, ) { let container = position.ancestors().find_map(|n| { @@ -528,7 +529,7 @@ pub fn auto_import_text_edit<'a>( }); if let Some(container) = container { - let action = best_action_for_target(container, path, target); + let action = best_action_for_target(container, anchor, target); make_assist(&action, target, edit); } } @@ -540,7 +541,8 @@ pub(crate) fn auto_import(mut ctx: AssistCtx) -> Option SmolStr { + self.text.clone() + } + pub(crate) fn as_known_name(&self) -> Option { let name = match self.text.as_str() { "isize" => KnownName::Isize, -- cgit v1.2.3 From cf0eff2e332f46eda4fcecb043854c9c0d710e4e Mon Sep 17 00:00:00 2001 From: Andrea Pretto Date: Fri, 19 Apr 2019 22:30:05 +0200 Subject: auto_import: better no anchor management --- crates/ra_assists/src/auto_import.rs | 55 +++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index 7527d805d..b002d0e4d 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs @@ -168,7 +168,7 @@ fn walk_use_tree_for_best_action<'a>( current_path_segments: &mut Vec<&'a ast::PathSegment>, // buffer containing path segments current_parent_use_tree_list: Option<&'a ast::UseTreeList>, // will be Some value if we are in a nested import current_use_tree: &'a ast::UseTree, // the use tree we are currently examinating - target: &[SmolStr], // the path we want to import + target: &[SmolStr], // the path we want to import ) -> ImportAction<'a> { // We save the number of segments in the buffer so we can restore the correct segments // before returning. Recursive call will add segments so we need to delete them. @@ -341,11 +341,11 @@ fn best_action_for_target<'b, 'a: 'b>( None => { // We have no action and no UseItem was found in container so we find // another item and we use it as anchor. - // If there are no items, we choose the target path itself as anchor. + // If there are no items above, we choose the target path itself as anchor. + // todo: we should include even whitespace blocks as anchor candidates let anchor = container .children() - .find_map(ast::ModuleItem::cast) - .map(AstNode::syntax) + .find(|n| n.range().start() < anchor.range().start()) .or(Some(anchor)); return ImportAction::add_new_use(anchor, false); @@ -498,9 +498,9 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec { match path.kind { hir::PathKind::Abs => ps.push("".into()), hir::PathKind::Crate => ps.push("crate".into()), - hir::PathKind::Plain => {}, + hir::PathKind::Plain => {} hir::PathKind::Self_ => ps.push("self".into()), - hir::PathKind::Super => ps.push("super".into()) + hir::PathKind::Super => ps.push("super".into()), } for s in path.segments.iter() { ps.push(s.name.to_smolstr()); @@ -513,7 +513,7 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec { // the cursor position #[allow(unused)] pub fn auto_import_text_edit( - // Ideally the position of the cursor, used to + // Ideally the position of the cursor, used to position: &SyntaxNode, // The statement to use as anchor (last resort) anchor: &SyntaxNode, @@ -590,6 +590,47 @@ std::fmt::Debug<|> " use std::fmt::Debug; +Debug<|> + ", + ); + } + #[test] + fn test_auto_import_add_use_no_anchor_with_item_below() { + check_assist( + auto_import, + " +std::fmt::Debug<|> + +fn main() { +} + ", + " +use std::fmt::Debug; + +Debug<|> + +fn main() { +} + ", + ); + } + + #[test] + fn test_auto_import_add_use_no_anchor_with_item_above() { + check_assist( + auto_import, + " +fn main() { +} + +std::fmt::Debug<|> + ", + " +use std::fmt::Debug; + +fn main() { +} + Debug<|> ", ); -- cgit v1.2.3 From 914421495835380b96e0016763fda6eff31a8179 Mon Sep 17 00:00:00 2001 From: Andrea Pretto Date: Mon, 15 Apr 2019 16:11:32 +0200 Subject: complete_import: add new import resolver infrastructure with some hardcoded importable name. Changes complete_scope to support that. --- crates/ra_assists/src/lib.rs | 2 +- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/resolve.rs | 65 ++++++++++++++++++++++ crates/ra_hir/src/source_binder.rs | 19 ++++++- crates/ra_ide_api/src/completion/complete_scope.rs | 55 ++++++++++++++++-- .../src/completion/completion_context.rs | 23 +++++++- 6 files changed, 155 insertions(+), 11 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index ded401b63..173c004cd 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -98,7 +98,7 @@ mod inline_local_variable; mod replace_if_let_with_match; mod split_import; mod remove_dbg; -mod auto_import; +pub mod auto_import; mod add_missing_impl_members; fn all_assists() -> &'static [fn(AssistCtx) -> Option] { diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 4411715de..f156e3f07 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -52,7 +52,7 @@ use crate::{ db::{HirDatabase, DefDatabase}, name::{AsName, KnownName}, source_id::{FileAstId, AstId}, - resolve::Resolver, + resolve::Resolver, resolve::ImportResolver, }; pub use self::{ diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index f2c85eb66..0f866e6c2 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -3,6 +3,8 @@ use std::sync::Arc; use rustc_hash::FxHashMap; +use ra_syntax::SmolStr; + use crate::{ ModuleDef, code_model_api::Crate, @@ -12,8 +14,12 @@ use crate::{ generics::GenericParams, expr::{scope::{ExprScopes, ScopeId}, PatId}, impl_block::ImplBlock, +<<<<<<< HEAD path::Path, Trait +======= + path::Path, Trait, +>>>>>>> complete_import: add new import resolver infrastructure with some hardcoded importable name. }; #[derive(Debug, Clone, Default)] @@ -21,6 +27,12 @@ pub(crate) struct Resolver { scopes: Vec, } +#[derive(Debug, Clone, Default)] +pub(crate) struct ImportResolver { + // todo: use fst crate or something like that + dummy_names: Vec<(SmolStr, Vec)>, +} + // FIXME how to store these best #[derive(Debug, Clone)] pub(crate) struct ModuleItemMap { @@ -309,3 +321,56 @@ 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> { + 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() + } + } +} diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index f1bb13bc6..a6f0ab289 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -14,14 +14,19 @@ 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, +<<<<<<< HEAD AsName, Module, HirFileId, Crate, Trait, Resolver, Ty, +======= + AsName, Module, HirFileId, Crate, Trait, Resolver, ImportResolver, +>>>>>>> complete_import: add new import resolver infrastructure with some hardcoded importable name. expr::{BodySourceMap, scope::{ScopeId, ExprScopes}}, ids::LocationCtx, - expr, AstId + expr, AstId, }; /// Locates the module by `FileId`. Picks topmost module in the file. @@ -170,6 +175,7 @@ fn def_with_body_from_child_node( #[derive(Debug)] pub struct SourceAnalyzer { resolver: Resolver, + import_resolver: ImportResolver, body_source_map: Option>, infer: Option>, scopes: Option>, @@ -217,6 +223,7 @@ impl SourceAnalyzer { offset: Option, ) -> 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); @@ -227,6 +234,7 @@ 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), @@ -237,6 +245,7 @@ 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, @@ -323,6 +332,14 @@ impl SourceAnalyzer { self.resolver.all_names(db) } + pub fn all_import_names( + &self, + db: &impl HirDatabase, + name: &Name, + ) -> FxHashMap> { + self.import_resolver.all_names(db, name) + } + pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec { // FIXME: at least, this should work with any DefWithBody, but ideally // this should be hir-based altogether diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index fd256fc3b..63d475823 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -1,12 +1,57 @@ -use crate::completion::{Completions, CompletionContext}; +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) { - if !ctx.is_trivial_path { - return; + if ctx.is_trivial_path { + let names = ctx.analyzer.all_names(ctx.db); + names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res)); } - let names = ctx.analyzer.all_names(ctx.db); - names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res)); + if let Some(name) = ctx.path_ident.as_ref() { + let import_names = ctx.analyzer.all_import_names(ctx.db, name); + import_names.into_iter().for_each(|(name, path)| { + let edit = { + let mut builder = TextEditBuilder::default(); + builder.replace(ctx.source_range(), name.to_string()); + auto_import::auto_import_text_edit( + ctx.token.parent(), + ctx.token.parent(), + &path, + &mut builder, + ); + builder.finish() + }; + CompletionItem::new( + CompletionKind::Reference, + ctx.source_range(), + build_import_label(&name, &path), + ) + .text_edit(edit) + .add_to(acc) + }); + } +} + +fn build_import_label(name: &str, path: &Vec) -> String { + let mut buf = String::with_capacity(64); + buf.push_str(name); + buf.push_str(" ("); + fmt_import_path(path, &mut buf); + buf.push_str(")"); + buf +} + +fn fmt_import_path(path: &Vec, 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); + } } #[cfg(test)] diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 359f2cffa..ca8f7900d 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -5,10 +5,10 @@ use ra_syntax::{ algo::{find_token_at_offset, find_covering_element, find_node_at_offset}, SyntaxKind::*, }; -use hir::source_binder; -use crate::{db, FilePosition}; +use hir::{ source_binder, Name }; +use crate::{db, FilePosition}; /// `CompletionContext` is created early during completion to figure out, where /// exactly is the cursor, syntax-wise. #[derive(Debug)] @@ -27,8 +27,10 @@ pub(crate) struct CompletionContext<'a> { pub(super) is_pat_binding: bool, /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. pub(super) is_trivial_path: bool, - /// If not a trivial, path, the prefix (qualifier). + /// If not a trivial path, the prefix (qualifier). pub(super) path_prefix: Option, + /// If a trivial path, the ident. + pub(super) path_ident: Option, pub(super) after_if: bool, /// `true` if we are a statement or a last expr in the block. pub(super) can_be_stmt: bool, @@ -63,6 +65,7 @@ impl<'a> CompletionContext<'a> { is_pat_binding: false, is_trivial_path: false, path_prefix: None, + path_ident: None, after_if: false, can_be_stmt: false, is_new_item: false, @@ -83,6 +86,18 @@ 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::(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. @@ -151,6 +166,7 @@ impl<'a> CompletionContext<'a> { Some(it) => it, None => return, }; + if let Some(segment) = ast::PathSegment::cast(parent) { let path = segment.parent_path(); self.is_call = path @@ -167,6 +183,7 @@ impl<'a> CompletionContext<'a> { return; } } + if path.qualifier().is_none() { self.is_trivial_path = true; -- cgit v1.2.3 From 200032852be0c66b978c875a8edf0eca1f08b901 Mon Sep 17 00:00:00 2001 From: Andrea Pretto Date: Sun, 21 Apr 2019 23:55:47 +0200 Subject: complete_import: prevent panic when the anchor is the completion source range (fix rebase mess) Please enter the commit message for your changes. Lines starting --- crates/ra_hir/src/resolve.rs | 4 ---- crates/ra_hir/src/source_binder.rs | 6 +----- crates/ra_ide_api/src/completion/complete_scope.rs | 24 +++++++++++++++------- 3 files changed, 18 insertions(+), 16 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 0f866e6c2..ce80be17f 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -14,12 +14,8 @@ use crate::{ generics::GenericParams, expr::{scope::{ExprScopes, ScopeId}, PatId}, impl_block::ImplBlock, -<<<<<<< HEAD path::Path, Trait -======= - path::Path, Trait, ->>>>>>> complete_import: add new import resolver infrastructure with some hardcoded importable name. }; #[derive(Debug, Clone, Default)] diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index a6f0ab289..42399622a 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -19,11 +19,7 @@ use ra_syntax::{ use crate::{ HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name, -<<<<<<< HEAD - AsName, Module, HirFileId, Crate, Trait, Resolver, Ty, -======= - AsName, Module, HirFileId, Crate, Trait, Resolver, ImportResolver, ->>>>>>> complete_import: add new import resolver infrastructure with some hardcoded importable name. + AsName, Module, HirFileId, Crate, Trait, Resolver, Ty, ImportResolver, expr::{BodySourceMap, scope::{ScopeId, ExprScopes}}, ids::LocationCtx, expr, AstId, diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 63d475823..5bd5376c9 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -23,13 +23,23 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { ); builder.finish() }; - CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - build_import_label(&name, &path), - ) - .text_edit(edit) - .add_to(acc) + + // Hack: copied this check form conv.rs beacause auto import can produce edits + // that invalidate assert in conv_with. + if edit + .as_atoms() + .iter() + .filter(|atom| !ctx.source_range().is_subrange(&atom.delete)) + .all(|atom| ctx.source_range().intersection(&atom.delete).is_none()) + { + CompletionItem::new( + CompletionKind::Reference, + ctx.source_range(), + build_import_label(&name, &path), + ) + .text_edit(edit) + .add_to(acc); + } }); } } -- cgit v1.2.3 From e01052d1f0b8bf70a418a10538528923c5f400d5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 22 Apr 2019 15:56:28 +0300 Subject: move auto-imoprter into IDE auto-import is purely an IDE concern, so it should be done outside of HIR --- crates/ra_assists/src/auto_import.rs | 4 +- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/name.rs | 13 ++++- crates/ra_hir/src/resolve.rs | 59 ---------------------- crates/ra_hir/src/source_binder.rs | 15 +----- crates/ra_ide_api/src/completion/complete_scope.rs | 55 +++++++++++++++++++- .../src/completion/completion_context.rs | 12 ----- 7 files changed, 68 insertions(+), 92 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index b002d0e4d..7c856c19b 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs @@ -492,7 +492,6 @@ fn apply_auto_import( } } -#[allow(unused)] pub fn collect_hir_path_segments(path: &hir::Path) -> Vec { let mut ps = Vec::::with_capacity(10); match path.kind { @@ -503,7 +502,7 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec { 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 { // 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, diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f156e3f07..4411715de 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -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::{ diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 331da6027..9a999e66c 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs @@ -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 { diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index ce80be17f..bd0f074c1 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -23,12 +23,6 @@ pub(crate) struct Resolver { scopes: Vec, } -#[derive(Debug, Clone, Default)] -pub(crate) struct ImportResolver { - // todo: use fst crate or something like that - dummy_names: Vec<(SmolStr, Vec)>, -} - // 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> { - 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() - } - } -} diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 42399622a..2959e3eca 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -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>, infer: Option>, scopes: Option>, @@ -219,7 +217,6 @@ impl SourceAnalyzer { offset: Option, ) -> 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> { - self.import_resolver.all_names(db, name) - } - pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec { // FIXME: at least, this should work with any DefWithBody, but ideally // this should be hir-based altogether diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 5bd5376c9..a2523c5ef 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -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, buf: &mut String) { } } +#[derive(Debug, Clone, Default)] +pub(crate) struct ImportResolver { + // todo: use fst crate or something like that + dummy_names: Vec<(SmolStr, Vec)>, +} + +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> { + 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}; diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index ca8f7900d..0d630fdf6 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -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::(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. -- cgit v1.2.3 From c27a3da5e86b1fcbfb562e0723fb97d72268fa72 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 22 Apr 2019 16:04:56 +0300 Subject: remove path_ident from CompletionContext We really shouldn't be looking at the identifier at point. Instead, all filtering and sorting should be implemented at the layer above. This layer should probably be home for auto-import completions as well, but, since that is not yet implemented, let's just stick this into complete_scope. --- crates/ra_ide_api/src/completion/complete_scope.rs | 70 +++++++++++----------- .../src/completion/completion_context.rs | 7 +-- 2 files changed, 38 insertions(+), 39 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index a2523c5ef..2473e58b4 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -1,6 +1,6 @@ use rustc_hash::FxHashMap; use ra_text_edit::TextEditBuilder; -use ra_syntax::SmolStr; +use ra_syntax::{SmolStr, ast, AstNode}; use ra_assists::auto_import; use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext}; @@ -9,41 +9,43 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { if ctx.is_trivial_path { let names = ctx.analyzer.all_names(ctx.db); names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res)); - } - if let Some(name) = ctx.path_ident.as_ref() { - 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(); - builder.replace(ctx.source_range(), name.to_string()); - auto_import::auto_import_text_edit( - ctx.token.parent(), - ctx.token.parent(), - &path, - &mut builder, - ); - builder.finish() - }; + // auto-import + // We fetch ident from the original file, because we need to pre-filter auto-imports + if ast::NameRef::cast(ctx.token.parent()).is_some() { + let import_resolver = ImportResolver::new(); + let import_names = import_resolver.all_names(ctx.token.text()); + import_names.into_iter().for_each(|(name, path)| { + let edit = { + let mut builder = TextEditBuilder::default(); + builder.replace(ctx.source_range(), name.to_string()); + auto_import::auto_import_text_edit( + ctx.token.parent(), + ctx.token.parent(), + &path, + &mut builder, + ); + builder.finish() + }; - // Hack: copied this check form conv.rs beacause auto import can produce edits - // that invalidate assert in conv_with. - if edit - .as_atoms() - .iter() - .filter(|atom| !ctx.source_range().is_subrange(&atom.delete)) - .all(|atom| ctx.source_range().intersection(&atom.delete).is_none()) - { - CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - build_import_label(&name, &path), - ) - .text_edit(edit) - .add_to(acc); - } - }); + // Hack: copied this check form conv.rs beacause auto import can produce edits + // that invalidate assert in conv_with. + if edit + .as_atoms() + .iter() + .filter(|atom| !ctx.source_range().is_subrange(&atom.delete)) + .all(|atom| ctx.source_range().intersection(&atom.delete).is_none()) + { + CompletionItem::new( + CompletionKind::Reference, + ctx.source_range(), + build_import_label(&name, &path), + ) + .text_edit(edit) + .add_to(acc); + } + }); + } } } diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 0d630fdf6..a8c8cc7b0 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -5,10 +5,10 @@ use ra_syntax::{ algo::{find_token_at_offset, find_covering_element, find_node_at_offset}, SyntaxKind::*, }; - -use hir::{ source_binder, Name }; +use hir::source_binder; use crate::{db, FilePosition}; + /// `CompletionContext` is created early during completion to figure out, where /// exactly is the cursor, syntax-wise. #[derive(Debug)] @@ -29,8 +29,6 @@ pub(crate) struct CompletionContext<'a> { pub(super) is_trivial_path: bool, /// If not a trivial path, the prefix (qualifier). pub(super) path_prefix: Option, - /// If a trivial path, the ident. - pub(super) path_ident: Option, pub(super) after_if: bool, /// `true` if we are a statement or a last expr in the block. pub(super) can_be_stmt: bool, @@ -65,7 +63,6 @@ impl<'a> CompletionContext<'a> { is_pat_binding: false, is_trivial_path: false, path_prefix: None, - path_ident: None, after_if: false, can_be_stmt: false, is_new_item: false, -- cgit v1.2.3 From aa1ef6ae9a9a61ab6ddc42d7987753df3aa67263 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 22 Apr 2019 16:18:14 +0300 Subject: unused import --- crates/ra_hir/src/resolve.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index bd0f074c1..f2c85eb66 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -3,8 +3,6 @@ use std::sync::Arc; use rustc_hash::FxHashMap; -use ra_syntax::SmolStr; - use crate::{ ModuleDef, code_model_api::Crate, -- cgit v1.2.3