diff options
| author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-01 22:37:59 +0000 |
|---|---|---|
| committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-01 22:37:59 +0000 |
| commit | 4447019f4b5f24728bb7b91b161755ddb373c74c (patch) | |
| tree | c53ff3531cbbad182e821eb92fa9ad201d2bff0c /crates/ra_ide_api/src/completion | |
| parent | 2b5c226e86892113bcab478cdf4c9adaf1e7b2f6 (diff) | |
| parent | c5852f422ff45adaa21815c1a15e03b067a56a82 (diff) | |
Merge #693
693: Name resolution refactoring r=matklad a=flodiebold
This is still very WIP, but it's becoming quite big and I want to make sure this isn't going in a completely bad direction :sweat_smile:. I'm not really happy with how the path resolution looks, and I'm not sure `PerNs<Resolution>` is the best return type -- there are 'this cannot happen in the (types/values) namespace' cases everywhere. I also want to unify the `resolver` and `nameres` namespaces once I'm done switching everything to `Resolver`. Also, `Resolver` only has a lifetime because it needs to have a reference to the `ItemMap` during import resolution :confused:
The differences in the completion snapshots are almost completely just ordering (except it completes `Self` as well now), so I changed it to sort the completions before snapshotting.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_ide_api/src/completion')
7 files changed, 178 insertions, 80 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index b33ddcde5..0b9948d4b 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
| @@ -1,21 +1,21 @@ | |||
| 1 | use join_to_string::join; | 1 | use join_to_string::join; |
| 2 | 2 | ||
| 3 | use hir::{Docs, Resolution}; | ||
| 4 | |||
| 3 | use crate::{ | 5 | use crate::{ |
| 4 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, | 6 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, |
| 5 | }; | 7 | }; |
| 6 | 8 | ||
| 7 | use hir::Docs; | ||
| 8 | |||
| 9 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | 9 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { |
| 10 | let (path, module) = match (&ctx.path_prefix, &ctx.module) { | 10 | let path = match &ctx.path_prefix { |
| 11 | (Some(path), Some(module)) => (path.clone(), module), | 11 | Some(path) => path.clone(), |
| 12 | _ => return, | 12 | _ => return, |
| 13 | }; | 13 | }; |
| 14 | let def_id = match module.resolve_path(ctx.db, &path).take_types() { | 14 | let def = match ctx.resolver.resolve_path(ctx.db, &path).take_types() { |
| 15 | Some(it) => it, | 15 | Some(Resolution::Def(def)) => def, |
| 16 | None => return, | 16 | _ => return, |
| 17 | }; | 17 | }; |
| 18 | match def_id { | 18 | match def { |
| 19 | hir::ModuleDef::Module(module) => { | 19 | hir::ModuleDef::Module(module) => { |
| 20 | let module_scope = module.scope(ctx.db); | 20 | let module_scope = module.scope(ctx.db); |
| 21 | for (name, res) in module_scope.entries() { | 21 | for (name, res) in module_scope.entries() { |
| @@ -24,7 +24,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
| 24 | ctx.source_range(), | 24 | ctx.source_range(), |
| 25 | name.to_string(), | 25 | name.to_string(), |
| 26 | ) | 26 | ) |
| 27 | .from_resolution(ctx, res) | 27 | .from_resolution(ctx, &res.def.map(hir::Resolution::Def)) |
| 28 | .add_to(acc); | 28 | .add_to(acc); |
| 29 | } | 29 | } |
| 30 | } | 30 | } |
| @@ -66,6 +66,17 @@ mod tests { | |||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | #[test] | 68 | #[test] |
| 69 | #[ignore] // should not complete foo, which currently doesn't work | ||
| 70 | fn dont_complete_current_use() { | ||
| 71 | check_reference_completion( | ||
| 72 | "dont_complete_current_use", | ||
| 73 | r" | ||
| 74 | use self::foo<|>; | ||
| 75 | ", | ||
| 76 | ); | ||
| 77 | } | ||
| 78 | |||
| 79 | #[test] | ||
| 69 | fn completes_mod_with_docs() { | 80 | fn completes_mod_with_docs() { |
| 70 | check_reference_completion( | 81 | check_reference_completion( |
| 71 | "mod_with_docs", | 82 | "mod_with_docs", |
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index f837bb1db..44514ab2b 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs | |||
| @@ -1,63 +1,20 @@ | |||
| 1 | use rustc_hash::FxHashSet; | 1 | use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext}; |
| 2 | use ra_syntax::ast::AstNode; | ||
| 3 | use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}; | ||
| 4 | 2 | ||
| 5 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { | 3 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { |
| 6 | if !ctx.is_trivial_path { | 4 | if !ctx.is_trivial_path { |
| 7 | return; | 5 | return; |
| 8 | } | 6 | } |
| 9 | let module = match &ctx.module { | 7 | let names = ctx.resolver.all_names(); |
| 10 | Some(it) => it, | ||
| 11 | None => return, | ||
| 12 | }; | ||
| 13 | if let Some(function) = &ctx.function { | ||
| 14 | let scopes = function.scopes(ctx.db); | ||
| 15 | complete_fn(acc, &scopes, ctx); | ||
| 16 | } | ||
| 17 | |||
| 18 | let module_scope = module.scope(ctx.db); | ||
| 19 | module_scope | ||
| 20 | .entries() | ||
| 21 | .filter(|(_name, res)| { | ||
| 22 | // For cases like `use self::foo<|>` don't suggest foo itself. | ||
| 23 | match res.import { | ||
| 24 | None => true, | ||
| 25 | Some(import) => { | ||
| 26 | let source = module.import_source(ctx.db, import); | ||
| 27 | !source.syntax().range().is_subrange(&ctx.leaf.range()) | ||
| 28 | } | ||
| 29 | } | ||
| 30 | }) | ||
| 31 | .for_each(|(name, res)| { | ||
| 32 | CompletionItem::new( | ||
| 33 | CompletionKind::Reference, | ||
| 34 | ctx.source_range(), | ||
| 35 | name.to_string(), | ||
| 36 | ) | ||
| 37 | .from_resolution(ctx, res) | ||
| 38 | .add_to(acc) | ||
| 39 | }); | ||
| 40 | } | ||
| 41 | 8 | ||
| 42 | fn complete_fn( | 9 | names.into_iter().for_each(|(name, res)| { |
| 43 | acc: &mut Completions, | 10 | CompletionItem::new( |
| 44 | scopes: &hir::ScopesWithSyntaxMapping, | 11 | CompletionKind::Reference, |
| 45 | ctx: &CompletionContext, | 12 | ctx.source_range(), |
| 46 | ) { | 13 | name.to_string(), |
| 47 | let mut shadowed = FxHashSet::default(); | 14 | ) |
| 48 | scopes | 15 | .from_resolution(ctx, &res) |
| 49 | .scope_chain_for_offset(ctx.offset) | 16 | .add_to(acc) |
| 50 | .flat_map(|scope| scopes.scopes.entries(scope).iter()) | 17 | }); |
| 51 | .filter(|entry| shadowed.insert(entry.name())) | ||
| 52 | .for_each(|entry| { | ||
| 53 | CompletionItem::new( | ||
| 54 | CompletionKind::Reference, | ||
| 55 | ctx.source_range(), | ||
| 56 | entry.name().to_string(), | ||
| 57 | ) | ||
| 58 | .kind(CompletionItemKind::Binding) | ||
| 59 | .add_to(acc) | ||
| 60 | }); | ||
| 61 | } | 18 | } |
| 62 | 19 | ||
| 63 | #[cfg(test)] | 20 | #[cfg(test)] |
| @@ -116,6 +73,30 @@ mod tests { | |||
| 116 | } | 73 | } |
| 117 | 74 | ||
| 118 | #[test] | 75 | #[test] |
| 76 | fn completes_generic_params() { | ||
| 77 | check_reference_completion( | ||
| 78 | "generic_params", | ||
| 79 | r" | ||
| 80 | fn quux<T>() { | ||
| 81 | <|> | ||
| 82 | } | ||
| 83 | ", | ||
| 84 | ); | ||
| 85 | } | ||
| 86 | |||
| 87 | #[test] | ||
| 88 | fn completes_generic_params_in_struct() { | ||
| 89 | check_reference_completion( | ||
| 90 | "generic_params_in_struct", | ||
| 91 | r" | ||
| 92 | struct X<T> { | ||
| 93 | x: <|> | ||
| 94 | } | ||
| 95 | ", | ||
| 96 | ); | ||
| 97 | } | ||
| 98 | |||
| 99 | #[test] | ||
| 119 | fn completes_module_items() { | 100 | fn completes_module_items() { |
| 120 | check_reference_completion( | 101 | check_reference_completion( |
| 121 | "module_items", | 102 | "module_items", |
| @@ -174,5 +155,4 @@ mod tests { | |||
| 174 | fn completes_self_in_methods() { | 155 | fn completes_self_in_methods() { |
| 175 | check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") | 156 | check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") |
| 176 | } | 157 | } |
| 177 | |||
| 178 | } | 158 | } |
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 578af6e5b..5d1851da6 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs | |||
| @@ -5,7 +5,7 @@ use ra_syntax::{ | |||
| 5 | algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset}, | 5 | algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset}, |
| 6 | SyntaxKind::*, | 6 | SyntaxKind::*, |
| 7 | }; | 7 | }; |
| 8 | use hir::source_binder; | 8 | use hir::{source_binder, Resolver}; |
| 9 | 9 | ||
| 10 | use crate::{db, FilePosition}; | 10 | use crate::{db, FilePosition}; |
| 11 | 11 | ||
| @@ -16,6 +16,7 @@ pub(crate) struct CompletionContext<'a> { | |||
| 16 | pub(super) db: &'a db::RootDatabase, | 16 | pub(super) db: &'a db::RootDatabase, |
| 17 | pub(super) offset: TextUnit, | 17 | pub(super) offset: TextUnit, |
| 18 | pub(super) leaf: &'a SyntaxNode, | 18 | pub(super) leaf: &'a SyntaxNode, |
| 19 | pub(super) resolver: Resolver, | ||
| 19 | pub(super) module: Option<hir::Module>, | 20 | pub(super) module: Option<hir::Module>, |
| 20 | pub(super) function: Option<hir::Function>, | 21 | pub(super) function: Option<hir::Function>, |
| 21 | pub(super) function_syntax: Option<&'a ast::FnDef>, | 22 | pub(super) function_syntax: Option<&'a ast::FnDef>, |
| @@ -42,12 +43,14 @@ impl<'a> CompletionContext<'a> { | |||
| 42 | original_file: &'a SourceFile, | 43 | original_file: &'a SourceFile, |
| 43 | position: FilePosition, | 44 | position: FilePosition, |
| 44 | ) -> Option<CompletionContext<'a>> { | 45 | ) -> Option<CompletionContext<'a>> { |
| 46 | let resolver = source_binder::resolver_for_position(db, position); | ||
| 45 | let module = source_binder::module_from_position(db, position); | 47 | let module = source_binder::module_from_position(db, position); |
| 46 | let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?; | 48 | let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?; |
| 47 | let mut ctx = CompletionContext { | 49 | let mut ctx = CompletionContext { |
| 48 | db, | 50 | db, |
| 49 | leaf, | 51 | leaf, |
| 50 | offset: position.offset, | 52 | offset: position.offset, |
| 53 | resolver, | ||
| 51 | module, | 54 | module, |
| 52 | function: None, | 55 | function: None, |
| 53 | function_syntax: None, | 56 | function_syntax: None, |
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index d3bc14894..bada6a33b 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | use hir::{Docs, Documentation}; | 1 | use hir::{Docs, Documentation, PerNs, Resolution}; |
| 2 | use ra_syntax::TextRange; | 2 | use ra_syntax::{ |
| 3 | TextRange, | ||
| 4 | }; | ||
| 3 | use ra_text_edit::TextEdit; | 5 | use ra_text_edit::TextEdit; |
| 4 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
| 5 | 7 | ||
| @@ -48,6 +50,7 @@ pub enum CompletionItemKind { | |||
| 48 | Trait, | 50 | Trait, |
| 49 | TypeAlias, | 51 | TypeAlias, |
| 50 | Method, | 52 | Method, |
| 53 | TypeParam, | ||
| 51 | } | 54 | } |
| 52 | 55 | ||
| 53 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | 56 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
| @@ -207,23 +210,34 @@ impl Builder { | |||
| 207 | pub(super) fn from_resolution( | 210 | pub(super) fn from_resolution( |
| 208 | mut self, | 211 | mut self, |
| 209 | ctx: &CompletionContext, | 212 | ctx: &CompletionContext, |
| 210 | resolution: &hir::Resolution, | 213 | resolution: &PerNs<Resolution>, |
| 211 | ) -> Builder { | 214 | ) -> Builder { |
| 212 | let def = resolution.def.take_types().or(resolution.def.take_values()); | 215 | use hir::ModuleDef::*; |
| 216 | |||
| 217 | let def = resolution | ||
| 218 | .as_ref() | ||
| 219 | .take_types() | ||
| 220 | .or(resolution.as_ref().take_values()); | ||
| 213 | let def = match def { | 221 | let def = match def { |
| 214 | None => return self, | 222 | None => return self, |
| 215 | Some(it) => it, | 223 | Some(it) => it, |
| 216 | }; | 224 | }; |
| 217 | let (kind, docs) = match def { | 225 | let (kind, docs) = match def { |
| 218 | hir::ModuleDef::Module(it) => (CompletionItemKind::Module, it.docs(ctx.db)), | 226 | Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)), |
| 219 | hir::ModuleDef::Function(func) => return self.from_function(ctx, func), | 227 | Resolution::Def(Function(func)) => return self.from_function(ctx, *func), |
| 220 | hir::ModuleDef::Struct(it) => (CompletionItemKind::Struct, it.docs(ctx.db)), | 228 | Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)), |
| 221 | hir::ModuleDef::Enum(it) => (CompletionItemKind::Enum, it.docs(ctx.db)), | 229 | Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)), |
| 222 | hir::ModuleDef::EnumVariant(it) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)), | 230 | Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)), |
| 223 | hir::ModuleDef::Const(it) => (CompletionItemKind::Const, it.docs(ctx.db)), | 231 | Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)), |
| 224 | hir::ModuleDef::Static(it) => (CompletionItemKind::Static, it.docs(ctx.db)), | 232 | Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)), |
| 225 | hir::ModuleDef::Trait(it) => (CompletionItemKind::Trait, it.docs(ctx.db)), | 233 | Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)), |
| 226 | hir::ModuleDef::Type(it) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)), | 234 | Resolution::Def(Type(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)), |
| 235 | Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None), | ||
| 236 | Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None), | ||
| 237 | Resolution::SelfType(..) => ( | ||
| 238 | CompletionItemKind::TypeParam, // (does this need its own kind?) | ||
| 239 | None, | ||
| 240 | ), | ||
| 227 | }; | 241 | }; |
| 228 | self.kind = Some(kind); | 242 | self.kind = Some(kind); |
| 229 | self.documentation = docs; | 243 | self.documentation = docs; |
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap new file mode 100644 index 000000000..71cb55a5b --- /dev/null +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | --- | ||
| 2 | created: "2019-02-01T22:20:40.580128393+00:00" | ||
| 3 | creator: [email protected] | ||
| 4 | expression: kind_completions | ||
| 5 | source: crates/ra_ide_api/src/completion/completion_item.rs | ||
| 6 | --- | ||
| 7 | [ | ||
| 8 | CompletionItem { | ||
| 9 | completion_kind: Reference, | ||
| 10 | label: "T", | ||
| 11 | kind: Some( | ||
| 12 | TypeParam | ||
| 13 | ), | ||
| 14 | detail: None, | ||
| 15 | documentation: None, | ||
| 16 | lookup: None, | ||
| 17 | insert_text: None, | ||
| 18 | insert_text_format: PlainText, | ||
| 19 | source_range: [44; 44), | ||
| 20 | text_edit: None | ||
| 21 | }, | ||
| 22 | CompletionItem { | ||
| 23 | completion_kind: Reference, | ||
| 24 | label: "quux", | ||
| 25 | kind: Some( | ||
| 26 | Function | ||
| 27 | ), | ||
| 28 | detail: Some( | ||
| 29 | "fn quux<T>()" | ||
| 30 | ), | ||
| 31 | documentation: None, | ||
| 32 | lookup: None, | ||
| 33 | insert_text: Some( | ||
| 34 | "quux()$0" | ||
| 35 | ), | ||
| 36 | insert_text_format: Snippet, | ||
| 37 | source_range: [44; 44), | ||
| 38 | text_edit: None | ||
| 39 | } | ||
| 40 | ] | ||
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap new file mode 100644 index 000000000..a35c0cd13 --- /dev/null +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | --- | ||
| 2 | created: "2019-02-01T22:23:21.508620224+00:00" | ||
| 3 | creator: [email protected] | ||
| 4 | expression: kind_completions | ||
| 5 | source: crates/ra_ide_api/src/completion/completion_item.rs | ||
| 6 | --- | ||
| 7 | [ | ||
| 8 | CompletionItem { | ||
| 9 | completion_kind: Reference, | ||
| 10 | label: "T", | ||
| 11 | kind: Some( | ||
| 12 | TypeParam | ||
| 13 | ), | ||
| 14 | detail: None, | ||
| 15 | documentation: None, | ||
| 16 | lookup: None, | ||
| 17 | insert_text: None, | ||
| 18 | insert_text_format: PlainText, | ||
| 19 | source_range: [46; 46), | ||
| 20 | text_edit: None | ||
| 21 | }, | ||
| 22 | CompletionItem { | ||
| 23 | completion_kind: Reference, | ||
| 24 | label: "X", | ||
| 25 | kind: Some( | ||
| 26 | Struct | ||
| 27 | ), | ||
| 28 | detail: None, | ||
| 29 | documentation: None, | ||
| 30 | lookup: None, | ||
| 31 | insert_text: None, | ||
| 32 | insert_text_format: PlainText, | ||
| 33 | source_range: [46; 46), | ||
| 34 | text_edit: None | ||
| 35 | } | ||
| 36 | ] | ||
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap index 6a49e325c..ba1d4abbd 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap | |||
| @@ -1,12 +1,26 @@ | |||
| 1 | --- | 1 | --- |
| 2 | created: "2019-01-23T05:27:32.422259+00:00" | 2 | created: "2019-01-27T20:17:10.051725945+00:00" |
| 3 | creator: insta@0.4.0 | 3 | creator: insta@0.5.2 |
| 4 | expression: kind_completions | 4 | expression: kind_completions |
| 5 | source: crates/ra_ide_api/src/completion/completion_item.rs | 5 | source: crates/ra_ide_api/src/completion/completion_item.rs |
| 6 | --- | 6 | --- |
| 7 | [ | 7 | [ |
| 8 | CompletionItem { | 8 | CompletionItem { |
| 9 | completion_kind: Reference, | 9 | completion_kind: Reference, |
| 10 | label: "Self", | ||
| 11 | kind: Some( | ||
| 12 | TypeParam | ||
| 13 | ), | ||
| 14 | detail: None, | ||
| 15 | documentation: None, | ||
| 16 | lookup: None, | ||
| 17 | insert_text: None, | ||
| 18 | insert_text_format: PlainText, | ||
| 19 | source_range: [25; 25), | ||
| 20 | text_edit: None | ||
| 21 | }, | ||
| 22 | CompletionItem { | ||
| 23 | completion_kind: Reference, | ||
| 10 | label: "self", | 24 | label: "self", |
| 11 | kind: Some( | 25 | kind: Some( |
| 12 | Binding | 26 | Binding |
