aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assists/add_import.rs10
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs41
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir_def/src/path.rs4
-rw-r--r--crates/ra_hir_expand/src/name.rs7
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs67
6 files changed, 90 insertions, 42 deletions
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs
index bf6cfe865..fc038df78 100644
--- a/crates/ra_assists/src/assists/add_import.rs
+++ b/crates/ra_assists/src/assists/add_import.rs
@@ -1,4 +1,4 @@
1use hir::{self, db::HirDatabase}; 1use hir::{self, db::HirDatabase, ModPath};
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, NameOwner}, 3 ast::{self, NameOwner},
4 AstNode, Direction, SmolStr, 4 AstNode, Direction, SmolStr,
@@ -20,10 +20,10 @@ pub fn auto_import_text_edit(
20 position: &SyntaxNode, 20 position: &SyntaxNode,
21 // The statement to use as anchor (last resort) 21 // The statement to use as anchor (last resort)
22 anchor: &SyntaxNode, 22 anchor: &SyntaxNode,
23 // The path to import as a sequence of strings 23 path_to_import: &ModPath,
24 target: &[SmolStr],
25 edit: &mut TextEditBuilder, 24 edit: &mut TextEditBuilder,
26) { 25) {
26 let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>();
27 let container = position.ancestors().find_map(|n| { 27 let container = position.ancestors().find_map(|n| {
28 if let Some(module) = ast::Module::cast(n.clone()) { 28 if let Some(module) = ast::Module::cast(n.clone()) {
29 return module.item_list().map(|it| it.syntax().clone()); 29 return module.item_list().map(|it| it.syntax().clone());
@@ -32,8 +32,8 @@ pub fn auto_import_text_edit(
32 }); 32 });
33 33
34 if let Some(container) = container { 34 if let Some(container) = container {
35 let action = best_action_for_target(container, anchor.clone(), target); 35 let action = best_action_for_target(container, anchor.clone(), &target);
36 make_assist(&action, target, edit); 36 make_assist(&action, &target, edit);
37 } 37 }
38} 38}
39 39
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs
index 8c483e2da..2629f00e6 100644
--- a/crates/ra_assists/src/assists/auto_import.rs
+++ b/crates/ra_assists/src/assists/auto_import.rs
@@ -1,7 +1,6 @@
1use hir::db::HirDatabase; 1use hir::{db::HirDatabase, ModPath};
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode}, 3 ast::{self, AstNode},
4 SmolStr,
5 SyntaxKind::USE_ITEM, 4 SyntaxKind::USE_ITEM,
6 SyntaxNode, 5 SyntaxNode,
7}; 6};
@@ -58,7 +57,6 @@ pub(crate) fn auto_import<F: ImportsLocator>(
58 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) 57 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
59 .filter(|use_path| !use_path.segments.is_empty()) 58 .filter(|use_path| !use_path.segments.is_empty())
60 .take(20) 59 .take(20)
61 .map(|import| import.to_string())
62 .collect::<std::collections::BTreeSet<_>>(); 60 .collect::<std::collections::BTreeSet<_>>();
63 if proposed_imports.is_empty() { 61 if proposed_imports.is_empty() {
64 return None; 62 return None;
@@ -76,15 +74,10 @@ pub(crate) fn auto_import<F: ImportsLocator>(
76 ) 74 )
77} 75}
78 76
79fn import_to_action(import: String, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder { 77fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder {
80 let mut action_builder = ActionBuilder::default(); 78 let mut action_builder = ActionBuilder::default();
81 action_builder.label(format!("Import `{}`", &import)); 79 action_builder.label(format!("Import `{}`", &import));
82 auto_import_text_edit( 80 auto_import_text_edit(position, anchor, &import, action_builder.text_edit_builder());
83 position,
84 anchor,
85 &[SmolStr::new(import)],
86 action_builder.text_edit_builder(),
87 );
88 action_builder 81 action_builder
89} 82}
90 83
@@ -121,6 +114,34 @@ mod tests {
121 } 114 }
122 115
123 #[test] 116 #[test]
117 fn auto_imports_are_merged() {
118 check_assist_with_imports_locator(
119 auto_import,
120 TestImportsLocator::new,
121 r"
122 use PubMod::PubStruct1;
123
124 PubStruct2<|>
125
126 pub mod PubMod {
127 pub struct PubStruct1;
128 pub struct PubStruct2;
129 }
130 ",
131 r"
132 use PubMod::{PubStruct2, PubStruct1};
133
134 PubStruct2<|>
135
136 pub mod PubMod {
137 pub struct PubStruct1;
138 pub struct PubStruct2;
139 }
140 ",
141 );
142 }
143
144 #[test]
124 fn applicable_when_found_multiple_imports() { 145 fn applicable_when_found_multiple_imports() {
125 check_assist_with_imports_locator( 146 check_assist_with_imports_locator(
126 auto_import, 147 auto_import,
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 9e2673d13..ea06a4a58 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -59,6 +59,7 @@ pub use hir_def::{
59 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. 59 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.
60}; 60};
61pub use hir_expand::{ 61pub use hir_expand::{
62 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, 62 name::{name, Name},
63 HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
63}; 64};
64pub use hir_ty::{display::HirDisplay, CallableDef}; 65pub use hir_ty::{display::HirDisplay, CallableDef};
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index ab290e2c9..a150b899f 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -16,13 +16,13 @@ use ra_syntax::ast;
16 16
17use crate::{type_ref::TypeRef, InFile}; 17use crate::{type_ref::TypeRef, InFile};
18 18
19#[derive(Debug, Clone, PartialEq, Eq, Hash)] 19#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct ModPath { 20pub struct ModPath {
21 pub kind: PathKind, 21 pub kind: PathKind,
22 pub segments: Vec<Name>, 22 pub segments: Vec<Name>,
23} 23}
24 24
25#[derive(Debug, Clone, PartialEq, Eq, Hash)] 25#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
26pub enum PathKind { 26pub enum PathKind {
27 Plain, 27 Plain,
28 /// `self::` is `Super(0)` 28 /// `self::` is `Super(0)`
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index b2e10f445..133805bdb 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -187,6 +187,13 @@ pub mod known {
187 PartialOrd, 187 PartialOrd,
188 Eq, 188 Eq,
189 PartialEq, 189 PartialEq,
190 // FIXME delete those after `ImportResolver` is removed.
191 hash,
192 fmt,
193 io,
194 Display,
195 Iterator,
196 Hasher,
190 ); 197 );
191 198
192 // self/Self cannot be used as an identifier 199 // self/Self cannot be used as an identifier
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index 458d7525e..64b04ec2b 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -6,6 +6,7 @@ use ra_text_edit::TextEditBuilder;
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7 7
8use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; 8use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};
9use hir::{ModPath, PathKind};
9 10
10pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { 11pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
11 if !ctx.is_trivial_path { 12 if !ctx.is_trivial_path {
@@ -54,58 +55,76 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
54 } 55 }
55} 56}
56 57
57fn build_import_label(name: &str, path: &[SmolStr]) -> String { 58fn build_import_label(name: &str, path: &ModPath) -> String {
58 let mut buf = String::with_capacity(64); 59 let mut buf = String::with_capacity(64);
59 buf.push_str(name); 60 buf.push_str(name);
60 buf.push_str(" ("); 61 buf.push_str(" (");
61 fmt_import_path(path, &mut buf); 62 buf.push_str(&path.to_string());
62 buf.push_str(")"); 63 buf.push_str(")");
63 buf 64 buf
64} 65}
65 66
66fn fmt_import_path(path: &[SmolStr], buf: &mut String) {
67 let mut segments = path.iter();
68 if let Some(s) = segments.next() {
69 buf.push_str(&s);
70 }
71 for s in segments {
72 buf.push_str("::");
73 buf.push_str(&s);
74 }
75}
76
77#[derive(Debug, Clone, Default)] 67#[derive(Debug, Clone, Default)]
78pub(crate) struct ImportResolver { 68pub(crate) struct ImportResolver {
79 // todo: use fst crate or something like that 69 // todo: use fst crate or something like that
80 dummy_names: Vec<(SmolStr, Vec<SmolStr>)>, 70 dummy_names: Vec<(SmolStr, ModPath)>,
81} 71}
82 72
83impl ImportResolver { 73impl ImportResolver {
84 pub(crate) fn new() -> Self { 74 pub(crate) fn new() -> Self {
75 use hir::name;
76
85 let dummy_names = vec![ 77 let dummy_names = vec![
86 (SmolStr::new("fmt"), vec![SmolStr::new("std"), SmolStr::new("fmt")]), 78 (
87 (SmolStr::new("io"), vec![SmolStr::new("std"), SmolStr::new("io")]), 79 SmolStr::new("fmt"),
88 (SmolStr::new("iter"), vec![SmolStr::new("std"), SmolStr::new("iter")]), 80 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![fmt]] },
89 (SmolStr::new("hash"), vec![SmolStr::new("std"), SmolStr::new("hash")]), 81 ),
82 (
83 SmolStr::new("io"),
84 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![io]] },
85 ),
86 (
87 SmolStr::new("iter"),
88 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![iter]] },
89 ),
90 (
91 SmolStr::new("hash"),
92 ModPath { kind: PathKind::Plain, segments: vec![name![std], name![hash]] },
93 ),
90 ( 94 (
91 SmolStr::new("Debug"), 95 SmolStr::new("Debug"),
92 vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Debug")], 96 ModPath {
97 kind: PathKind::Plain,
98 segments: vec![name![std], name![fmt], name![Debug]],
99 },
93 ), 100 ),
94 ( 101 (
95 SmolStr::new("Display"), 102 SmolStr::new("Display"),
96 vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Display")], 103 ModPath {
104 kind: PathKind::Plain,
105 segments: vec![name![std], name![fmt], name![Display]],
106 },
97 ), 107 ),
98 ( 108 (
99 SmolStr::new("Hash"), 109 SmolStr::new("Hash"),
100 vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hash")], 110 ModPath {
111 kind: PathKind::Plain,
112 segments: vec![name![std], name![hash], name![Hash]],
113 },
101 ), 114 ),
102 ( 115 (
103 SmolStr::new("Hasher"), 116 SmolStr::new("Hasher"),
104 vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hasher")], 117 ModPath {
118 kind: PathKind::Plain,
119 segments: vec![name![std], name![hash], name![Hasher]],
120 },
105 ), 121 ),
106 ( 122 (
107 SmolStr::new("Iterator"), 123 SmolStr::new("Iterator"),
108 vec![SmolStr::new("std"), SmolStr::new("iter"), SmolStr::new("Iterator")], 124 ModPath {
125 kind: PathKind::Plain,
126 segments: vec![name![std], name![iter], name![Iterator]],
127 },
109 ), 128 ),
110 ]; 129 ];
111 130
@@ -115,7 +134,7 @@ impl ImportResolver {
115 // Returns a map of importable items filtered by name. 134 // Returns a map of importable items filtered by name.
116 // The map associates item name with its full path. 135 // The map associates item name with its full path.
117 // todo: should return Resolutions 136 // todo: should return Resolutions
118 pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, Vec<SmolStr>> { 137 pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, ModPath> {
119 if name.len() > 1 { 138 if name.len() > 1 {
120 self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect() 139 self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect()
121 } else { 140 } else {